mirror of
https://github.com/markqvist/Sideband.git
synced 2025-08-03 12:06:07 -04:00
Updated kivymd
This commit is contained in:
parent
c6df8b851b
commit
abcf173cc8
160 changed files with 11617 additions and 6545 deletions
|
@ -1,3 +0,0 @@
|
|||
%s
|
||||
def get_view(self) -> %s:
|
||||
return self.view
|
|
@ -1,26 +0,0 @@
|
|||
# FILE TO FIND AND CREATE LOCALIZATION FILES FOR YOUR APPLICATION. \
|
||||
\
|
||||
In this file, you can specify in which files of your project to search for \
|
||||
localization strings. \
|
||||
These files should be listed in the below command: \
|
||||
\
|
||||
\
|
||||
xgettext -Lpython --output=messages.pot --from-code=utf-8 \
|
||||
path/to/file-1 \
|
||||
path/to/file-2 \
|
||||
...
|
||||
|
||||
.PHONY: po mo
|
||||
|
||||
po:
|
||||
xgettext -Lpython --output=messages.pot --from-code=utf-8 \
|
||||
View/%s/%s.kv \
|
||||
View/%s/%s.py
|
||||
msgmerge --update --no-fuzzy-matching --backup=off data/locales/po/en.po messages.pot
|
||||
msgmerge --update --no-fuzzy-matching --backup=off data/locales/po/ru.po messages.pot
|
||||
|
||||
mo:
|
||||
mkdir -p data/locales/en/LC_MESSAGES
|
||||
mkdir -p data/locales/ru/LC_MESSAGES
|
||||
msgfmt -c -o data/locales/en/LC_MESSAGES/%s.mo data/locales/po/en.po
|
||||
msgfmt -c -o data/locales/ru/LC_MESSAGES/%s.mo data/locales/po/ru.po
|
|
@ -1,33 +0,0 @@
|
|||
# The model implements the observer pattern. This means that the class must
|
||||
# support adding, removing, and alerting observers. In this case, the model is
|
||||
# completely independent of controllers and views. It is important that all
|
||||
# registered observers implement a specific method that will be called by the
|
||||
# model when they are notified (in this case, it is the `model_is_changed`
|
||||
# method). For this, observers must be descendants of an abstract class,
|
||||
# inheriting which, the `model_is_changed` method must be overridden.
|
||||
|
||||
|
||||
class BaseScreenModel:
|
||||
"""Implements a base class for model modules."""
|
||||
|
||||
_observers = []
|
||||
|
||||
def add_observer(self, observer) -> None:
|
||||
self._observers.append(observer)
|
||||
|
||||
def remove_observer(self, observer) -> None:
|
||||
self._observers.remove(observer)
|
||||
|
||||
def notify_observers(self, name_screen: str) -> None:
|
||||
"""
|
||||
Method that will be called by the observer when the model data changes.
|
||||
|
||||
:param name_screen:
|
||||
name of the view for which the method should be called
|
||||
:meth:`model_is_changed`.
|
||||
"""
|
||||
|
||||
for observer in self._observers:
|
||||
if observer.name == name_screen:
|
||||
observer.model_is_changed()
|
||||
break
|
|
@ -1 +0,0 @@
|
|||
%s
|
|
@ -1,16 +0,0 @@
|
|||
# Of course, "very flexible Python" allows you to do without an abstract
|
||||
# superclass at all or use the clever exception `NotImplementedError`. In my
|
||||
# opinion, this can negatively affect the architecture of the application.
|
||||
# I would like to point out that using Kivy, one could use the on-signaling
|
||||
# model. In this case, when the state changes, the model will send a signal
|
||||
# that can be received by all attached observers. This approach seems less
|
||||
# universal - you may want to use a different library in the future.
|
||||
|
||||
|
||||
class Observer:
|
||||
"""Abstract superclass for all observers."""
|
||||
|
||||
def model_is_changed(self):
|
||||
"""
|
||||
The method that will be called on the observer when the model changes.
|
||||
"""
|
|
@ -1,72 +0,0 @@
|
|||
#:import images_path kivymd.images_path
|
||||
#:import colors kivymd.color_definitions.colors
|
||||
#:import get_color_from_hex kivy.utils.get_color_from_hex
|
||||
|
||||
|
||||
<%s>
|
||||
|
||||
FitImage:
|
||||
source:
|
||||
( \
|
||||
f"{images_path}restdb-logo.png" \
|
||||
if root.model.database.name == "RestDB" else \
|
||||
f"{images_path}firebase-logo.png" \
|
||||
) \
|
||||
if hasattr(root.model, "database") else \
|
||||
f"{images_path}transparent.png"
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "vertical"
|
||||
|
||||
MDToolbar:
|
||||
id: toolbar
|
||||
title: "%s"
|
||||
right_action_items: [["web", lambda x: %s]]
|
||||
md_bg_color:
|
||||
( \
|
||||
get_color_from_hex(colors["Yellow"]["700"]) \
|
||||
if root.model.database.name == "Firebase" else \
|
||||
get_color_from_hex(colors["Blue"]["300"]) \
|
||||
) \
|
||||
if hasattr(root.model, "database") else \
|
||||
app.theme_cls.primary_color
|
||||
|
||||
MDFloatLayout:
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "vertical"
|
||||
adaptive_height: True
|
||||
size_hint_x: None
|
||||
width: root.width - dp(72)
|
||||
radius: 12
|
||||
padding: "12dp"
|
||||
md_bg_color: 1, 1, 1, .5
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
|
||||
MDLabel:
|
||||
id: prev_label
|
||||
text: %s
|
||||
font_style: "H6"
|
||||
adaptive_height: True
|
||||
halign: "center"
|
||||
color: 1, 1, 1, 1
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "vertical"
|
||||
adaptive_height: True
|
||||
padding: "50dp"
|
||||
spacing: "20dp"
|
||||
|
||||
MDTextField:
|
||||
hint_text: %s
|
||||
on_text: root.controller.set_user_data("login", self.text)
|
||||
|
||||
MDTextField:
|
||||
hint_text: %s
|
||||
on_text: root.controller.set_user_data("password", self.text)
|
||||
|
||||
MDFillRoundFlatButton:
|
||||
text: %s
|
||||
on_release: root.controller.on_tap_button_login()
|
||||
pos_hint: {"center_x": .5, "center_y": .1}
|
||||
md_bg_color: toolbar.md_bg_color
|
|
@ -1,15 +0,0 @@
|
|||
%s
|
||||
from View.base_screen import BaseScreenView
|
||||
|
||||
|
||||
class %s(BaseScreenView):
|
||||
"""Implements the login start screen in the user application."""
|
||||
%s
|
||||
def model_is_changed(self) -> None:
|
||||
"""
|
||||
Called whenever any change has occurred in the data model.
|
||||
The view in this method tracks these changes and updates the UI
|
||||
according to these changes.
|
||||
"""
|
||||
|
||||
%s
|
|
@ -1,47 +0,0 @@
|
|||
from kivy.properties import ObjectProperty
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.theming import ThemableBehavior
|
||||
from kivymd.uix.screen import MDScreen
|
||||
|
||||
from Utility.observer import Observer
|
||||
|
||||
|
||||
class BaseScreenView(ThemableBehavior, MDScreen, Observer):
|
||||
"""
|
||||
A base class that implements a visual representation of the model data
|
||||
:class:`~Model.%s.%s`.
|
||||
The view class must be inherited from this class.
|
||||
"""
|
||||
|
||||
controller = ObjectProperty()
|
||||
"""
|
||||
Controller object - :class:`~Controller.%s.%s`.
|
||||
|
||||
:attr:`controller` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to `None`.
|
||||
"""
|
||||
|
||||
model = ObjectProperty()
|
||||
"""
|
||||
Model object - :class:`~Model.%s.%s`.
|
||||
|
||||
:attr:`model` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to `None`.
|
||||
"""
|
||||
|
||||
manager_screens = ObjectProperty()
|
||||
"""
|
||||
Screen manager object - :class:`~kivy.uix.screenmanager.ScreenManager`.
|
||||
|
||||
:attr:`manager_screens` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to `None`.
|
||||
"""
|
||||
|
||||
def __init__(self, **kw):
|
||||
super().__init__(**kw)
|
||||
# Often you need to get access to the application object from the view
|
||||
# class. You can do this using this attribute.
|
||||
self.app = MDApp.get_running_app()
|
||||
# Adding a view class as observer.
|
||||
self.model.add_observer(self)
|
|
@ -1,13 +0,0 @@
|
|||
# The screens dictionary contains the objects of the models and controllers
|
||||
# of the screens of the application.
|
||||
|
||||
from Model.%s import %s
|
||||
|
||||
from Controller.%s import %s
|
||||
|
||||
screens = {
|
||||
%s: {
|
||||
"model": %s,
|
||||
"controller": %s,
|
||||
},
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
"""
|
||||
The entry point to the application.
|
||||
|
||||
The application uses the MVC template. Adhering to the principles of clean
|
||||
architecture means ensuring that your application is easy to test, maintain,
|
||||
and modernize.
|
||||
|
||||
You can read more about this template at the links below:
|
||||
|
||||
https://github.com/HeaTTheatR/LoginAppMVC
|
||||
https://en.wikipedia.org/wiki/Model–view–controller
|
||||
"""
|
||||
|
||||
from typing import NoReturn
|
||||
|
||||
from kivy.uix.screenmanager import ScreenManager%s
|
||||
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from View.screens import screens%s
|
||||
%s
|
||||
|
||||
class %s(MDApp):%s
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)%s
|
||||
self.load_all_kv_files(self.directory)
|
||||
# This is the screen manager that will contain all the screens of your
|
||||
# application.
|
||||
self.manager_screens = ScreenManager()
|
||||
%s
|
||||
def build(self) -> ScreenManager:
|
||||
self.generate_application_screens()
|
||||
return self.manager_screens
|
||||
|
||||
def generate_application_screens(self) -> NoReturn:
|
||||
"""
|
||||
Creating and adding screens to the screen manager.
|
||||
You should not change this cycle unnecessarily. He is self-sufficient.
|
||||
|
||||
If you need to add any screen, open the `View.screens.py` module and
|
||||
see how new screens are added according to the given application
|
||||
architecture.
|
||||
"""
|
||||
|
||||
for i, name_screen in enumerate(screens.keys()):
|
||||
model = screens[name_screen]["model"](%s)
|
||||
controller = screens[name_screen]["controller"](model)
|
||||
view = controller.get_view()
|
||||
view.manager_screens = self.manager_screens
|
||||
view.name = name_screen
|
||||
self.manager_screens.add_widget(view)
|
||||
%s%s
|
||||
|
||||
%s().run()
|
210
sbapp/kivymd/tools/patterns/add_view.py
Normal file
210
sbapp/kivymd/tools/patterns/add_view.py
Normal file
|
@ -0,0 +1,210 @@
|
|||
"""
|
||||
The script creates a new View package
|
||||
=====================================
|
||||
|
||||
The script creates a new View package in an existing project with an MVC
|
||||
template created using the create_project utility.
|
||||
|
||||
.. versionadded:: 1.0.0
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Utility create_project <https://kivymd.readthedocs.io/en/latest/api/kivymd/tools/patterns/create_project/>`_
|
||||
|
||||
.. rubric:: Use a clean architecture for your applications.
|
||||
|
||||
To add a new view to an existing project that was created using the
|
||||
`create_project` utility, use the following command::
|
||||
|
||||
kivymd.add_view \\
|
||||
name_pattern \\
|
||||
path_to_project \\
|
||||
name_view
|
||||
|
||||
Example command::
|
||||
|
||||
kivymd.add_view \\
|
||||
MVC \\
|
||||
/Users/macbookair/Projects \\
|
||||
NewScreen
|
||||
|
||||
You can also add new views with responsive behavior to an existing project::
|
||||
|
||||
kivymd.add_view \\
|
||||
MVC \\
|
||||
/Users/macbookair/Projects \\
|
||||
NewScreen \\
|
||||
--use_responsive yes
|
||||
|
||||
For more information about adaptive design,
|
||||
`see here <https://kivymd.readthedocs.io/en/latest/components/responsivelayout/>`_.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
"main",
|
||||
]
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from kivy import Logger
|
||||
|
||||
from kivymd.tools.argument_parser import ArgumentParserWithHelp
|
||||
from kivymd.tools.patterns.create_project import (
|
||||
chek_camel_case_name_project,
|
||||
create_common_responsive_module,
|
||||
create_controller,
|
||||
create_model,
|
||||
create_view,
|
||||
)
|
||||
|
||||
screens_data = """%s
|
||||
|
||||
screens = {%s
|
||||
}"""
|
||||
|
||||
screns_comment = """# The screen's dictionary contains the objects of the models and controllers
|
||||
# of the screens of the application.
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
"""The function of adding a new view to the project."""
|
||||
|
||||
global screens_data
|
||||
|
||||
parser = create_argument_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
# pattern_name isn't used currently, will be used if new patterns is added in future
|
||||
pattern_name = args.pattern # noqa F841
|
||||
path_to_project = args.directory
|
||||
name_view = args.name
|
||||
use_responsive = args.use_responsive
|
||||
|
||||
if not os.path.exists(path_to_project):
|
||||
parser.error(f"Project <{path_to_project}> does not exist...")
|
||||
|
||||
if name_view[-6:] != "Screen":
|
||||
parser.error(
|
||||
f"The name of the <{name_view}> screen should contain the word "
|
||||
f"'Screen' at the end.\n"
|
||||
"For example - '--name_screen MyFirstScreen ...'"
|
||||
)
|
||||
|
||||
if name_view in os.listdir(os.path.join(path_to_project, "View")):
|
||||
parser.error(
|
||||
f"The <{name_view}> view also exists in the <{path_to_project}> project..."
|
||||
)
|
||||
|
||||
# Create model.
|
||||
name_database = (
|
||||
"yes"
|
||||
if "database.py" in os.listdir(os.path.join(path_to_project, "Model"))
|
||||
else "no"
|
||||
)
|
||||
module_name = chek_camel_case_name_project(name_view)
|
||||
if not module_name:
|
||||
parser.error(
|
||||
"The name of the screen should be written in camel case style. "
|
||||
"\nFor example - 'MyFirstScreen'"
|
||||
)
|
||||
module_name = "_".join([name.lower() for name in module_name])
|
||||
path_to_project = path_to_project
|
||||
create_model(name_view, module_name, name_database, path_to_project)
|
||||
|
||||
# Create controller.
|
||||
# FIXME: This is not a very good solution in order to understand whether
|
||||
# a project uses a hot reload or not. Because the string
|
||||
# 'from kivymd.tools.hotreload.app import MDApp' in the project can just
|
||||
# be commented out and the project does not actually use hot reload.
|
||||
with open(os.path.join(path_to_project, "main.py")) as main_module:
|
||||
if "from kivymd.tools.hotreload.app import MDApp" in main_module.read():
|
||||
use_hotreload = "yes"
|
||||
else:
|
||||
use_hotreload = "no"
|
||||
create_controller(
|
||||
name_view, module_name, use_hotreload, path_to_project
|
||||
)
|
||||
# Create View.
|
||||
if use_responsive == "no":
|
||||
create_view(name_view, module_name, [], path_to_project)
|
||||
else:
|
||||
create_view(name_view, module_name, [name_view], path_to_project)
|
||||
create_common_responsive_module([name_view], path_to_project)
|
||||
# Create 'View.screens.py module'.
|
||||
create_screens_data(name_view, module_name, path_to_project)
|
||||
Logger.info(
|
||||
f"KivyMD: The {name_view} view has been added to the project..."
|
||||
)
|
||||
|
||||
|
||||
def create_screens_data(
|
||||
name_view: str, module_name: str, path_to_project: str
|
||||
) -> None:
|
||||
with open(
|
||||
os.path.join(path_to_project, "View", "screens.py")
|
||||
) as screen_module:
|
||||
screen_module = screen_module.read()
|
||||
imports = re.findall(
|
||||
"from Model.*Model|from Controller.*Controller", screen_module
|
||||
)
|
||||
screens = ""
|
||||
path_to_view = os.path.join(path_to_project, "View")
|
||||
|
||||
for name in os.listdir(path_to_view):
|
||||
if os.path.isdir(os.path.join(path_to_view, name)):
|
||||
res = re.findall("[A-Z][a-z]*", name)
|
||||
if res and len(res) == 2 and res[-1] == "Screen":
|
||||
screens += (
|
||||
"\n '%s': {"
|
||||
"\n 'model': %s,"
|
||||
"\n 'controller': %s,"
|
||||
"\n },"
|
||||
% (
|
||||
f"{res[0].lower()} {res[1].lower()}",
|
||||
f'{"".join(res)}Model',
|
||||
f'{"".join(res)}Controller',
|
||||
)
|
||||
)
|
||||
|
||||
imports.append(f"from Model.{module_name} import {name_view}Model")
|
||||
imports.append(
|
||||
f"from Controller.{module_name} import {name_view}Controller"
|
||||
)
|
||||
imports.insert(0, screns_comment)
|
||||
screens = screens_data % ("\n".join(imports), screens)
|
||||
|
||||
with open(
|
||||
os.path.join(path_to_project, "View", "screens.py"), "w"
|
||||
) as screen_module:
|
||||
screen_module.write(screens)
|
||||
|
||||
|
||||
def create_argument_parser() -> ArgumentParserWithHelp:
|
||||
parser = ArgumentParserWithHelp(
|
||||
prog="create_project.py",
|
||||
allow_abbrev=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"pattern",
|
||||
help="the name of the pattern with which the project will be created.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"directory",
|
||||
help="the directory of the project to which you want to add a new view.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"name",
|
||||
help="the name of the view to add to an existing project.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use_responsive",
|
||||
default="no",
|
||||
help="whether to create a view with responsive behavior.",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue