From 4f48bfb3fb4a53c200897c081af6e369aa034ae5 Mon Sep 17 00:00:00 2001 From: shekhar-cis Date: Mon, 21 Mar 2022 20:11:28 +0530 Subject: [PATCH] Add Kivy myaddress screen --- src/bitmessagekivy/baseclass/myaddress.py | 232 ++++++++++++++++++ .../baseclass/myaddress_widgets.py | 64 +++++ src/bitmessagekivy/kv/common_widgets.kv | 2 +- src/bitmessagekivy/kv/myaddress.kv | 2 +- src/bitmessagekivy/main.kv | 2 + src/bitmessagekivy/screens_data.json | 5 + 6 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 src/bitmessagekivy/baseclass/myaddress.py create mode 100644 src/bitmessagekivy/baseclass/myaddress_widgets.py diff --git a/src/bitmessagekivy/baseclass/myaddress.py b/src/bitmessagekivy/baseclass/myaddress.py new file mode 100644 index 00000000..5db5f7d6 --- /dev/null +++ b/src/bitmessagekivy/baseclass/myaddress.py @@ -0,0 +1,232 @@ +# pylint: disable=unused-argument, import-error, no-member, attribute-defined-outside-init +# pylint: disable=no-name-in-module, too-few-public-methods, too-many-instance-attributes + +""" +myaddress.py +============== +All generated addresses are managed in MyAddress +""" + +import os +from functools import partial + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen, ScreenManagerException +from kivy.app import App + +from kivymd.uix.list import ( + IRightBodyTouch, + TwoLineAvatarIconListItem, +) +from kivymd.uix.selectioncontrol import MDSwitch + +from pybitmessage.bmconfigparser import config + +from pybitmessage.bitmessagekivy.get_platform import platform +from pybitmessage.bitmessagekivy.baseclass.common import ( + avatar_image_first_letter, AvatarSampleWidget, ThemeClsColor, + toast, empty_screen_label, load_image_path +) + +from pybitmessage.bitmessagekivy.baseclass.popup import MyaddDetailPopup +from pybitmessage.bitmessagekivy.baseclass.myaddress_widgets import HelperMyAddress + + +class ToggleBtn(IRightBodyTouch, MDSwitch): + """ToggleBtn class for kivy UI""" + + +class CustomTwoLineAvatarIconListItem(TwoLineAvatarIconListItem): + """CustomTwoLineAvatarIconListItem class for kivy Ui""" + + +class MyAddress(Screen, HelperMyAddress): + """MyAddress screen class for kivy Ui""" + + address_label = StringProperty() + text_address = StringProperty() + addresses_list = ListProperty() + has_refreshed = True + is_add_created = False + label_str = "Yet no address is created by user!!!!!!!!!!!!!" + no_search_res_found = "No search result found" + min_scroll_y_limit = -0.0 + scroll_y_step = 0.06 + number_of_addresses = 20 + addresses_at_a_time = 15 + canvas_color_black = [0, 0, 0, 0] + canvas_color_gray = [0.5, 0.5, 0.5, 0.5] + is_android_width = .9 + other_platform_width = .6 + disabled_addr_width = .8 + other_platform_disabled_addr_width = .55 + max_scroll_limit = 1.0 + + def __init__(self, *args, **kwargs): + """Clock schdule for method Myaddress accounts""" + super(MyAddress, self).__init__(*args, **kwargs) + self.image_dir = load_image_path() + self.kivy_running_app = App.get_running_app() + self.kivy_state = self.kivy_running_app.kivy_state_obj + + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock schdule for method Myaddress accounts""" + self.addresses_list = config.addresses() + if self.kivy_state.searching_text: + self.ids.refresh_layout.scroll_y = self.max_scroll_limit + filtered_list = [ + x for x in config.addresses() + if self.filter_address(x) + ] + self.addresses_list = filtered_list + self.addresses_list = [obj for obj in reversed(self.addresses_list)] + self.ids.tag_label.text = '' + if self.addresses_list: + self.ids.tag_label.text = 'My Addresses' + self.has_refreshed = True + self.set_mdList(0, self.addresses_at_a_time) + self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + else: + self.ids.ml.add_widget(empty_screen_label(self.label_str, self.no_search_res_found)) + if not self.kivy_state.searching_text and not self.is_add_created: + try: + self.manager.current = 'login' + except ScreenManagerException: + pass + + def get_address_list(self, first_index, last_index, data): + """Getting address and append to the list""" + for address in self.addresses_list[first_index:last_index]: + data.append({ + 'text': config.get(address, 'label'), + 'secondary_text': address} + ) + return data + + def set_address_to_widget(self, item): + """Setting address to the widget""" + is_enable = config.getboolean(item['secondary_text'], 'enabled') + meny = CustomTwoLineAvatarIconListItem( + text=item['text'], secondary_text=item['secondary_text'], + theme_text_color='Custom' if is_enable else 'Primary', + text_color=ThemeClsColor,) + try: + meny.canvas.children[3].rgba = self.canvas_color_black if is_enable else self.canvas_color + except Exception: + pass + meny.add_widget(AvatarSampleWidget( + source=os.path.join( + self.image_dir, "text_images", "{}.png".format(avatar_image_first_letter( + item["text"].strip()))) + )) + meny.bind(on_press=partial( + self.myadd_detail, item['secondary_text'], item['text'])) + self.set_address_status(item, meny, is_enable) + + def set_address_status(self, item, meny, is_enable): + """Setting the identity status enable/disable on UI""" + if self.kivy_state.association == item['secondary_text'] and is_enable: + meny.add_widget(self.is_active_badge()) + else: + meny.add_widget(ToggleBtn(active=True if is_enable else False)) + self.ids.ml.add_widget(meny) + + def set_mdList(self, first_index, last_index): + """Creating the mdlist""" + data = [] + self.get_address_list(first_index, last_index, data) + for item in data: + self.set_address_to_widget(item) + + def check_scroll_y(self, instance, somethingelse): + """Load data on Scroll down""" + if self.ids.refresh_layout.scroll_y <= self.min_scroll_y_limit and self.has_refreshed: + self.ids.refresh_layout.scroll_y = self.scroll_y_step + my_addresses = len(self.ids.ml.children) + if my_addresses != len(self.addresses_list): + self.update_addressBook_on_scroll(my_addresses) + self.has_refreshed = ( + True if my_addresses != len(self.addresses_list) else False + ) + + def update_addressBook_on_scroll(self, my_addresses): + """Loads more data on scroll down""" + self.set_mdList(my_addresses, my_addresses + self.number_of_addresses) + + def myadd_detail(self, fromaddress, label, *args): + """Load myaddresses details""" + if config.get(fromaddress, 'enabled'): + obj = MyaddDetailPopup() + self.address_label = obj.address_label = label + self.text_address = obj.address = fromaddress + width = self.is_android_width if platform == 'android' else self.other_platform_width + self.myadddetail_popup = self.myaddress_detail_popup(obj, width) + self.myadddetail_popup.auto_dismiss = False + self.myadddetail_popup.open() + else: + width = self.disabled_addr_width if platform == 'android' else self.other_platform_disabled_addr_width + self.dialog_box = self.inactive_address_popup(width, self.callback_for_menu_items) + self.dialog_box.open() + + def callback_for_menu_items(self, text_item, *arg): + """Callback of inactive address alert box""" + self.dialog_box.dismiss() + toast(text_item) + + def refresh_callback(self, *args): + """Method updates the state of application, + While the spinner remains on the screen""" + def refresh_callback(interval): + """Method used for loading the myaddress screen data""" + self.kivy_state.searching_text = '' + self.ids.search_bar.ids.search_field.text = '' + self.has_refreshed = True + self.ids.ml.clear_widgets() + self.init_ui() + self.ids.refresh_layout.refresh_done() + Clock.schedule_once(self.address_permision_callback, 0) + Clock.schedule_once(refresh_callback, 1) + + @staticmethod + def filter_address(address): + """It will return True if search is matched""" + searched_text = App.get_running_app().kivy_state_obj.searching_text.lower() + return bool(config.search_addresses(address, searched_text)) + + def disable_address_ui(self, address, instance): + """This method is used to disable addresses from UI""" + config.disable_address(address) + instance.parent.parent.theme_text_color = 'Primary' + instance.parent.parent.canvas.children[3].rgba = MyAddress.canvas_color_gray + toast('Address disabled') + Clock.schedule_once(self.address_permision_callback, 0) + + def enable_address_ui(self, address, instance): + """This method is used to enable addresses from UI""" + config.enable_address(address) + instance.parent.parent.theme_text_color = 'Custom' + instance.parent.parent.canvas.children[3].rgba = MyAddress.canvas_color_black + toast('Address Enabled') + Clock.schedule_once(self.address_permision_callback, 0) + + def address_permision_callback(self, dt=0): + """callback for enable or disable addresses""" + addresses = [addr for addr in config.addresses() + if config.getboolean(str(addr), 'enabled')] + self.parent.parent.ids.content_drawer.ids.identity_dropdown.values = addresses + # self.parent.parent.ids.sc3.children[1].ids.btn.values = addresses + self.kivy_running_app.identity_list = addresses + + def toggleAction(self, instance): + """This method is used for enable or disable address""" + addr = instance.parent.parent.secondary_text + if instance.active: + self.enable_address_ui(addr, instance) + else: + self.disable_address_ui(addr, instance) diff --git a/src/bitmessagekivy/baseclass/myaddress_widgets.py b/src/bitmessagekivy/baseclass/myaddress_widgets.py new file mode 100644 index 00000000..23e2342f --- /dev/null +++ b/src/bitmessagekivy/baseclass/myaddress_widgets.py @@ -0,0 +1,64 @@ +# pylint: disable=too-many-arguments, no-name-in-module, import-error +# pylint: disable=too-few-public-methods, no-member, too-many-ancestors + +""" +MyAddress widgets are here. +""" + +from kivymd.uix.button import MDFlatButton +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.list import IRightBodyTouch + +from pybitmessage.bitmessagekivy.get_platform import platform +from pybitmessage.bitmessagekivy.baseclass.common import ThemeClsColor + + +class BadgeText(IRightBodyTouch, MDLabel): + """BadgeText class for kivy UI""" + + +class HelperMyAddress(object): + """Widget used in MyAddress are here""" + dialog_height = .25 + + @staticmethod + def is_active_badge(): + """This function show the 'active' label of active Address.""" + active_status = 'Active' + is_android_width = 90 + width = 50 + height = 60 + badge_obj = BadgeText( + size_hint=(None, None), + size=[is_android_width if platform == 'android' else width, height], + text=active_status, halign='center', + font_style='Body1', theme_text_color='Custom', + text_color=ThemeClsColor, font_size='13sp' + ) + return badge_obj + + @staticmethod + def myaddress_detail_popup(obj, width): + """This method show the details of address as popup opens.""" + show_myaddress_dialogue = MDDialog( + type="custom", + size_hint=(width, HelperMyAddress.dialog_height), + content_cls=obj, + ) + return show_myaddress_dialogue + + @staticmethod + def inactive_address_popup(width, callback_for_menu_items): + """This method shows the warning popup if the address is inactive""" + dialog_text = 'Address is not currently active. Please click on Toggle button to active it.' + dialog_box = MDDialog( + text=dialog_text, + size_hint=(width, HelperMyAddress.dialog_height), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ], + ) + return dialog_box diff --git a/src/bitmessagekivy/kv/common_widgets.kv b/src/bitmessagekivy/kv/common_widgets.kv index 2707c8d8..275bd12c 100644 --- a/src/bitmessagekivy/kv/common_widgets.kv +++ b/src/bitmessagekivy/kv/common_widgets.kv @@ -49,7 +49,7 @@ size_hint: None, None size: dp(36), dp(48) pos_hint: {'center_x': .95, 'center_y': .4} - on_active: app.root.ids.sc10.toggleAction(self) + on_active: app.root.ids.id_myaddress.toggleAction(self) : canvas: diff --git a/src/bitmessagekivy/kv/myaddress.kv b/src/bitmessagekivy/kv/myaddress.kv index 93496eeb..71dde54a 100644 --- a/src/bitmessagekivy/kv/myaddress.kv +++ b/src/bitmessagekivy/kv/myaddress.kv @@ -30,4 +30,4 @@ size_hint: None, None size: dp(36), dp(48) pos_hint: {'center_x': .95, 'center_y': .4} - on_active: app.root.ids.sc10.toggleAction(self) \ No newline at end of file + on_active: app.root.ids.id_myaddress.toggleAction(self) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index e92a2b23..797c5680 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -212,6 +212,8 @@ MDNavigationLayout: id:sc6 Random: id:id_newidentity + MyAddress: + id:id_myaddress MDNavigationDrawer: id: nav_drawer diff --git a/src/bitmessagekivy/screens_data.json b/src/bitmessagekivy/screens_data.json index 4628ef8e..33e13df6 100644 --- a/src/bitmessagekivy/screens_data.json +++ b/src/bitmessagekivy/screens_data.json @@ -2,5 +2,10 @@ "Login": { "kv_string": "login", "Import": "from pybitmessage.bitmessagekivy.baseclass.login import *" + }, + "My addresses": { + "kv_string": "myaddress", + "name_screen": "myaddress", + "Import": "from pybitmessage.bitmessagekivy.baseclass.myaddress import MyAddress" } }