From 245c95cf93905d5121fdc3e97ee3e2c735a7ae1f Mon Sep 17 00:00:00 2001 From: mdmujtabaraza <45493966+mdmujtabaraza@users.noreply.github.com> Date: Fri, 8 Apr 2022 00:45:13 +0530 Subject: [PATCH] Added tags feature and many fixes + improvements --- main.py | 5 + src/__pycache__/app.cpython-38.pyc | Bin 18122 -> 20809 bytes src/app.kv | 75 ++++++-- src/app.py | 177 ++++++++++++++---- src/db.py | 28 +++ .../__pycache__/json_to_apkg.cpython-38.pyc | Bin 4423 -> 4438 bytes src/lib/helpers.py | 4 +- src/lib/json_to_apkg.py | 5 +- strings/en-us.json | 3 + 9 files changed, 239 insertions(+), 58 deletions(-) create mode 100644 src/db.py diff --git a/main.py b/main.py index da22f82..0e87b3b 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,7 @@ # /storage/emulate/0/Download # '/storage/emulated/0/Android/data/org.test.vocabtoanki/files/media/' # settings_path /data/user/0/org.test.vocabtoanki/files +# /data/user/0/org.test.vocabtoanki/files # https://pyjnius.readthedocs.io/en/stable/android.html # plyer # https://python-for-android.readthedocs.io/en/latest/apis/ @@ -53,8 +54,10 @@ import ssl from src.app import MyApp +from src.db import connection from src.lib.helpers import get_root_path + if __name__ == '__main__': if 'ANDROID_STORAGE' in os.environ: try: @@ -72,3 +75,5 @@ for f in mp3_files: os.remove(f) os.remove(root_path + 'output.apkg') + + connection.close() diff --git a/src/__pycache__/app.cpython-38.pyc b/src/__pycache__/app.cpython-38.pyc index c23af954c054c5fd79a5906a385fbc660f3be316..b18b5172e305a977fe1fde95c292c5480f377a4c 100644 GIT binary patch delta 10547 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 delta 8112 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 diff --git a/src/app.kv b/src/app.kv index 151da1a..c3f3ee2 100644 --- a/src/app.kv +++ b/src/app.kv @@ -46,8 +46,8 @@ ScreenManager: id: dict_dropdown text: get_text("browse_button") font_style: 'Button' - pos_hint: {"center_x": 0.5, 'center_y': 0.85} - on_release: root.open_dropdown(dict_dropdown=True) + pos_hint: {"center_x": 0.5, 'center_y': 0.89} + on_release: root.open_dictionary_dropdown() MDTextField: id: word_input text: get_text("sample_url") @@ -59,10 +59,10 @@ ScreenManager: # icon_right: get_text('paste_icon') # icon_right_color: app.theme_cls.primary_color size_hint: (.75, .1) - pos_hint: {'center_x': 0.45, 'center_y': 0.7} + pos_hint: {'center_x': 0.45, 'center_y': 0.72} MDIconButton: icon: get_text('paste_icon') - pos_hint: {"center_x": .9, "center_y": .7} + pos_hint: {"center_x": .9, "center_y": .72} on_release: word_input.text = Clipboard.paste() # MDLabel: # text: get_text("chose_accent") @@ -70,29 +70,59 @@ ScreenManager: # font_style: 'Body1' # halign: 'center' # pos_hint: {'center_x': 0.5, 'center_y': 0.58} - GridLayout: - cols: 2 - row_force_default: True - row_default_height: 40 - col_force_default: True - col_default_width: 180 - pos_hint: {'center_x': 0.39, 'center_y': 0.5} - size_hint: (None, .1) - MDLabel: - text: get_text("en_uk") + # GridLayout: + # cols: 2 + # row_force_default: True + # row_default_height: 40 + # col_force_default: True + # col_default_width: 180 + # pos_hint: {'center_x': 0.39, 'center_y': 0.5} + # size_hint: (None, .1) + MDTextField: + id: tags_input + padding: "10dp" + multiline: False + hint_text: get_text("tag_info") + helper_text: f"ex: {get_text('sample_tags')}" + helper_text_mode: "on_focus" + icon_left: get_text('tag_icon') + # icon_left_color: 'red' + size_hint: (.75, .1) + pos_hint: {'center_x': 0.45, 'center_y': 0.58} + on_focus: root.tags_input_focus_mode(self.focus) + BoxLayout: + orientation: 'horizontal' + size_hint: (.9, .3) + pos_hint: {"center_x": .54, "center_y": .42} Check: + id: check_uk + width: 36 + pos_hint: {"center_x": .12, "center_y": .4} on_active: root.checkbox_click(self, self.active, "co.uk") MDLabel: - text: get_text("en_us") + width: 152 + pos_hint: {"center_x": .12, "center_y": .4} + text: f'[ref=uk]{get_text("en_uk")}[/ref]' + markup: True + on_ref_press: root.check_it_down(*args) Check: + id: check_us + width: 36 + pos_hint: {"center_x": .25, "center_y": .4} active: True on_active: root.checkbox_click(self, self.active, "com") + MDLabel: + width: 152 + pos_hint: {"center_x": .25, "center_y": .4} + text: f'[ref=us]{get_text("en_us")}[/ref]' + markup: True + on_ref_press: root.check_it_down(*args) MDRectangleFlatButton: text: get_text("generate_flashcards") font_style: 'Button' - pos_hint: {'center_x': 0.5, 'center_y': 0.25} + pos_hint: {'center_x': 0.5, 'center_y': 0.2} on_press: root.dialog_popup(get_text("finding_meanings"), choice(get_text("funny_loading_messages"))) - on_release: root.show_data() + on_release: root.show_meanings() : @@ -143,8 +173,13 @@ ScreenManager: adaptive_height: True - size_hint: (None, 1) - size: (48, 74) - width: 74 + size_hint: (.12, 1) + # size: (48, 74) + # width: 74 pos_hint: {'center_x': .5, 'center_y': .5} on_active: root.on_checkbox_active(*args) + + + + IconLeftWidget: + icon: root.icon \ No newline at end of file diff --git a/src/app.py b/src/app.py index 8977bf7..e30fa36 100644 --- a/src/app.py +++ b/src/app.py @@ -8,10 +8,10 @@ import re import traceback -logging.basicConfig( - level=logging.DEBUG, - format="%(asctime)s:%(levelname)s:%(message)s" -) +# logging.basicConfig( +# level=logging.DEBUG, +# format="%(asctime)s:%(levelname)s:%(message)s" +# ) import bs4 import urllib3 @@ -24,9 +24,11 @@ from kivy.animation import Animation from kivy import require, platform +from kivy.metrics import dp +from kivy.properties import StringProperty from kivymd.app import MDApp from kivymd.toast import toast -from kivymd.uix.list import OneLineListItem, TwoLineListItem +from kivymd.uix.list import OneLineListItem, TwoLineListItem, OneLineIconListItem from kivymd.uix.dialog import MDDialog from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.button import MDFlatButton, MDRaisedButton, MDRectangleFlatButton, MDIconButton, MDFloatingActionButton @@ -34,6 +36,7 @@ from kivy.lang.builder import Builder from kivy.uix.screenmanager import Screen, ScreenManager from kivy.core.window import Window +from kivymd.uix.screen import MDScreen from kivymd.uix.toolbar import MDToolbar from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelTwoLine from kivymd.uix.selectioncontrol import MDCheckbox @@ -49,15 +52,17 @@ from kivy.utils import get_color_from_hex from src.dict_scraper.spiders import cambridge +from src.db import connection, cursor from src.lib.helpers import get_root_path from src.lib.json_to_apkg import JsonToApkg from src.lib.strings import get_text # os.environ["KIVY_NO_CONSOLELOG"] = "1" -require('2.1.0') +# require('2.1.0') -CONTAINER = {'current_url': '', 'requests': [], 'm_checkboxes': [], 'm_checkboxes_selected': 0, 'm_checkboxes_total': 0} +CONTAINER = {'current_url': '', 'requests': [], 'tags': [], 'tags_input_text': '', + 'm_checkboxes': [], 'm_checkboxes_selected': 0, 'm_checkboxes_total': 0} DICTIONARIES = { get_text("cambridge"): "dictionary.cambridge.org/dictionary/english/", get_text("dictionary_com"): "dictionary.com/browse/", @@ -221,12 +226,18 @@ def on_checkbox_active(self, checkbox, value): # print(checkbox) -class MenuScreen(Screen): +class IconListItem(OneLineIconListItem): + icon = StringProperty() + + +class MenuScreen(MDScreen): def __init__(self, **kwargs): # call grid layout constructor super(MenuScreen, self).__init__(**kwargs) - self.dropdown_menu = None + self.dictionary_menu = None + self.tags_menu = None self.dialog = None + self.menu = None self.tld = 'com' self.timestamp = dt.now().strftime("%Y%m%d%H%M%S") @@ -279,7 +290,7 @@ def __init__(self, **kwargs): # self.submit = MDRectangleFlatButton( # text='Submit', # pos_hint={'center_x': 0.5, 'center_y': 0.4}, - # on_release=self.show_data + # on_release=self.show_meanings # ) # bind the button # self.submit.bind(on_press=self.press) @@ -296,11 +307,26 @@ def __init__(self, **kwargs): # self.manager.transition.duration = 0.5 # self.manager.current = 'meanings_screen' - def open_dropdown(self): - if self.dropdown_menu is not None: - self.dropdown_menu.dismiss() + def check_it_down(self, label_obj, lang): + if lang == "us": + self.ids.check_us.active = True + elif lang == 'uk': + self.ids.check_uk.active = True + else: + pass + + def tags_input_focus_mode(self, is_focussed): + if is_focussed: + MDApp.get_running_app().open_tags_dropdown() + else: + if self.tags_menu: + self.tags_menu.dismiss() + + def open_dictionary_dropdown(self): + if self.dictionary_menu is not None: + self.dictionary_menu.dismiss() - self.menu_list = [ + menu_items = [ { "viewclass": "OneLineListItem", "text": get_text("cambridge"), @@ -327,18 +353,14 @@ def open_dropdown(self): "on_release": lambda x=get_text("vocabulary_com"): self.browse_dictionary(x) } ] - self.dropdown_menu = MDDropdownMenu( + self.dictionary_menu = MDDropdownMenu( caller=self.ids.dict_dropdown, - items=self.menu_list, - width_mult=4 + items=menu_items, + position='bottom', + width_mult=4, + max_height=dp(248), ) - self.dropdown_menu.open() - - def find_word(self): - self.open_dropdown() - - def find_idiom(self): - print("idiom is pressed") + self.dictionary_menu.open() def browse_dictionary(self, dictionary_name): webbrowser.open('https://' + DICTIONARIES[dictionary_name]) @@ -456,7 +478,21 @@ def generate_flashcards(self, btn): extracted_dictionary = cambridge.CambridgeSpider( soup, self.tld, checkbox.section_tuple ).parse() - notes.append(jta.generate_note(extracted_dictionary)) + notes.append(jta.generate_note(extracted_dictionary, CONTAINER['tags'])) + # ToDo: Add a database row of tag if not exists + # print(CONTAINER['tags']) + for tag in CONTAINER['tags']: + try: + cursor.execute(""" + INSERT OR REPLACE INTO tags (tag) VALUES (?) + """, (tag,)) + except Exception as e: + print(e) + print(traceback.format_exc()) + # print("inserted") + # print('committing') + connection.commit() + # print('committed') jta.generate_apkg(notes) MDApp.get_running_app().soft_restart() @@ -490,8 +526,11 @@ def change_checkbox_state(self, checkbox): else: checkbox.active = True - def show_data(self): + def show_meanings(self): word_url = self.ids.word_input.text.split('#')[0].split('?')[0] + CONTAINER['tags'] = self.ids.tags_input.text.split() + if not CONTAINER['tags']: + CONTAINER['tags'] = [''] dict_name = None if not validators.url(word_url): self.toast(get_text("url_not_found")) @@ -597,11 +636,11 @@ def show_data(self): # )) # clear the input boxes - self.ids.word_input.text = "" + # self.ids.word_input.text = "" return True -class MeaningsScreen(Screen): +class MeaningsScreen(MDScreen): def __init__(self, **kwargs): # call grid layout constructor super(MeaningsScreen, self).__init__(**kwargs) @@ -675,15 +714,19 @@ class MyApp(MDApp): menu_screen_instance = MenuScreen() meanings_screen_instance = MeaningsScreen() + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.screen = Builder.load_file("src/app.kv") + def build(self): + Window.bind(on_keyboard=self._on_keyboard_handler) # sm.add_widget(MenuScreen(name='menu_screen')) # sm.add_widget(MeaningsScreen(name='meanings_screen')) self.title = get_text("app_title") self.theme_cls.primary_palette = "Blue" self.theme_cls.theme_style = "Dark" self.theme_cls.material_style = "M3" - screen = Builder.load_file("src/app.kv") - return screen + return self.screen # return sm # return MyLayout() @@ -713,6 +756,7 @@ def restart(self): self.stop() global CONTAINER CONTAINER['current_url'] = '' + CONTAINER['tags'] = [] CONTAINER['m_checkboxes'] = [] CONTAINER['m_checkboxes_selected'] = 0 CONTAINER['m_checkboxes_total'] = 0 @@ -732,11 +776,10 @@ def change_screen(self): def soft_restart(self): global CONTAINER CONTAINER['current_url'] = '' + CONTAINER['tags'] = [] CONTAINER['m_checkboxes'] = [] CONTAINER['m_checkboxes_selected'] = 0 CONTAINER['m_checkboxes_total'] = 0 - self.root.transition.direction = 'right' - self.root.transition.duration = 0.5 # 0.5 second meanings_screen = self.root.get_screen("meanings_screen") meanings_screen.ids.toolbar.title = get_text("app_title") @@ -746,7 +789,10 @@ def soft_restart(self): # meanings_screen.ids.toolbar.right_action_items = \ # [[get_text("select_all_icon"), lambda x: self.get_running_app().meanings_screen_instance.select_all()]] meanings_screen.ids.meanings_selection_list.clear_widgets() - self.root.current = 'menu_screen' + # self.root.transition.direction = 'right' + # self.root.transition.duration = 0.5 # 0.5 second + # self.root.current = 'menu_screen' + self.change_screen() # def callback(self, button): # Snackbar(text="Hello World").open() @@ -773,6 +819,71 @@ def soft_restart(self): # meanings_screen.ids.toolbar.left_action_items = left_action_items # meanings_screen.ids.toolbar.right_action_items = right_action_items + def _on_keyboard_handler(self, instance, key, *args): + # print(key, chr(key)) + menu_screen = self.root.get_screen("menu_screen") + + if menu_screen.ids.tags_input.focus: + menu_screen_instance = self.get_running_app().menu_screen_instance + if menu_screen_instance.tags_menu: + menu_screen_instance.tags_menu.dismiss() + if key == 8: + self.open_tags_dropdown() + else: + self.open_tags_dropdown(chr(key)) + # CONTAINER['tags_input_text'] = CONTAINER['tags_input_text'][:-1] + # elif key == 32: + # CONTAINER['tags_input_text'] = '' + # else: + # CONTAINER['tags_input_text'] += chr(key) + + def open_tags_dropdown(self, key=None): + menu_screen = self.root.get_screen("menu_screen") + menu_screen_instance = self.get_running_app().menu_screen_instance + menu_items = [] + try: + typed_tag = menu_screen.ids.tags_input.text.split()[-1] if key is None \ + else menu_screen.ids.tags_input.text.split()[-1] + key + except IndexError: + typed_tag = '' + # print("typed_tag:", typed_tag) + if not typed_tag: + cursor.execute(f"SELECT tag FROM tags ORDER BY tag DESC LIMIT 5") + else: + cursor.execute(f"SELECT tag FROM tags WHERE tag LIKE '%{typed_tag}%' ORDER BY tag DESC LIMIT 5") + for row in cursor.fetchall(): + some_dict = { + "viewclass": "IconListItem", + "icon": get_text("tag_icon"), + "height": dp(56), + "text": row[0], + "on_release": lambda x=row[0]: self.set_tag(x), + } + menu_items.append(some_dict) + menu_screen_instance.tags_menu = MDDropdownMenu( + caller=menu_screen.ids.tags_input, + items=menu_items, + position='bottom', + width_mult=4, + ) + menu_screen_instance.tags_menu.open() + + def set_tag(self, tag): + menu_screen = self.root.get_screen("menu_screen") + menu_screen_instance = self.get_running_app().menu_screen_instance + + tags = menu_screen.ids.tags_input.text + if ' ' in tags: + tags_list = tags.split() + tags_list[-1] = tag + tags = ' '.join(tags_list) + else: + tags = tag + + menu_screen.ids.tags_input.text = tags + ' ' + menu_screen_instance.tags_menu.dismiss() + menu_screen.ids.tags_input.focus = True + def on_selected(self): meanings_screen = self.root.get_screen("meanings_screen") export_button = \ diff --git a/src/db.py b/src/db.py new file mode 100644 index 0000000..af51c9a --- /dev/null +++ b/src/db.py @@ -0,0 +1,28 @@ +import sqlite3 + +from src.lib.helpers import get_root_path + +connection = sqlite3.connect(f'{get_root_path()}data.db') +cursor = connection.cursor() + +# https://stackoverflow.com/a/44951682 +cursor.execute(""" +CREATE TABLE IF NOT EXISTS tags( +tag TEXT NOT NULL COLLATE NOCASE, +PRIMARY KEY(tag) +) +""") +# dt datetime default current_timestamp + +# Without a COLLATE INDEX our queries will do a full table scan +# EXPLAIN QUERY PLAN SELECT * FROM tags WHERE tag = 'some-tag; +# output: SCAN TABLE tags + +# When COLLATE NOCASE index is present, the query does not scan all rows. +# EXPLAIN QUERY PLAN SELECT * FROM tags WHERE tag = 'some-tag'; +# output: SEARCH TABLE tags USING INDEX idx_nocase_tags (tag=?) + +# Refer: https://www.designcise.com/web/tutorial/how-to-do-case-insensitive-comparisons-in-sqlite +cursor.execute(""" +CREATE INDEX IF NOT EXISTS idx_nocase_tags ON tags (tag COLLATE NOCASE) +""") diff --git a/src/lib/__pycache__/json_to_apkg.cpython-38.pyc b/src/lib/__pycache__/json_to_apkg.cpython-38.pyc index 08a12ce8f728db7c0ff09180cbd3690c2e06d9c4..b697fcae4b529f61b1e0210a3288ce33ca0f9533 100644 GIT binary patch delta 159 zcmX@EbWMpbl$V!_0SJE0@JnJ+-^l08F2xMuLjfC*<^^JBATGW)Ih(zVk$LhX_E2G# z5{4}H8s-|78m1J*UglcX8rIDo9OCT4%(qx`^HWlDigbWlZn2akrWa4n;nx#pE0O~W wM6qSXr(`CV6gdGolUMM&F$PS2&+o^|$n=+ub+Uti52Nd3enIicO9U1J0DH_OGXMYp delta 144 zcmcbnbX diff --git a/src/lib/helpers.py b/src/lib/helpers.py index 922746e..6218ed7 100644 --- a/src/lib/helpers.py +++ b/src/lib/helpers.py @@ -1,10 +1,8 @@ import os -from kivy import platform - def get_root_path() -> str: - if platform == 'android': # if 'ANDROID_STORAGE' in os.environ: + if 'ANDROID_STORAGE' in os.environ: from android.storage import app_storage_path # path = f'{app_storage_path()}/' diff --git a/src/lib/json_to_apkg.py b/src/lib/json_to_apkg.py index 1ef2514..6529270 100644 --- a/src/lib/json_to_apkg.py +++ b/src/lib/json_to_apkg.py @@ -113,7 +113,7 @@ def generate_apkg(self, notes): my_package.write_to_file(root_path + apkg_filename) return apkg_filename - def generate_note(self, j_dict): + def generate_note(self, j_dict, tags): # create/initialize model # print('before my_model') # >>> random.randrange(1 << 30, 1 << 31) @@ -167,7 +167,8 @@ def generate_note(self, j_dict): # print('Before my_note') my_note = genanki.Note( model=my_model, - fields=list_of_fields + fields=list_of_fields, + tags=tags ) return my_note diff --git a/strings/en-us.json b/strings/en-us.json index c0af3e3..2b6eaeb 100644 --- a/strings/en-us.json +++ b/strings/en-us.json @@ -11,6 +11,8 @@ "paste_here": "Paste word/expression url here", "chose_accent": "Select Pronunciation Accent", + "tag_info": "Enter tags separated by space", + "sample_tags": "IELTS Phrasal_Verb Intermediate", "en_uk": "English (United Kingdom)", "en_us": "English (United States)", "generate_flashcards": "Generate Anki Flashcards", @@ -29,6 +31,7 @@ "select_none_icon": "select-off", "paste_icon": "clipboard-file", "export_icon": "file-export", + "tag_icon": "tag", "browse_button": "Browse",