Source code for acg.main

"""Contains the Main App :class:`AnkiCardGenApp`."""


import os

import certifi
from kivy import platform
from kivy.clock import mainthread
from kivy.properties import (
    AliasProperty,
    BooleanProperty,
    ConfigParserProperty,
    DictProperty,
    ObjectProperty,
)
from kivy.uix.modalview import ModalView
from kivymd.app import MDApp
from kivymd.uix.filemanager import MDFileManager
from kivymd.uix.spinner import MDSpinner
from pony.orm import db_session

from . import ANKI_DIR, ASSETS_DIR, CONFIG_PATH, HOME, db, screens
from .custom_widgets.main_menu import MainMenu
from .templates import template_cookbook

os.environ["SSL_CERT_FILE"] = certifi.where()


[docs]class AnkiCardGenApp(MDApp): """Main App.""" # Data template = ObjectProperty(force_dispatch=True) # Config apkg_export_dir = ConfigParserProperty( HOME / "ankicardgen", "Paths", "apkg_export_dir", "app", ) import_dir = ConfigParserProperty(HOME, "Paths", "import_dir", "app") kobo_import_dir = ConfigParserProperty(HOME, "Paths", "kobo_import_dir", "app") anki_template_dir = ConfigParserProperty( "vocab_card", "Paths", "anki_template_dir", "app" ) primary_palette = ConfigParserProperty("Red", "Theme", "primary_palette", "app") accent_palette = ConfigParserProperty("Amber", "Theme", "accent_palette", "app") theme_style = ConfigParserProperty("Light", "Theme", "theme_style", "app") source_language = ConfigParserProperty("en", "Template", "source_language", "app") target_language = ConfigParserProperty("pt", "Template", "target_language", "app") current_template_name = ConfigParserProperty( "Portuguese Vocabulary (en)", "Template", "name", "app" ) # TODO: fix bug where default value has to be a valid recipe templates = AliasProperty(getter=lambda *_: template_cookbook.get_recipe_names()) word_state_dict = DictProperty() busy = BooleanProperty(False) busy_modal = ObjectProperty(None) file_manager = ObjectProperty(None)
[docs] def get_anki_template_dir(self): """Return absolute path where html-, css- and js-files for anki-card is located.""" return os.path.join(ANKI_DIR, self.anki_template_dir)
@staticmethod
[docs] def get_application_config(): """Return default path for the config.""" return str(CONFIG_PATH)
[docs] def build_config(self, config): # pylint: disable=no-self-use """If no config-file exists, sets the default.""" config.setdefaults( "Theme", { "primary_palette": "Red", "accent_palette": "Amber", "theme_style": "Light", }, ) config.setdefaults("Paths", {})
[docs] def bind_theme_cls_and_config(self): """Bind :attr:`theme_cls` and the corresponding :class:`~kivy.properties.ConfigParserProperties`.""" keys = self.config["Theme"] self.bind(**{key: self.theme_cls.setter(key) for key in keys}) self.theme_cls.bind(**{key: self.setter(key) for key in keys}) for key in keys: setattr(self.theme_cls, key, getattr(self, key))
[docs] def build(self): """Set up App and return :class:`custom_widgets.MainMenu` as root widget.""" self.bind_theme_cls_and_config() self.file_manager = MDFileManager() os.makedirs(self.apkg_export_dir, exist_ok=True) return MainMenu( screen_dicts=screens.screen_dicts, screen_dir=str(screens.SCREEN_DIR), image_source=str(ASSETS_DIR / "AnkiCardGen.png"),
) @db_session
[docs] def get_current_template_db(self): """Return data-base object for :attr:`current_template_name`.""" return db.Template.get(name=self.current_template_name) or db.Template( name=self.current_template_name
)
[docs] def get_word_states(self): """Return dict of word-states for current template from data-base.""" with db_session: return { card.name: card.state for card in self.get_current_template_db().cards
}
[docs] def new_template_instance(self): """Return new instance of current template class.""" return template_cookbook.cook(self.current_template_name)
[docs] def on_current_template_name(self, *_): """Set up new template if :attr:`current_template_name` changes.""" self.template = self.new_template_instance() self.word_state_dict = self.get_word_states()
[docs] def on_start(self): """Set up template on start of app.""" super().on_start() self.on_current_template_name() self.request_permissions()
[docs] def on_pause(self): # pylint: disable=no-self-use """Enable coming back to app.""" return True
@mainthread
[docs] def on_busy(self, *_): """Set up :attr:`busy_modal` if necessary. Then open or close it depending on state of :attr:`busy`.""" if not self.busy_modal: self.busy_modal = ModalView( auto_dismiss=False, size_hint=(1.2, 1.2), opacity=0.5, ) spinner = MDSpinner(active=False, size_hint=(0.5, 0.5)) self.busy_modal.add_widget(spinner) self.bind(busy=spinner.setter("active")) if self.busy: self.busy_modal.open() else: self.busy_modal.dismiss()
@staticmethod
[docs] def request_permissions(): """Request storage permissions on android.""" if platform == "android": from android.permissions import ( # pylint: disable=import-outside-toplevel Permission, request_permissions, ) request_permissions( [Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE]
)
[docs]def main(): """Main-function.""" AnkiCardGenApp().run()
if __name__ == "__main__": main()