From c05c456f31cc2a596e5f955c1109144cc5e6c83f Mon Sep 17 00:00:00 2001 From: Tobias Kurze Date: Mon, 14 Sep 2020 21:00:18 +0200 Subject: [PATCH] tests with kivy --- .gitignore | 139 +++++++++++++++ Pipfile | 12 ++ Pipfile.lock | 103 +++++++++++ android.txt | 3 + data/screens/accordions.kv | 39 +++++ data/screens/buttons.kv | 26 +++ gui.py | 349 +++++++++++++++++++++++++++++++++++++ projctrl_info.md | 1 + showcase.kv | 100 +++++++++++ 9 files changed, 772 insertions(+) create mode 100644 .gitignore create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 android.txt create mode 100644 data/screens/accordions.kv create mode 100644 data/screens/buttons.kv create mode 100644 gui.py create mode 100644 projctrl_info.md create mode 100644 showcase.kv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..139ca9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +.idea +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..cface72 --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +kivy = "==2.0.0rc2" + +[requires] +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..ca22715 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,103 @@ +{ + "_meta": { + "hash": { + "sha256": "7d229b60b63aa364eed937ad0dbe66eeff26c3ee078fadf4d466ebd9ea54dedc" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + ], + "version": "==2020.6.20" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "docutils": { + "hashes": [ + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.16" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "kivy": { + "hashes": [ + "sha256:11502f20961915cf61bc8d4c9c6e91799afeef802a457b202201ac64178bd5c9", + "sha256:17240ce04d51349205dfa63a9582bf4bd8f0da9e7b366eb5ac3dc8ac0ada3fea", + "sha256:2042b1a861de3927ebd81baae0bea6e322866a7cf41d7f698d4ede4265f460c3", + "sha256:2fbb0fa7d2142ef8acf5de7a334a4d4db78adc5e76007679a0a8f0cb58146536", + "sha256:3333f46de8b84120811cbc81745a7ed7f594db2ef159d154e1dc52783d98acce", + "sha256:450f4d0b848cd927abb2558c4a6b596cab0bee10eab930e35cf8dbe0e3bfff3b", + "sha256:4e7a202d4c120b6965526e00f5537f4d2f450478e60b8d3fc767cbe0339ef086", + "sha256:5492f7ccc56527b3483b27dbe8eb3bb5e9d47f8ca7976a45fd5863638ba9f1bd", + "sha256:62a3a554ff74b857a0f6143555d09e65d1e3843ecc11a6fb3de02751f8c6918e", + "sha256:750dad044eff22fae83f110fc332e8565fdab8e6daaabd93131438f3bb05deb1", + "sha256:7ef75443e5ffe075035dc38409bcb675d18812c9b72528156c5f8560dc242ab1", + "sha256:9f543cd2ef999cb4055fb333f109a06e52c82a465eaa4cd594df48026c147900", + "sha256:ae7a2b49e0a31f2a8b55e69c95b6088eed4ed14adfbc2c4df3f996ee66c09920", + "sha256:b15207cc06bb92ae78a2ce1ed00ff827fd7cb15aa98bf41450e5576cbd5328f6", + "sha256:ed81d88c1c943b13e028709ccd0590748787184db2c6f4c4f1b3b4905b5ca087" + ], + "index": "pypi", + "version": "==2.0.0rc2" + }, + "kivy-garden": { + "hashes": [ + "sha256:9b7d9de5efacbcd0c4b3dd873b30622a86093c9965aa47b523c7a32f3eb34610", + "sha256:c256f42788421273a08fbb0a228f0fb0e80dd86b629fb8c0920507f645be6c72" + ], + "version": "==0.1.4" + }, + "pygments": { + "hashes": [ + "sha256:2594e8fdb06fef91552f86f4fd3a244d148ab24b66042036e64f29a291515048", + "sha256:2df50d16b45b977217e02cba6c8422aaddb859f3d0570a88e09b00eafae89c6e" + ], + "markers": "python_version >= '3.5'", + "version": "==2.7.0" + }, + "requests": { + "hashes": [ + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.24.0" + }, + "urllib3": { + "hashes": [ + "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", + "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.25.10" + } + }, + "develop": {} +} diff --git a/android.txt b/android.txt new file mode 100644 index 0000000..5934cfc --- /dev/null +++ b/android.txt @@ -0,0 +1,3 @@ +title=Showcase +author=Kivy team +orientation=landscape \ No newline at end of file diff --git a/data/screens/accordions.kv b/data/screens/accordions.kv new file mode 100644 index 0000000..36ecb98 --- /dev/null +++ b/data/screens/accordions.kv @@ -0,0 +1,39 @@ +ShowcaseScreen: + name: 'Accordions' + + fullscreen: True + + BoxLayout: + size_hint_y: None + height: '48dp' + + ToggleButton: + id: tbh + text: 'Horizontal' + group: 'accordion' + state: 'down' + + ToggleButton: + text: 'Vertical' + group: 'accordion' + + Accordion: + + orientation: 'horizontal' if tbh.state == 'down' else 'vertical' + + AccordionItem: + title: 'Panel 1' + Label: + text: 'This is a label fit to the content view' + text_size: self.width, None + + AccordionItem: + title: 'Panel 2' + Button: + text: 'A button, what else?' + + AccordionItem: + title: 'Panel 3' + Label: + text: 'This is a label fit to the content view' + text_size: self.width, None diff --git a/data/screens/buttons.kv b/data/screens/buttons.kv new file mode 100644 index 0000000..1fecfc8 --- /dev/null +++ b/data/screens/buttons.kv @@ -0,0 +1,26 @@ +ShowcaseScreen: + name: 'Buttons' + + Button: + size_hint_y: None + height: '48dp' + text: 'Button normal' + + Button: + size_hint_y: None + height: '48dp' + text: 'Button down' + state: 'down' + + Button: + size_hint_y: None + height: '48dp' + text: 'Button disabled' + disabled: True + + Button: + size_hint_y: None + height: '48dp' + text: 'Button down disabled' + state: 'down' + disabled: True \ No newline at end of file diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..eb4b0c7 --- /dev/null +++ b/gui.py @@ -0,0 +1,349 @@ +''' +Showcase of Kivy Features +========================= + +This showcases many features of Kivy. You should see a +menu bar across the top with a demonstration area below. The +first demonstration is the accordion layout. You can see, but not +edit, the kv language code for any screen by pressing the bug or +'show source' icon. Scroll through the demonstrations using the +left and right icons in the top right or selecting from the menu +bar. + +The file showcase.kv describes the main container, while each demonstration +pane is described in a separate .kv file in the data/screens directory. +The image data/background.png provides the gradient background while the +icons in data/icon directory are used in the control bar. The file +data/faust_github.jpg is used in the Scatter pane. The icons are +from `http://www.gentleface.com/free_icon_set.html` and licensed as +Creative Commons - Attribution and Non-commercial Use Only; they +sell a commercial license. + +The file android.txt is used to package the application for use with the +Kivy Launcher Android application. For Android devices, you can +copy/paste this directory into /sdcard/kivy/showcase on your Android device. + +''' + +from time import time +from kivy.app import App +from os.path import dirname, join +from kivy.lang import Builder +from kivy.properties import NumericProperty, StringProperty, BooleanProperty,\ + ListProperty +from kivy.clock import Clock +from kivy.animation import Animation +from kivy.uix.screenmanager import Screen + + +class ShowcaseScreen(Screen): + fullscreen = BooleanProperty(False) + + def add_widget(self, *args): + if 'content' in self.ids: + return self.ids.content.add_widget(*args) + return super(ShowcaseScreen, self).add_widget(*args) + + +class ShowcaseApp(App): + + index = NumericProperty(-1) + current_title = StringProperty() + time = NumericProperty(0) + show_sourcecode = BooleanProperty(False) + sourcecode = StringProperty() + screen_names = ListProperty([]) + hierarchy = ListProperty([]) + + def build(self): + self.title = 'hello world' + Clock.schedule_interval(self._update_clock, 1 / 60.) + self.screens = {} + self.available_screens = sorted([ + 'Buttons', 'ToggleButton', 'Sliders', 'ProgressBar', 'Switches', + 'CheckBoxes', 'TextInputs', 'Accordions', 'FileChoosers', + 'Carousel', 'Bubbles', 'CodeInput', 'DropDown', 'Spinner', + 'Scatter', 'Splitter', 'TabbedPanel + Layouts', 'RstDocument', + 'Popups', 'ScreenManager']) + self.available_screens = sorted(['Accordions', 'Buttons']) + self.screen_names = self.available_screens + curdir = dirname(__file__) + self.available_screens = [join(curdir, 'data', 'screens', + '{}.kv'.format(fn).lower()) for fn in self.available_screens] + self.go_next_screen() + + def on_pause(self): + return True + + def on_resume(self): + pass + + def on_current_title(self, instance, value): + self.root.ids.spnr.text = value + + def go_previous_screen(self): + self.index = (self.index - 1) % len(self.available_screens) + screen = self.load_screen(self.index) + sm = self.root.ids.sm + sm.switch_to(screen, direction='right') + self.current_title = screen.name + self.update_sourcecode() + + def go_next_screen(self): + self.index = (self.index + 1) % len(self.available_screens) + screen = self.load_screen(self.index) + sm = self.root.ids.sm + sm.switch_to(screen, direction='left') + self.current_title = screen.name + self.update_sourcecode() + + def go_screen(self, idx): + self.index = idx + self.root.ids.sm.switch_to(self.load_screen(idx), direction='left') + self.update_sourcecode() + + def go_hierarchy_previous(self): + ahr = self.hierarchy + if len(ahr) == 1: + return + if ahr: + ahr.pop() + if ahr: + idx = ahr.pop() + self.go_screen(idx) + + def load_screen(self, index): + if index in self.screens: + return self.screens[index] + screen = Builder.load_file(self.available_screens[index]) + self.screens[index] = screen + return screen + + def read_sourcecode(self): + fn = self.available_screens[self.index] + with open(fn) as fd: + return fd.read() + + def toggle_source_code(self): + self.show_sourcecode = not self.show_sourcecode + if self.show_sourcecode: + height = self.root.height * .3 + else: + height = 0 + + Animation(height=height, d=.3, t='out_quart').start( + self.root.ids.sv) + + self.update_sourcecode() + + def update_sourcecode(self): + if not self.show_sourcecode: + self.root.ids.sourcecode.focus = False + return + self.root.ids.sourcecode.text = self.read_sourcecode() + self.root.ids.sv.scroll_y = 1 + + def showcase_floatlayout(self, layout): + + def add_button(*t): + if not layout.get_parent_window(): + return + if len(layout.children) > 5: + layout.clear_widgets() + layout.add_widget(Builder.load_string(''' +#:import random random.random +Button: + size_hint: random(), random() + pos_hint: {'x': random(), 'y': random()} + text: + 'size_hint x: {} y: {}\\n pos_hint x: {} y: {}'.format(\ + self.size_hint_x, self.size_hint_y, self.pos_hint['x'],\ + self.pos_hint['y']) +''')) + Clock.schedule_once(add_button, 1) + Clock.schedule_once(add_button) + + def showcase_boxlayout(self, layout): + + def add_button(*t): + if not layout.get_parent_window(): + return + if len(layout.children) > 5: + layout.orientation = 'vertical'\ + if layout.orientation == 'horizontal' else 'horizontal' + layout.clear_widgets() + layout.add_widget(Builder.load_string(''' +Button: + text: self.parent.orientation if self.parent else '' +''')) + Clock.schedule_once(add_button, 1) + Clock.schedule_once(add_button) + + def showcase_gridlayout(self, layout): + + def add_button(*t): + if not layout.get_parent_window(): + return + if len(layout.children) > 15: + layout.rows = 3 if layout.rows is None else None + layout.cols = None if layout.rows == 3 else 3 + layout.clear_widgets() + layout.add_widget(Builder.load_string(''' +Button: + text: + 'rows: {}\\ncols: {}'.format(self.parent.rows, self.parent.cols)\ + if self.parent else '' +''')) + Clock.schedule_once(add_button, 1) + Clock.schedule_once(add_button) + + def showcase_stacklayout(self, layout): + orientations = ('lr-tb', 'tb-lr', + 'rl-tb', 'tb-rl', + 'lr-bt', 'bt-lr', + 'rl-bt', 'bt-rl') + + def add_button(*t): + if not layout.get_parent_window(): + return + if len(layout.children) > 11: + layout.clear_widgets() + cur_orientation = orientations.index(layout.orientation) + layout.orientation = orientations[cur_orientation - 1] + layout.add_widget(Builder.load_string(''' +Button: + text: self.parent.orientation if self.parent else '' + size_hint: .2, .2 +''')) + Clock.schedule_once(add_button, 1) + Clock.schedule_once(add_button) + + def showcase_anchorlayout(self, layout): + + def change_anchor(self, *l): + if not layout.get_parent_window(): + return + anchor_x = ('left', 'center', 'right') + anchor_y = ('top', 'center', 'bottom') + if layout.anchor_x == 'left': + layout.anchor_y = anchor_y[anchor_y.index(layout.anchor_y) - 1] + layout.anchor_x = anchor_x[anchor_x.index(layout.anchor_x) - 1] + + Clock.schedule_once(change_anchor, 1) + Clock.schedule_once(change_anchor, 1) + + def _update_clock(self, dt): + self.time = time() + + +if __name__ == '__main__': + ShowcaseApp().run() + +""" +Name + +# Adresse / Lage + +Baujahr: + +Kaufpreis: + +davon Grundstück (in Euro oder Prozent) + +([davon] Sanierungskosten) + +Kaufnebenkosten: +- Notar +- Grundbuch +- Grunderwerbssteuer +- Provision + + +Fläche (qm): + +- Kosten pro qm (reiner Kaufpreis) +- Kosten pro qm (inkl. Nebenkosten) + + +Mieteinnahme (pro Jahr / Monat) + +Geschätzte Mietsteigerung pro Jahr (%) +ab welchem Jahr + +Instandhaltungskosten / Rücklage +Instandhaltungsrücklage: +1. bis 5. Jahr 3,00 Euro / m² +6. bis 10. Jahr 6,00 Euro / m² +11. bis 15. Jahr 7,50 Euro / m² +ab 16. Jahr 9,00 Euro / m² + +Verwalutngskosten pro Jahr + +Geschätzte Kostensteigerung pro Jahr + + +Finanzierung +- Eigenkapital +- Zinssatz (ggf. automatisch aus Zinsbindungsdauer abgeleitet) +- Tilgung +- (geschätzter Anschlusszinssatz / ggf. abgeleitet aus Zinsbindungsdauer) + + +Infos: +https://www.zinsland.de/blog/immobilien-investment/immobilien-steuern-sparen/ + +Von Steuer von absetzbar: + +Das können Vermieter von der Steuer absetzen (Auswahl): +Immobilienanzeigen +Maklerprovision +Fahrtkosten +Zinsen +Anschaffungskosten der Immobilie +Grundsteuer +Kosten für möblierte Wohnung +Reparatur- und Renovierungsarbeiten +Anwalt und Steuerberater +Die Anschaffungs- oder Herstellungskosten der Immobilie absetzen +Viele Kosten einer Immobilie können Sie durch die Steuererklärung wieder reinholen – sogar einen Teil der Anschaffungs- oder Herstellungskosten. Dafür gelten, je nach Baujahr des Kaufobjekts, zwei unterschiedliche Regelungen: + +Wurde die Immobilie vor dem 31. Dezember 1924 gebaut, können Sie 40 Jahre lang jährlich 2,5 Prozent der Herstellungs- und Anschaffungskosten von der Steuer absetzen. + +Wurde die Immobilie erst nach diesem Datum gebaut, also nach 1924, können Sie über 50 Jahre hinweg 2 Prozent pro Jahr geltend machen. + +Ob Sie Ihr Wunschobjekt dabei kaufen oder selbst bauen lassen, ist unerheblich. In beiden Fällen profitieren Sie von denselben Steuervorteilen Ihres Eigenheims. + +Die Kosten für Reparatur- und Renovierungsarbeiten +Ob die Heizung ein Leck hat, der Wasserhahn tropft oder die Fenster erneuert werden müssen: In den meisten Fällen muss der Vermieter bei Schäden in der Wohnung zahlen. Glücklicherweise können die Handwerkerkosten für Reparatur- und Renovierungsarbeiten komplett von der Steuer abgesetzt werden. + +Auch hierbei können die Ausgaben als Werbungskosten in der Steuererklärung geltend gemacht werden. Hierfür müssen Sie die Anlage V der Steuerklärung entsprechend ausfüllen. Entweder geben Sie dabei die vollen Kosten für ein Jahr an oder Sie verteilen die Ausgaben gleichmäßig auf bis zu fünf Jahre. + +Hausnebenkosten von der Steuer absetzen +Normalerweise legen Sie als Vermieter die Hausnebenkosten (Müllabfuhr, Versicherung, Wasser, Hausmeister) direkt auf den Mieter um. Die Einkünfte, die der Vermieter durch diese Nebenkosten erhält, müssen zwar auch in der Steuerklärung angegeben werden. Allerdings ist auch hier die Absetzung als Werbungskosten möglich. + +Dazu zählen beispielsweise die Instandsetzung der Heizung, die Reinigung der Gemeinschafträume oder der Winterdienst. Nur, wenn Sie die genannten Tätigkeiten selbst durchführen, können Sie Ihre eigene Arbeitsleistung nicht absetzen (dafür aber die Kosten für Werkzeug, Material und die Fahrtkosten). + +Bei Leerstand trotzdem Steuern sparen +Der Leerstand eines vermieteten Objekts ist der Albtraum eines jeden Vermieters. Doch selbst in diesem Fall können Sie mit Ihrer Immobilie Steuern sparen. Denn auch ohne regelmäßige Einkünfte können die anfallenden Kosten von der Steuer abgesetzt werden. + +Allerdings müssen Sie als Vermieter beweisen, dass Sie während des Leerstands auch ernsthaft nach einem neuen Mieter suchen. Hierfür reichen anfangs vorgelegte Inserate in Zeitungen oder Online-Parteien. Später müssen Sie einen Makler beauftragen oder nach einigen Monaten gar eine Renovierung durchführen. + + +Wichtige Infos: + +Kaufpreis +-Kaufnebenkosten (Maklerprovision, Notarkosten, Grunderwerbsteuer, Ämter und Dienstleister, Renovierungskosten) +-Betriebskosten +-Finanzierungskosten +-Einnahmen durch Mieten + +Um unerfahrenen Anlegern ein Objekt schmackhaft zu machen, nehmen Makler häufig nur die monatlichen Nettomieteinnahmen, um die Rendite zu bestimmen, wodurch diese auf den ersten Blick natürlich sehr hoch aussehen. Diese Bruttoanfangsrendite hat keine Aussagekraft, sondern ist lediglich ein gefälliges Verkaufsargument für unerfahrene Käufer. Dass der Kredit bei der Bank abgezahlt werden muss, die Tilgung die Liquidität schmälert und regelmäßig ins Gebäude investiert werden muss, wird nicht mit in die Kalkulation einbezogen. Zieht man nun alle Faktoren in die professionelle Kalkulation mit ein, sind oftmals nur noch rote Zahlen bei dem vormals so renditestarken Investment zu sehen. Das Investment ist zum monatlichen Verlustbringer geworden. Das aber verkauft sich nun mal nicht und so wird im Verkauf nur mit der Bruttoanfangsrendite gerechnet. + +Verwatlungskosten (ggf. sind die überflüssig – zumindest zunächst): ca. 20€ pro Monat und Wohneinheit + +Kaufpreisfaktor: + +Kaufpreis/ (100%/90%*Jahreskaltmiete): Daraus Mietrendite, z.B. Faktor 20: 5%, Faktor 25: 4% etc. +Aktuell zwischen 25 und 30 (teils (leicht) drüber) + +""" diff --git a/projctrl_info.md b/projctrl_info.md new file mode 100644 index 0000000..09093ff --- /dev/null +++ b/projctrl_info.md @@ -0,0 +1 @@ +Default readme for immoinvest Some project description here! OS: diff --git a/showcase.kv b/showcase.kv new file mode 100644 index 0000000..7843c7d --- /dev/null +++ b/showcase.kv @@ -0,0 +1,100 @@ +#:kivy 1.8.0 +#:import KivyLexer kivy.extras.highlight.KivyLexer +#:import Factory kivy.factory.Factory + + + background_color: .4, .4, .4, 1 + + + canvas.before: + Color: + rgba: 0.128, 0.128, 0.128, 1 + Rectangle: + size: self.size + pos: self.pos + border: 27, 20, 12, 12 + background_normal: 'atlas://data/images/defaulttheme/action_group' + option_cls: Factory.ActionSpinnerOptions + +: + on_size: self.width = '220dp' + +: + ScrollView: + do_scroll_x: False + do_scroll_y: False if root.fullscreen else (content.height > root.height - dp(16)) + AnchorLayout: + size_hint_y: None + height: root.height if root.fullscreen else max(root.height, content.height) + GridLayout: + id: content + cols: 1 + spacing: '8dp' + padding: '8dp' + size_hint: (1, 1) if root.fullscreen else (.8, None) + height: self.height if root.fullscreen else self.minimum_height + + +BoxLayout: + orientation: 'vertical' + + canvas.before: + Color: + rgb: .6, .6, .6 + Rectangle: + size: self.size + source: 'data/background.png' + + ActionBar: + + ActionView: + id: av + ActionPrevious: + with_previous: (False if sm.current_screen.name == 'button' else True) if sm.current_screen else False + title: 'Showcase' + ('' if not app.current_title else ' - {}'.format(app.current_title)) + on_release: app.go_hierarchy_previous() + + ActionSpinner: + id: spnr + important: True + text: 'Jump to Screen' + values: app.screen_names + on_text: + if sm.current != args[1]:\ + idx = app.screen_names.index(args[1]);\ + app.go_screen(idx) + ActionToggleButton: + text: 'Toggle sourcecode' + icon: 'data/icons/bug.png' + on_release: app.toggle_source_code() + ActionButton: + text: 'Previous screen' + icon: 'data/icons/chevron-left.png' + on_release: app.go_previous_screen() + + ActionButton: + text: 'Next screen' + icon: 'data/icons/chevron-right.png' + on_release: app.go_next_screen() + important: True + + ScrollView: + id: sv + size_hint_y: None + height: 0 + + CodeInput: + id: sourcecode + lexer: KivyLexer() + text: app.sourcecode + readonly: True + size_hint_y: None + font_size: '12sp' + height: self.minimum_height + + ScreenManager: + id: sm + on_current_screen: + spnr.text = args[1].name + idx = app.screen_names.index(args[1].name) + if idx > -1: app.hierarchy.append(idx) \ No newline at end of file