From 2f6c017420b2bc19a70937a8040f9d5189b93c48 Mon Sep 17 00:00:00 2001 From: surbhicis Date: Wed, 27 Jul 2022 13:23:31 +0530 Subject: [PATCH] kivy mock integration into v0.6 --- src/bitmessagekivy/main.kv | 30 - src/bitmessagekivy/mpybit.py | 890 +++++++++++++++++- src/bitmessagekivy/screens_data.json | 78 ++ src/mock/baseclass/__init__.py | 0 src/mock/baseclass/addressbook.py | 147 +++ src/mock/baseclass/allmail.py | 153 +++ src/mock/baseclass/common.py | 125 +++ src/mock/baseclass/draft.py | 157 +++ src/mock/baseclass/inbox.py | 81 ++ src/mock/baseclass/login.py | 118 +++ src/mock/baseclass/maildetail.py | 238 +++++ src/mock/baseclass/msg_composer.py | 263 ++++++ src/mock/baseclass/myaddress.py | 239 +++++ src/mock/baseclass/network.py | 32 + src/mock/baseclass/payment.py | 44 + src/mock/baseclass/popup.py | 155 +++ src/mock/baseclass/qrcode.py | 27 + src/mock/baseclass/scan_screen.py | 104 ++ src/mock/baseclass/sent.py | 179 ++++ src/mock/baseclass/settings.py | 10 + src/mock/baseclass/trash.py | 79 ++ src/mock/bitmessagemock.py | 45 + src/mock/images | 1 + src/mock/keys.dat | 6 + src/mock/mockbitmessagekivy/__init__.py | 0 src/mock/mockbitmessagekivy/addresses.py | 1 + src/mock/mockbitmessagekivy/bmconfigparser.py | 280 ++++++ .../class_addressGenerator.py | 79 ++ src/mock/mockbitmessagekivy/get_platform.py | 48 + src/mock/mockbitmessagekivy/inventory.py | 15 + src/mock/mockbitmessagekivy/kivy_state.py | 72 ++ src/mock/mockbitmessagekivy/kv | 1 + src/mock/mockbitmessagekivy/main.kv | 422 +++++++++ .../mockbitmessagekivy/network/__init__.py | 0 .../mockbitmessagekivy/network/threads.py | 1 + src/mock/mockbitmessagekivy/queues.py | 55 ++ src/mock/mockbitmessagekivy/screens_data.json | 78 ++ src/mock/mockbitmessagekivy/shutdown.py | 24 + src/mock/mockbitmessagekivy/singleton.py | 1 + src/mock/mockbitmessagekivy/state.py | 133 +++ 40 files changed, 4364 insertions(+), 47 deletions(-) create mode 100644 src/bitmessagekivy/screens_data.json create mode 100644 src/mock/baseclass/__init__.py create mode 100644 src/mock/baseclass/addressbook.py create mode 100644 src/mock/baseclass/allmail.py create mode 100644 src/mock/baseclass/common.py create mode 100644 src/mock/baseclass/draft.py create mode 100644 src/mock/baseclass/inbox.py create mode 100644 src/mock/baseclass/login.py create mode 100644 src/mock/baseclass/maildetail.py create mode 100644 src/mock/baseclass/msg_composer.py create mode 100644 src/mock/baseclass/myaddress.py create mode 100644 src/mock/baseclass/network.py create mode 100644 src/mock/baseclass/payment.py create mode 100644 src/mock/baseclass/popup.py create mode 100644 src/mock/baseclass/qrcode.py create mode 100644 src/mock/baseclass/scan_screen.py create mode 100644 src/mock/baseclass/sent.py create mode 100644 src/mock/baseclass/settings.py create mode 100644 src/mock/baseclass/trash.py create mode 100644 src/mock/bitmessagemock.py create mode 120000 src/mock/images create mode 100644 src/mock/keys.dat create mode 100644 src/mock/mockbitmessagekivy/__init__.py create mode 120000 src/mock/mockbitmessagekivy/addresses.py create mode 100644 src/mock/mockbitmessagekivy/bmconfigparser.py create mode 100644 src/mock/mockbitmessagekivy/class_addressGenerator.py create mode 100644 src/mock/mockbitmessagekivy/get_platform.py create mode 100644 src/mock/mockbitmessagekivy/inventory.py create mode 100644 src/mock/mockbitmessagekivy/kivy_state.py create mode 120000 src/mock/mockbitmessagekivy/kv create mode 100644 src/mock/mockbitmessagekivy/main.kv create mode 100644 src/mock/mockbitmessagekivy/network/__init__.py create mode 120000 src/mock/mockbitmessagekivy/network/threads.py create mode 100644 src/mock/mockbitmessagekivy/queues.py create mode 100644 src/mock/mockbitmessagekivy/screens_data.json create mode 100644 src/mock/mockbitmessagekivy/shutdown.py create mode 120000 src/mock/mockbitmessagekivy/singleton.py create mode 100644 src/mock/mockbitmessagekivy/state.py diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index e9c89796..1c921a8d 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -216,38 +216,8 @@ MDNavigationLayout: id: scr_mngr size_hint_y: None height: root.height - toolbar.height - Inbox: - id:sc1 - Create: - id:sc3 - Sent: - id:sc4 - Trash: - id:sc5 - Login: - id:sc6 - Random: - id:sc7 - Setting: - id:sc9 - MyAddress: - id:sc10 - AddressBook: - id:sc11 - Payment: - id:sc12 NetworkStat: id:sc13 - MailDetail: - id:sc14 - ShowQRCode: - id:sc15 - Draft: - id:sc16 - Allmails: - id:sc17 - ScanScreen: - id:sc23 MDNavigationDrawer: id: nav_drawer diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index d4caa883..f826123a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,34 +1,890 @@ +# pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument +# pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation +# pylint: disable=protected-access +# pylint: disable=import-outside-toplevel,ungrouped-imports,wrong-import-order,unused-import,arguments-differ +# pylint: disable=invalid-name,unnecessary-comprehension,broad-except,simplifiable-if-expression,no-member +# pylint: disable=too-many-return-statements + """ - Dummy implementation for kivy Desktop and android(mobile) interface +Bitmessage android(mobile) interface """ -# pylint: disable=too-few-public-methods -from kivy.app import App -from kivy.uix.label import Label +from pybitmessage.bitmessagekivy.get_platform import platform +import os +from pybitmessage.bmconfigparser import BMConfigParser +from functools import partial +from kivymd.app import MDApp +from kivy.clock import Clock +from kivy.core.clipboard import Clipboard +from kivy.core.window import Window +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ( + BooleanProperty, + ListProperty, + NumericProperty, + ObjectProperty, + StringProperty +) +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.spinner import Spinner +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.button import MDRaisedButton +from kivymd.uix.list import ( + IRightBodyTouch, + OneLineAvatarIconListItem, + OneLineListItem +) -from pybitmessage.bitmessagekivy.kivy_state import KivyStateVariables +from kivy.uix.screenmanager import SlideTransition, FallOutTransition + +from pybitmessage import queues +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state +from kivymd.uix.bottomsheet import MDCustomBottomSheet + +from kivy.lang import Observable +import ast + +# from pybitmessage.bitmessagekivy.baseclass.common import toast -class NavigateApp(App): +if platform != "android": + from kivy.config import Config + Config.set("input", "mouse", "mouse, multitouch_on_demand") +elif platform == "android": + from jnius import autoclass, cast # noqa:F401 + from android.runnable import run_on_ui_thread + from android import python_act as PythonActivity + + Toast = autoclass("android.widget.Toast") + String = autoclass("java.lang.String") + CharSequence = autoclass("java.lang.CharSequence") + context = PythonActivity.mActivity + + @run_on_ui_thread + def show_toast(text, length): + """Its showing toast on screen""" + t = Toast.makeText(context, text, length) + t.show() + + +with open(os.path.join(os.path.dirname(__file__), "screens_data.json")) as read_file: + all_data = ast.literal_eval(read_file.read()) + data_screens = list(all_data.keys()) + +for modules in data_screens: + exec(all_data[modules]['Import']) + +# pylint: disable=too-few-public-methods,too-many-arguments,attribute-defined-outside-init + + +class Lang(Observable): + observers = [] + lang = None + + def __init__(self, defaultlang): + super(Lang, self).__init__() + self.ugettext = None + self.lang = defaultlang + self.switch_lang(self.lang) + + def _(self, text): + # return self.ugettext(text) + return text + + def fbind(self, name, func, args, **kwargs): + if name == "_": + self.observers.append((func, args, kwargs)) + else: + return super(Lang, self).fbind(name, func, **args, **kwargs) + + def funbind(self, name, func, args, **kwargs): + if name == "_": + key = (func, args, kwargs) + if key in self.observers: + self.observers.remove(key) + else: + return super(Lang, self).funbind(name, func, *args, **kwargs) + + def switch_lang(self, lang): + # get the right locales directory, and instanciate a gettext + # locale_dir = os.path.join(os.path.dirname(__file__), 'translations', 'mo', 'locales') + # locales = gettext.translation('langapp', locale_dir, languages=[lang]) + # self.ugettext = locales.gettext + + # update all the kv rules attached to this text + for func, largs in self.observers: + func(largs, None, None) + + +class NavigationItem(OneLineAvatarIconListItem): + """NavigationItem class for kivy Ui""" + badge_text = StringProperty() + icon = StringProperty() + active = BooleanProperty(False) + + def currentlyActive(self): + """Currenly active""" + for nav_obj in self.parent.children: + nav_obj.active = False + self.active = True + + +class NavigationDrawerDivider(OneLineListItem): + """ + A small full-width divider that can be placed + in the :class:`MDNavigationDrawer` + """ + + disabled = True + divider = None + _txt_top_pad = NumericProperty(dp(8)) + _txt_bot_pad = NumericProperty(dp(8)) + + def __init__(self, **kwargs): + # pylint: disable=bad-super-call + super(OneLineListItem, self).__init__(**kwargs) + self.height = dp(16) + + +class NavigationDrawerSubheader(OneLineListItem): + """ + A subheader for separating content in :class:`MDNavigationDrawer` + + Works well alongside :class:`NavigationDrawerDivider` + """ + + disabled = True + divider = None + theme_text_color = 'Secondary' + + +class ContentNavigationDrawer(BoxLayout): + """ContentNavigationDrawer class for kivy Uir""" + + def __init__(self, *args, **kwargs): + """Method used for contentNavigationDrawer""" + super(ContentNavigationDrawer, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for class contentNavigationDrawer""" + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + + def check_scroll_y(self, instance, somethingelse): + """show data on scroll down""" + if self.ids.btn.is_open: + self.ids.btn.is_open = False + + +class BadgeText(IRightBodyTouch, MDLabel): + """BadgeText class for kivy Ui""" + + +class CustomSpinner(Spinner): + """CustomSpinner class for kivy Ui""" + + def __init__(self, *args, **kwargs): + """Method used for setting size of spinner""" + super(CustomSpinner, self).__init__(*args, **kwargs) + self.dropdown_cls.max_height = Window.size[1] / 3 + self.values = list(addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true') + + +class NavigateApp(MDApp): """Navigation Layout of class""" + # pylint: disable=too-many-public-methods,inconsistent-return-statements - def __init__(self): - super(NavigateApp, self).__init__() - self.kivy_state_obj = KivyStateVariables() + # theme_cls = ThemeManager() + previous_date = ObjectProperty() + obj_1 = ObjectProperty() + variable_1 = ListProperty(addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true') + nav_drawer = ObjectProperty() + state.screen_density = Window.size + window_size = state.screen_density + app_platform = platform + title = "PyBitmessageChange" + imgstatus = False + count = 0 + manager_open = False + file_manager = None + state.imageDir = os.path.join('./images', 'kivy') + image_path = state.imageDir + tr = Lang("en") # for changing in franch replace en with fr def build(self): """Method builds the widget""" - # pylint: disable=no-self-use - return Label(text="Hello World !") + for kv in data_screens: + Builder.load_file( + os.path.join( + os.path.dirname(__file__), + 'kv', + # f'{all_data[kv]["kv_string"]}.kv', + '{0}.kv'.format(all_data[kv]["kv_string"]), + ) + ) + # self.obj_1 = AddressBook() + # kivysignalthread = UIkivySignaler() + # kivysignalthread.daemon = True + # kivysignalthread.start() + Window.bind(on_keyboard=self.on_key, on_request_close=self.on_request_close) + return Builder.load_file(os.path.join(os.path.dirname(__file__), 'main.kv')) - def clickNavDrawer(self): - """method for clicking navigation drawer""" - pass + def run(self): + """Running the widgets""" + super(NavigateApp, self).run() + @staticmethod + def showmeaddresses(name="text"): + """Show the addresses in spinner to make as dropdown""" + if name == "text": + if BMConfigParser().addresses(): + return BMConfigParser().addresses()[0][:16] + '..' + return "textdemo" + elif name == "values": + if BMConfigParser().addresses(): + return [address[:16] + '..' + for address in BMConfigParser().addresses()] + return "valuesdemo" + + def getCurrentAccountData(self, text): + """Get Current Address Account Data""" + if text != '': + if os.path.exists(state.imageDir + '/default_identicon/{}.png'.format(text)): + self.load_selected_Image(text) + else: + self.root.ids.content_drawer.ids.reset_image.opacity = 0 + self.root.ids.content_drawer.ids.reset_image.disabled = True + address_label = self.current_address_label( + BMConfigParser().get(text, 'label'), text) + self.root_window.children[1].ids.toolbar.title = address_label + state.association = text + state.searcing_text = '' + # LoadingPopup().open() + self.set_message_count() + for nav_obj in self.root.ids.content_drawer.children[ + 0].children[0].children[0].children: + nav_obj.active = True if nav_obj.text == 'Inbox' else False + self.fileManagerSetting() + Clock.schedule_once(self.setCurrentAccountData, 0.5) + + def fileManagerSetting(self): + """This method is for file manager setting""" + if not self.root.ids.content_drawer.ids.file_manager.opacity and \ + self.root.ids.content_drawer.ids.file_manager.disabled: + self.root.ids.content_drawer.ids.file_manager.opacity = 1 + self.root.ids.content_drawer.ids.file_manager.disabled = False + + def setCurrentAccountData(self, dt=0): + """This method set the current accout data on all the screens""" + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) + + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.children[2].children[2].ids.search_field.text = '' + self.root.ids.sc4.loadSent(state.association) + + self.root.ids.sc16.clear_widgets() + self.root.ids.sc16.add_widget(Draft()) + + self.root.ids.sc5.clear_widgets() + self.root.ids.sc5.add_widget(Trash()) + + self.root.ids.sc17.clear_widgets() + self.root.ids.sc17.add_widget(Allmails()) + + self.root.ids.sc10.ids.ml.clear_widgets() + self.root.ids.sc10.init_ui() + + self.root.ids.scr_mngr.current = 'inbox' + + @staticmethod + def getCurrentAccount(): + """It uses to get current account label""" + if state.association: + return state.association + return "Bitmessage Login" + + # @staticmethod def addingtoaddressbook(self): - """method for clicking address book popup""" + """Adding to address Book""" + width = .85 if platform == 'android' else .8 + self.add_popup = MDDialog( + title='Add contact\'s', + type="custom", + size_hint=(width, .23), + content_cls=GrashofPopup(), + buttons=[ + MDRaisedButton( + text="Save", + on_release=self.savecontact, + ), + MDRaisedButton( + text="Cancel", + on_release=self.close_pop, + ), + MDRaisedButton( + text="Scan QR code", + on_release=self.scan_qr_code, + ), + ], + ) + # self.add_popup.set_normal_height() + self.add_popup.auto_dismiss = False + self.add_popup.open() + # p.open() + + def scan_qr_code(self, instance): + """this method is used for showing QR code scanner""" + if self.is_camara_attached(): + self.add_popup.dismiss() + self.root.ids.sc23.get_screen(self.root.ids.scr_mngr.current, self.add_popup) + self.root.ids.scr_mngr.current = 'scanscreen' + else: + altet_txt = ( + 'Currently this feature is not avaialbe!' if platform == 'android' else 'Camera is not available!') + self.add_popup.dismiss() + toast(altet_txt) + + def is_camara_attached(self): + """This method is for checking is camera available or not""" + self.root.ids.sc23.check_camera() + is_available = self.root.ids.sc23.camera_avaialbe + return is_available + + def savecontact(self, instance): + """Method is used for saving contacts""" + pupup_obj = self.add_popup.content_cls + label = pupup_obj.ids.label.text.strip() + address = pupup_obj.ids.address.text.strip() + if label == '' and address == '': + pupup_obj.ids.label.focus = True + pupup_obj.ids.address.focus = True + elif address == '': + pupup_obj.ids.address.focus = True + elif label == '': + pupup_obj.ids.label.focus = True + else: + pupup_obj.ids.address.focus = True + # pupup_obj.ids.label.focus = True + + stored_address = [addr[1] for addr in []] + stored_labels = [labels[0] for labels in []] + if label and address and address not in stored_address \ + and label not in stored_labels and pupup_obj.valid: + queues.UISignalQueue.put(('rerenderAddressBook', '')) + self.add_popup.dismiss() + try: + rootIds = self.root.ids + except: + rootIds = state.kivyapp.root.ids + rootIds.sc11.ids.ml.clear_widgets() + rootIds.sc11.loadAddresslist(None, 'All', '') + rootIds.scr_mngr.current = 'addressbook' + toast('Saved') + + def close_pop(self, instance): + """Pop is Canceled""" + self.add_popup.dismiss() + toast('Canceled') + + def getDefaultAccData(self, instance): + """Getting Default Account Data""" + if self.variable_1: + state.association = first_addr = self.variable_1[0] + return first_addr + return 'Select Address' + + def get_default_logo(self, instance): + """Getting default logo image""" + if self.variable_1: + first_addr = self.variable_1[0] + if BMConfigParser().get(str(first_addr), 'enabled') == 'true': + if os.path.exists(state.imageDir + '/default_identicon/{}.png'.format(first_addr)): + return state.imageDir + '/default_identicon/{}.png'.format(first_addr) + else: + return + return state.imageDir + '/drawer_logo1.png' + + @staticmethod + def addressexist(): + """Checking address existence""" + if BMConfigParser().addresses(): + return True + return False + + def on_key(self, window, key, *args): + # pylint: disable=inconsistent-return-statements, too-many-branches + """Method is used for going on previous screen""" + if key == 27: + if state.in_search_mode and self.root.ids.scr_mngr.current not in [ + "mailDetail", "create"]: + self.closeSearchScreen() + elif self.root.ids.scr_mngr.current == "mailDetail": + self.root.ids.scr_mngr.current = 'sent'\ + if state.detailPageType == 'sent' else 'inbox' \ + if state.detailPageType == 'inbox' else 'draft' + self.back_press() + if state.in_search_mode and state.searcing_text: + toolbar_obj = self.root.ids.toolbar + toolbar_obj.left_action_items = [ + ['arrow-left', lambda x: self.closeSearchScreen()]] + toolbar_obj.right_action_items = [] + self.root.ids.toolbar.title = '' + elif self.root.ids.scr_mngr.current == "create": + self.save_draft() + self.set_common_header() + state.in_composer = False + self.root.ids.scr_mngr.current = 'inbox' + elif self.root.ids.scr_mngr.current == "showqrcode": + self.set_common_header() + self.root.ids.scr_mngr.current = 'myaddress' + elif self.root.ids.scr_mngr.current == "random": + self.root.ids.scr_mngr.current = 'login' + elif self.root.ids.scr_mngr.current == 'pay-options': + self.set_common_header() + self.root.ids.scr_mngr.current = 'payment' + elif self.root.ids.scr_mngr.current == 'chroom': + if state.association: + address_label = self.current_address_label( + BMConfigParser().get( + state.association, 'label'), state.association) + self.root.ids.toolbar.title = address_label + self.set_common_header() + self.root.ids.scr_mngr.transition = FallOutTransition() + self.root.ids.scr_mngr.current = 'chlist' + self.root.ids.scr_mngr.transition = SlideTransition() + else: + if state.kivyapp.variable_1: + self.root.ids.scr_mngr.current = 'inbox' + self.root.ids.scr_mngr.transition.direction = 'right' + self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) + return True + elif key == 13 and state.searcing_text and not state.in_composer: + if state.search_screen == 'inbox': + self.root.ids.sc1.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + elif state.search_screen == 'addressbook': + self.root.ids.sc11.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + elif state.search_screen == 'myaddress': + self.loadMyAddressScreen(True) + Clock.schedule_once(self.search_callback, 0.5) + elif state.search_screen == 'sent': + self.root.ids.sc4.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + + def search_callback(self, dt=0): + """Show data after loader is loaded""" + if state.search_screen == 'inbox': + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) + self.root.ids.sc1.children[1].active = False + elif state.search_screen == 'addressbook': + self.root.ids.sc11.ids.ml.clear_widgets() + self.root.ids.sc11.loadAddresslist(None, 'All', '') + self.root.ids.sc11.children[1].active = False + elif state.search_screen == 'myaddress': + self.root.ids.sc10.ids.ml.clear_widgets() + self.root.ids.sc10.init_ui() + self.loadMyAddressScreen(False) + else: + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.loadSent(state.association) + self.root.ids.sc4.children[1].active = False + self.root.ids.scr_mngr.current = state.search_screen + + def loadMyAddressScreen(self, action): + """loadMyAddressScreen method spin the loader""" + if len(self.root.ids.sc10.children) <= 2: + self.root.ids.sc10.children[0].active = action + else: + self.root.ids.sc10.children[1].active = action + + def save_draft(self): + """Saving drafts messages""" + composer_objs = self.root + from_addr = str(self.root.ids.sc3.children[1].ids.ti.text) + # to_addr = str(self.root.ids.sc3.children[1].ids.txt_input.text) + if from_addr and state.detailPageType != 'draft' \ + and not state.in_sent_method: + Draft().draft_msg(composer_objs) + return + + def reset(self, *args): + """Set transition direction""" + self.root.ids.scr_mngr.transition.direction = 'left' + self.root.ids.scr_mngr.transition.unbind(on_complete=self.reset) + + @staticmethod + def status_dispatching(data): + """Dispatching Status acknowledgment""" + ackData, message = data + if state.ackdata == ackData: + state.status.status = message + + def clear_composer(self): + """If slow down, the new composer edit screen""" + self.set_navbar_for_composer() + composer_obj = self.root.ids.sc3.children[1].ids + composer_obj.ti.text = '' + composer_obj.btn.text = 'Select' + composer_obj.txt_input.text = '' + composer_obj.subject.text = '' + composer_obj.body.text = '' + state.in_composer = True + state.in_sent_method = False + + def set_navbar_for_composer(self): + """Clearing toolbar data when composer open""" + self.root.ids.toolbar.left_action_items = [ + ['arrow-left', lambda x: self.back_press()]] + self.root.ids.toolbar.right_action_items = [ + ['refresh', + lambda x: self.root.ids.sc3.children[1].reset_composer()], + ['send', + lambda x: self.root.ids.sc3.children[1].send(self)]] + + def set_toolbar_for_QrCode(self): + """This method is use for setting Qr code toolbar.""" + self.root.ids.toolbar.left_action_items = [ + ['arrow-left', lambda x: self.back_press()]] + self.root.ids.toolbar.right_action_items = [] + + def set_common_header(self): + """Common header for all window""" + self.root.ids.toolbar.right_action_items = [ + ['account-plus', lambda x: self.addingtoaddressbook()]] + # self.root.ids.toolbar.left_action_items = [ + # ['menu', lambda x: self.root.toggle_nav_drawer()]] + self.root.ids.toolbar.left_action_items = [ + ['menu', lambda x: self.root.ids.nav_drawer.set_state("toggle")]] + return + + def back_press(self): + """Method for, reverting composer to previous page""" + if self.root.ids.scr_mngr.current == 'create': + self.save_draft() + if self.root.ids.scr_mngr.current == \ + 'mailDetail' and state.in_search_mode: + toolbar_obj = self.root.ids.toolbar + toolbar_obj.left_action_items = [ + ['arrow-left', lambda x: self.closeSearchScreen()]] + toolbar_obj.right_action_items = [] + self.root.ids.toolbar.title = '' + else: + self.set_common_header() + if self.root.ids.scr_mngr.current == 'chroom' and state.association: + self.root.ids.scr_mngr.transition = FallOutTransition() + address_label = self.current_address_label( + BMConfigParser().get( + state.association, 'label'), state.association) + self.root.ids.toolbar.title = address_label + self.root.ids.scr_mngr.current = 'inbox' \ + if state.in_composer else 'allmails'\ + if state.is_allmail else state.detailPageType\ + if state.detailPageType else 'myaddress'\ + if self.root.ids.scr_mngr.current == 'showqrcode' else 'payment'\ + if self.root.ids.scr_mngr.current == 'pay-options' else 'chlist'\ + if self.root.ids.scr_mngr.current == 'chroom' else 'inbox' + if self.root.ids.scr_mngr.current == 'chlist': + self.root.ids.scr_mngr.transition = SlideTransition() + self.root.ids.scr_mngr.transition.direction = 'right' + self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) + if state.is_allmail or state.detailPageType == 'draft': + state.is_allmail = False + state.detailPageType = '' + state.in_composer = False + + @staticmethod + def get_inbox_count(): + """Getting inbox count""" pass + @staticmethod + def get_sent_count(): + """Getting sent count""" + pass -if __name__ == '__main__': - NavigateApp().run() + def set_message_count(self): + """Setting message count""" + pass + + def on_start(self): + """Setting message count""" + self.set_message_count() + + @staticmethod + def current_address_label(current_add_label=None, current_addr=None): + """Getting current address labels""" + addresses = [addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true'] + if addresses: + if current_add_label: + first_name = current_add_label + addr = current_addr + else: + addr = addresses[0] + first_name = BMConfigParser().get(addr, 'label') + if BMConfigParser().get(addr, 'enabled') != 'true': + return '' + f_name = first_name.split() + label = f_name[0][:14].capitalize() + '...' if len( + f_name[0]) > 15 else f_name[0].capitalize() + address = ' (' + addr + ')' + return label + address + return '' + + def searchQuery(self, instance): + """Showing searched mails""" + state.search_screen = self.root.ids.scr_mngr.current + state.searcing_text = str(instance.text).strip() + if instance.focus and state.searcing_text: + toolbar_obj = self.root.ids.toolbar + toolbar_obj.left_action_items = [ + ['arrow-left', lambda x: self.closeSearchScreen()]] + toolbar_obj.right_action_items = [] + self.root.ids.toolbar.title = '' + state.in_search_mode = True + + def closeSearchScreen(self): + """Function for close search screen""" + self.set_common_header() + if state.association: + address_label = self.current_address_label( + BMConfigParser().get( + state.association, 'label'), state.association) + self.root.ids.toolbar.title = address_label + state.searcing_text = '' + self.refreshScreen() + state.in_search_mode = False + + def refreshScreen(self): + """Method show search button only on inbox or sent screen""" + # pylint: disable=unused-variable + state.searcing_text = '' + if state.search_screen == 'inbox': + self.root.ids.sc1.ids.inbox_search.ids.search_field.text = '' + # try: + # self.root.ids.sc1.children[ + # 3].children[2].ids.search_field.text = '' + # except Exception: + # self.root.ids.sc1.children[ + # 2].children[2].ids.search_field.text = '' + self.root.ids.sc1.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + elif state.search_screen == 'addressbook': + self.root.ids.sc11.ids.address_search.ids.search_field.text = '' + # self.root.ids.sc11.children[ + # 2].children[2].ids.search_field.text = '' + self.root.ids.sc11.children[ + 1].active = True + Clock.schedule_once(self.search_callback, 0.5) + elif state.search_screen == 'myaddress': + self.root.ids.sc10.ids.search_bar.ids.search_field.text = '' + # try: + # self.root.ids.sc10.children[ + # 1].children[2].ids.search_field.text = '' + # except Exception: + # self.root.ids.sc10.children[ + # 2].children[2].ids.search_field.text = '' + self.loadMyAddressScreen(True) + Clock.schedule_once(self.search_callback, 0.5) + else: + self.root.ids.sc4.ids.sent_search.ids.search_field.text = '' + # self.root.ids.sc4.children[ + # 2].children[2].ids.search_field.text = '' + self.root.ids.sc4.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + return + + def set_mail_detail_header(self): + """Setting the details of the page""" + if state.association and state.in_search_mode: + address_label = self.current_address_label( + BMConfigParser().get( + state.association, 'label'), state.association) + self.root.ids.toolbar.title = address_label + toolbar_obj = self.root.ids.toolbar + toolbar_obj.left_action_items = [ + ['arrow-left', lambda x: self.back_press()]] + delete_btn = ['delete-forever', + lambda x: self.root.ids.sc14.delete_mail()] + dynamic_list = [] + if state.detailPageType == 'inbox': + dynamic_list = [ + ['reply', lambda x: self.root.ids.sc14.inbox_reply()], + delete_btn] + elif state.detailPageType == 'sent': + dynamic_list = [delete_btn] + elif state.detailPageType == 'draft': + dynamic_list = [ + ['pencil', lambda x: self.root.ids.sc14.write_msg(self)], + delete_btn] + toolbar_obj.right_action_items = dynamic_list + + def load_screen(self, instance): + """This method is used for loading screen on every click""" + if instance.text == 'Inbox': + self.root.ids.scr_mngr.current = 'inbox' + self.root.ids.sc1.children[1].active = True + elif instance.text == 'All Mails': + self.root.ids.scr_mngr.current = 'allmails' + try: + self.root.ids.sc17.children[1].active = True + except Exception: + self.root.ids.sc17.children[0].children[1].active = True + elif instance.text == 'Trash': + self.root.ids.scr_mngr.current = 'trash' + try: + self.root.ids.sc5.children[1].active = True + except: + self.root.ids.sc5.children[0].children[1].active = True + Clock.schedule_once(partial(self.load_screen_callback, instance), 1) + + def load_screen_callback(self, instance, dt=0): + """This method is rotating loader for few seconds""" + if instance.text == 'Inbox': + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) + self.root.ids.sc1.children[1].active = False + elif instance.text == 'All Mails': + self.root.ids.sc17.clear_widgets() + self.root.ids.sc17.add_widget(Allmails()) + try: + self.root.ids.sc17.children[1].active = False + except Exception: + self.root.ids.sc17.children[0].children[1].active = False + elif instance.text == 'Trash': + # self.root.ids.sc5.ids.ml.clear_widgets() + # self.root.ids.sc5.init_ui(0) + self.root.ids.sc5.clear_widgets() + self.root.ids.sc5.add_widget(Trash()) + try: + self.root.ids.sc5.children[1].active = False + except: + self.root.ids.sc5.children[0].children[1].active = False + + def on_request_close(self, *args): # pylint: disable=no-self-use + """This method is for app closing request""" + AppClosingPopup().open() # noqa:F821 + return True + + def file_manager_open(self): + """This method open the file manager of local system""" + from kivymd.uix.filemanager import MDFileManager + + if not self.file_manager: + self.file_manager = MDFileManager( + exit_manager=self.exit_manager, + select_path=self.select_path, + ext=['.png', '.jpg'] + ) + self.file_manager.previous = False + self.file_manager.current_path = '/' + if platform == 'android': + from android.permissions import request_permissions, Permission, check_permission + if check_permission(Permission.WRITE_EXTERNAL_STORAGE) and \ + check_permission(Permission.READ_EXTERNAL_STORAGE): + self.file_manager.show(os.getenv('EXTERNAL_STORAGE')) + self.manager_open = True + else: + request_permissions([Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE]) + else: + self.file_manager.show(os.environ["HOME"]) + self.manager_open = True + + def select_path(self, path): + """This method is used to save the select image""" + try: + from PIL import Image as PilImage + newImg = PilImage.open(path).resize((300, 300)) + if platform == 'android': + android_path = os.path.join( + os.environ['ANDROID_PRIVATE'] + '/app' + '/images' + '/kivy/') + if not os.path.exists(android_path + '/default_identicon/'): + os.makedirs(android_path + '/default_identicon/') + newImg.save('{1}/default_identicon/{0}.png'.format( + state.association, android_path)) + else: + if not os.path.exists(state.imageDir + '/default_identicon/'): + os.makedirs(state.imageDir + '/default_identicon/') + newImg.save(state.imageDir + '/default_identicon/{0}.png'.format(state.association)) + self.load_selected_Image(state.association) + toast('Image changed') + except Exception: + toast('Exit') + self.exit_manager() + + def exit_manager(self, *args): + """Called when the user reaches the root of the directory tree.""" + self.manager_open = False + self.file_manager.close() + + def load_selected_Image(self, curerentAddr): + """This method load the selected image on screen""" + top_box_obj = self.root.ids.content_drawer.ids.top_box.children[0] + # spinner_img_obj = self.root.ids.content_drawer.ids.btn.children[1] + # spinner_img_obj.source = top_box_obj.source ='./images/default_identicon/{0}.png'.format(curerentAddr) + top_box_obj.source = state.imageDir + '/default_identicon/{0}.png'.format(curerentAddr) + self.root.ids.content_drawer.ids.reset_image.opacity = 1 + self.root.ids.content_drawer.ids.reset_image.disabled = False + top_box_obj.reload() + # spinner_img_obj.reload() + + def rest_default_avatar_img(self): + """set default avatar generated image""" + img_path = state.imageDir + '/default_identicon/{}.png'.format(state.association) + try: + if os.path.exists(img_path): + os.remove(img_path) + self.root.ids.content_drawer.ids.reset_image.opacity = 0 + self.root.ids.content_drawer.ids.reset_image.disabled = True + except: + pass + toast('Avatar reset') + + def copy_composer_text(self, text): # pylint: disable=no-self-use + """Copy the data from mail detail page""" + Clipboard.copy(text) + toast('Copied') + + def reset_login_screen(self): + """This method is used for clearing random screen""" + if self.root.ids.sc7.ids.add_random_bx.children: + self.root.ids.sc7.ids.add_random_bx.clear_widgets() + + def open_payment_layout(self, sku): + """It basically open up a payment layout for kivy Ui""" + pml = PaymentMethodLayout() + self.product_id = sku + self.custom_sheet = MDCustomBottomSheet(screen=pml) + self.custom_sheet.open() + + def initiate_purchase(self, method_name): + """initiate_purchase module""" + print("Purchasing {} through {}".format(self.product_id, method_name)) + + def _after_scan(self, text): + if self.root.ids.sc23.previous_open_screen == 'composer': + self.root.ids.sc3.children[1].ids.txt_input.text = text + self.root.ids.scr_mngr.current = 'create' + elif self.root.ids.sc23.previous_open_screen: + back_screen = self.root.ids.sc23.previous_open_screen + self.root.ids.scr_mngr.current = 'inbox' if back_screen == 'scanscreen' else back_screen + add_obj = self.root.ids.sc23.pop_up_instance + add_obj.content_cls.ids.address.text = text + Clock.schedule_once(partial(self.open_popup, add_obj), .5) + + @staticmethod + def open_popup(instance, dt): + """This method is used for opening popup""" + instance.open() + + +class PaymentMethodLayout(BoxLayout): + """PaymentMethodLayout class for kivy Ui""" diff --git a/src/bitmessagekivy/screens_data.json b/src/bitmessagekivy/screens_data.json new file mode 100644 index 00000000..e9bba36e --- /dev/null +++ b/src/bitmessagekivy/screens_data.json @@ -0,0 +1,78 @@ +{ + "Inbox": { + "kv_string": "inbox", + "name_screen": "inbox", + "Import": "from baseclass.inbox import Inbox", + }, + "Sent": { + "kv_string": "sent", + "name_screen": "sent", + "Import": "from baseclass.sent import Sent", + }, + "Draft": { + "kv_string": "draft", + "name_screen": "draft", + "Import": "from baseclass.draft import Draft", + }, + "Trash": { + "kv_string": "trash", + "name_screen": "trash", + "Import": "from baseclass.trash import Trash", + }, + "All Mails": { + "kv_string": "allmails", + "name_screen": "allmails", + "Import": "from baseclass.allmail import Allmails", + }, + "Address Book": { + "kv_string": "addressbook", + "name_screen": "addressbook", + "Import": "from baseclass.addressbook import AddressBook", + }, + "Settings": { + "kv_string": "settings", + "name_screen": "set", + "Import": "from baseclass.settings import Setting", + }, + "Payment": { + "kv_string": "payment", + "name_screen": "payment", + "Import": "from baseclass.payment import Payment", + }, + "Network status": { + "kv_string": "network", + "name_screen": "networkstat", + "Import": "from baseclass.network import NetworkStat", + }, + "My addresses": { + "kv_string": "myaddress", + "name_screen": "myaddress", + "Import": "from baseclass.myaddress import MyAddress", + }, + "MailDetail": { + "kv_string": "maildetail", + "name_screen": "mailDetail", + "Import": "from baseclass.maildetail import MailDetail", + }, + "Create": { + "kv_string": "msg_composer", + "name_screen": "create", + "Import": "from baseclass.msg_composer import Create", + }, + "Login": { + "kv_string": "login", + "Import": "from baseclass.login import *", + }, + "Scanner": { + "kv_string": "scan_screen", + "Import": "from baseclass.scan_screen import ScanScreen", + }, + "Popups": { + "kv_string": "popup", + "Import": "from baseclass.popup import *", + }, + "Qrcode": { + "kv_string": "qrcode", + "Import": "from baseclass.qrcode import ShowQRCode", + }, +} diff --git a/src/mock/baseclass/__init__.py b/src/mock/baseclass/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/mock/baseclass/addressbook.py b/src/mock/baseclass/addressbook.py new file mode 100644 index 00000000..17671f40 --- /dev/null +++ b/src/mock/baseclass/addressbook.py @@ -0,0 +1,147 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel, too-many-function-args + +""" +Kivy Addressbook Screen +""" + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from baseclass.common import toast +from baseclass.popup import AddbookDetailPopup + +from kivymd.uix.button import MDRaisedButton +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel + +from pybitmessage.bitmessagekivy.get_platform import platform +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class AddressBook(Screen): + """AddressBook Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + address_label = StringProperty() + address = StringProperty() + + def __init__(self, *args, **kwargs): + """Getting AddressBook Details""" + super(AddressBook, self).__init__(*args, **kwargs) + self.addbook_popup = None + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method AddressBook""" + self.loadAddresslist(None, 'All', '') + print(dt) + + def loadAddresslist(self): + """Clock Schdule for method AddressBook""" + if kivy_state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 + self.ids.tag_label.text = '' + if self.queryreturn: + pass + else: + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No contact found!" if kivy_state.searcing_text + else "No contact found yet...... ", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def check_scroll_y(self): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + + @staticmethod + def refreshes(*args): + """Refresh the Widget""" + # state.navinstance.ids.sc11.ids.ml.clear_widgets() + # state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') + + # @staticmethod + def addBook_detail(self, address, label, instance): + """Addressbook details""" + if instance.state == 'closed': + instance.ids.delete_msg.disabled = True + if instance.open_progress == 0.0: + obj = AddbookDetailPopup() + self.address_label = obj.address_label = label + self.address = obj.address = address + width = .9 if platform == 'android' else .8 + self.addbook_popup = MDDialog( + type="custom", + size_hint=(width, .25), + content_cls=obj, + buttons=[ + MDRaisedButton( + text="Send message to", + on_release=self.send_message_to, + ), + MDRaisedButton( + text="Save", + on_release=self.update_addbook_label, + ), + MDRaisedButton( + text="Cancel", + on_release=self.close_pop, + ), + ], + ) + # self.addbook_popup.set_normal_height() + self.addbook_popup.auto_dismiss = False + self.addbook_popup.open() + else: + instance.ids.delete_msg.disabled = False + + def delete_address(self, instance): + """Delete inbox mail from inbox listing""" + self.ids.ml.remove_widget(instance.parent.parent) + # if len(self.ids.ml.children) == 0: + if self.ids.ml.children is not None: + self.ids.tag_label.text = '' + toast('Address Deleted') + + def close_pop(self): + """Pop is Canceled""" + self.addbook_popup.dismiss() + toast('Canceled') + + def update_addbook_label(self): + """Updating the label of address book address""" + address_list = [] + stored_labels = [labels[0] for labels in address_list] + add_dict = dict(address_list) + label = str(self.addbook_popup.content_cls.ids.add_label.text) + if label in stored_labels and self.address == add_dict[label]: + stored_labels.remove(label) + if label and label not in stored_labels: + state.kivyapp.root.ids.sc11.ids.ml.clear_widgets() + state.kivyapp.root.ids.sc11.loadAddresslist(None, 'All', '') + self.addbook_popup.dismiss() + toast('Saved') + + def send_message_to(self): + """Method used to fill to_address of composer autofield""" + state.kivyapp.set_navbar_for_composer() + window_obj = state.kivyapp.root.ids + window_obj.sc3.children[1].ids.txt_input.text = self.address + window_obj.sc3.children[1].ids.ti.text = '' + window_obj.sc3.children[1].ids.btn.text = 'Select' + window_obj.sc3.children[1].ids.subject.text = '' + window_obj.sc3.children[1].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.addbook_popup.dismiss() diff --git a/src/mock/baseclass/allmail.py b/src/mock/baseclass/allmail.py new file mode 100644 index 00000000..96438e56 --- /dev/null +++ b/src/mock/baseclass/allmail.py @@ -0,0 +1,153 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel + +""" +Kivy All mail screen +""" + +from functools import partial + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from baseclass.common import ( + showLimitedCnt, toast, ThemeClsColor, + avatarImageFirstLetter, CutsomSwipeToDeleteItem, + ShowTimeHistoy +) + +from kivymd.uix.label import MDLabel + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class Allmails(Screen): + """Allmails Screen for kivy Ui""" + + data = ListProperty() + has_refreshed = True + all_mails = ListProperty() + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Method Parsing the address""" + super(Allmails, self).__init__(*args, **kwargs) + if kivy_state.association == '': + if state.kivyapp.variable_1: + kivy_state.association = state.kivyapp.variable_1[0] + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method all mails""" + self.loadMessagelist() + print(dt) + + def loadMessagelist(self): + """Load Inbox, Sent anf Draft list of messages""" + self.account = kivy_state.association + self.ids.tag_label.text = '' + if self.all_mails: + pass + else: + self.set_AllmailCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def set_AllmailCnt(self, Count): # pylint: disable=no-self-use + """This method is used to set allmails message count""" + allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt + allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdlist(self): + """This method is used to create mdList for allmaills""" + data_exist = len(self.ids.ml.children) + for item in self.all_mails: + body = item[3].decode() if isinstance(item[3], bytes) else item[3] + subject = item[2].decode() if isinstance(item[2], bytes) else item[2] + message_row = CutsomSwipeToDeleteItem( + text=item[1], + ) + + listItem = message_row.ids.content + secondary_text = (subject[:50] + '........' if len( + subject) >= 50 else ( + subject + ',' + body)[0:50] + '........').replace('\t', '').replace(' ', '') + listItem.secondary_text = secondary_text + listItem.theme_text_color = "Custom" + listItem.text_color = ThemeClsColor + # pylint: disable=consider-using-f-string + img_latter = kivy_state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(body.strip())) + message_row.ids.avater_img.source = img_latter + listItem.bind(on_release=partial( + self.mail_detail, item[5], item[4], message_row)) + message_row.ids.time_tag.text = str(ShowTimeHistoy(item[7])) + message_row.ids.chip_tag.text = item[4] + message_row.ids.delete_msg.bind(on_press=partial( + self.swipe_delete, item[5], item[4])) + self.ids.ml.add_widget(message_row) + updated_data = len(self.ids.ml.children) + # pylint: disable=simplifiable-if-expression + self.has_refreshed = True if data_exist != updated_data else False + + def check_scroll_y(self): + """Scroll fixed length""" + if self.ids.scroll_y.scroll_y <= -0.00 and self.has_refreshed: + self.ids.scroll_y.scroll_y = .06 + + def mail_detail(self, unique_id, folder, instance): + """Load sent and inbox mail details""" + if instance.state == 'closed': + instance.ids.delete_msg.disabled = True + if instance.open_progress == 0.0: + kivy_state.detailPageType = folder + kivy_state.is_allmail = True + kivy_state.mail_id = unique_id + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[11].clear_widgets() + src_mng_obj.current = 'mailDetail' + else: + instance.ids.delete_msg.disabled = False + + def swipe_delete(self, folder, instance): + """Delete inbox mail from all mail listing""" + self.ids.ml.remove_widget(instance.parent.parent) + try: + msg_count_objs = self.parent.parent.ids.content_drawer.ids + nav_lay_obj = self.parent.parent.ids + except Exception: + msg_count_objs = self.parent.parent.parent.ids.content_drawer.ids + nav_lay_obj = self.parent.parent.parent.ids + if folder == 'inbox': + msg_count_objs.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.inbox_count) - 1) + kivy_state.inbox_count = str(int(kivy_state.inbox_count) - 1) + nav_lay_obj.sc1.ids.ml.clear_widgets() + nav_lay_obj.sc1.loadMessagelist(kivy_state.association) + else: + msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.sent_count) - 1) + kivy_state.sent_count = str(int(kivy_state.sent_count) - 1) + nav_lay_obj.sc4.ids.ml.clear_widgets() + nav_lay_obj.sc4.loadSent(kivy_state.association) + if folder != 'inbox': + msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.all_count) - 1) + kivy_state.all_count = str(int(kivy_state.all_count) - 1) + msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.trash_count) + 1) + kivy_state.trash_count = str(int(kivy_state.trash_count) + 1) + if int(kivy_state.all_count) <= 0: + self.ids.tag_label.text = '' + nav_lay_obj.sc17.remove_widget(instance.parent.parent) + toast('Deleted') diff --git a/src/mock/baseclass/common.py b/src/mock/baseclass/common.py new file mode 100644 index 00000000..6c6754cb --- /dev/null +++ b/src/mock/baseclass/common.py @@ -0,0 +1,125 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel, abstract-method + +""" +Kivy Common UI Widget +""" + +from datetime import datetime + +from kivy.core.window import Window +from kivy.metrics import dp +from kivy.properties import ( + NumericProperty, + StringProperty +) +from kivy.uix.image import Image + +from kivymd.uix.list import ( + ILeftBody, + IRightBodyTouch, +) +from kivymd.uix.label import MDLabel +from kivymd.toast import kivytoast +from kivymd.uix.card import MDCardSwipe +from kivymd.uix.chip import MDChip + +# from pybitmessage.get_platform import platform +platform = "linux" + + +ThemeClsColor = [0.12, 0.58, 0.95, 1] + + +data_screens = { + "MailDetail": { + "kv_string": "maildetail", + "Factory": "MailDetail()", + "name_screen": "mailDetail", + "object": 0, + "Import": "from baseclass.maildetail import MailDetail", + }, +} + + +def chipTag(text): + """This method is used for showing chip tag""" + obj = MDChip() + # obj.size_hint = (None, None) + obj.size_hint = (0.16 if platform == "android" else 0.08, None) + obj.text = text + obj.icon = "" + obj.pos_hint = { + "center_x": 0.91 if platform == "android" else 0.94, + "center_y": 0.3 + } + obj.height = dp(18) + obj.text_color = (1, 1, 1, 1) + obj.radius = [8] + return obj + + +def toast(text): + """Method will display the toast message""" + kivytoast.toast(text) + + +def showLimitedCnt(total_msg): + """This method set the total count limit in badge_text""" + return "99+" if total_msg > 99 else str(total_msg) + + +def avatarImageFirstLetter(letter_string): + """This function is used to the first letter for the avatar image""" + try: + if letter_string[0].upper() >= 'A' and letter_string[0].upper() <= 'Z': + img_latter = letter_string[0].upper() + elif int(letter_string[0]) >= 0 and int(letter_string[0]) <= 9: + img_latter = letter_string[0] + else: + img_latter = '!' + except ValueError: + img_latter = '!' + return img_latter if img_latter else '!' + + +def ShowTimeHistoy(act_time): + """This method is used to return the message sent or receive time""" + action_time = datetime.fromtimestamp(int(act_time)) + crnt_date = datetime.now() + duration = crnt_date - action_time + display_data = ( + action_time.strftime("%d/%m/%Y") + if duration.days >= 365 + else action_time.strftime("%I:%M %p").lstrip("0") + if duration.days == 0 and crnt_date.strftime("%d/%m/%Y") == action_time.strftime("%d/%m/%Y") + else action_time.strftime("%d %b") + ) + return display_data + + +# pylint: disable=too-few-public-methods +class AvatarSampleWidget(ILeftBody, Image): + """AvatarSampleWidget class for kivy Ui""" + + +# pylint: disable=too-many-ancestors +class TimeTagRightSampleWidget(IRightBodyTouch, MDLabel): + """TimeTagRightSampleWidget class for Ui""" + + +class SwipeToDeleteItem(MDCardSwipe): + """Swipe delete class for App UI""" + text = StringProperty() + cla = Window.size[0] / 2 + # cla = 800 + swipe_distance = NumericProperty(cla) + opening_time = NumericProperty(0.5) + + +class CutsomSwipeToDeleteItem(MDCardSwipe): + """Custom swipe delete class for App UI""" + text = StringProperty() + cla = Window.size[0] / 2 + swipe_distance = NumericProperty(cla) + opening_time = NumericProperty(0.5) diff --git a/src/mock/baseclass/draft.py b/src/mock/baseclass/draft.py new file mode 100644 index 00000000..5bf80837 --- /dev/null +++ b/src/mock/baseclass/draft.py @@ -0,0 +1,157 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel, simplifiable-if-expression + +""" +Kivy Draft screen +""" + +from functools import partial + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from baseclass.common import ( + showLimitedCnt, toast, ThemeClsColor, + SwipeToDeleteItem, ShowTimeHistoy +) + +from kivymd.uix.label import MDLabel + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class Draft(Screen): + """Draft screen class for kivy Ui""" + + data = ListProperty() + account = StringProperty() + queryreturn = ListProperty() + has_refreshed = True + + def __init__(self, *args, **kwargs): + """Method used for storing draft messages""" + super(Draft, self).__init__(*args, **kwargs) + if kivy_state.association == '': + if state.kivyapp.variable_1: + kivy_state.association = state.kivyapp.variable_1[0] + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method draft accounts""" + self.sentaccounts() + print(dt) + + def sentaccounts(self): + """Load draft accounts""" + # self.account = state.association + self.loadDraft() + + def loadDraft(self): + """Load draft list for Draft messages""" + self.account = kivy_state.association + self.ids.tag_label.text = '' + if self.queryreturn: + self.ids.tag_label.text = 'Draft' + self.set_draftCnt(kivy_state.draft_count) + self.set_mdList() + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_draftCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def set_draftCnt(self, Count): # pylint: disable=no-self-use + """This method set the count of draft mails""" + draftCnt_obj = state.kivyapp.root.ids.content_drawer.ids.draft_cnt + draftCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdList(self): + """This method is used to create mdlist""" + data = [] + total_draft_msg = len(self.ids.ml.children) + for mail in self.queryreturn: + third_text = mail[3].replace('\n', ' ') + data.append({ + 'text': mail[1].strip(), + 'secondary_text': mail[2][:10] + '...........' if len( + mail[2]) > 10 else mail[2] + '\n' + " " + ( + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, + 'ackdata': mail[5], 'senttime': mail[6]}) + for item in data: + message_row = SwipeToDeleteItem( + text='Draft', + ) + listItem = message_row.ids.content + listItem.secondary_text = item["text"] + listItem.theme_text_color = "Custom" + listItem.text_color = ThemeClsColor + message_row.ids.avater_img.source = kivy_state.imageDir + '/avatar.png' + listItem.bind(on_release=partial( + self.draft_detail, item['ackdata'], message_row)) + message_row.ids.time_tag.text = str(ShowTimeHistoy(item['senttime'])) + message_row.ids.delete_msg.bind(on_press=partial(self.delete_draft, item['ackdata'])) + self.ids.ml.add_widget(message_row) + updated_msg = len(self.ids.ml.children) + self.has_refreshed = True if total_draft_msg != updated_msg else False + + def check_scroll_y(self): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + + def draft_detail(self, ackdata, instance): + """Show draft Details""" + if instance.state == 'closed': + instance.ids.delete_msg.disabled = True + if instance.open_progress == 0.0: + kivy_state.detailPageType = 'draft' + kivy_state.mail_id = ackdata + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[11].clear_widgets() + # src_mng_obj.screens[11].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + else: + instance.ids.delete_msg.disabled = False + + def delete_draft(self, instance): + """Delete draft message permanently""" + if int(kivy_state.draft_count) > 0: + kivy_state.draft_count = str(int(kivy_state.draft_count) - 1) + self.set_draftCnt(kivy_state.draft_count) + if int(kivy_state.draft_count) <= 0: + # self.ids.identi_tag.children[0].text = '' + self.ids.tag_label.text = '' + self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') + + @staticmethod + def draft_msg(src_object): + """Save draft mails""" + composer_object = state.kivyapp.root.ids.sc3.children[1].ids + fromAddress = str(composer_object.ti.text) + toAddress = str(composer_object.txt_input.text) + sendMessageToPeople = True + if sendMessageToPeople: + from pybitmessage.addresses import addBMIfNotPresent + toAddress = addBMIfNotPresent(toAddress) + kivy_state.msg_counter_objs = src_object.children[2].children[0].ids + kivy_state.draft_count = str(int(kivy_state.draft_count) + 1) \ + if kivy_state.association == fromAddress else kivy_state.draft_count + src_object.ids.sc16.clear_widgets() + src_object.ids.sc16.add_widget(Draft()) + toast('Save draft') diff --git a/src/mock/baseclass/inbox.py b/src/mock/baseclass/inbox.py new file mode 100644 index 00000000..218bee38 --- /dev/null +++ b/src/mock/baseclass/inbox.py @@ -0,0 +1,81 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel, simplifiable-if-expression + +""" +Kivy Inbox screen +""" + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from baseclass.common import showLimitedCnt + +from kivymd.uix.label import MDLabel + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class Inbox(Screen): + """Inbox Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Method Parsing the address""" + super(Inbox, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + @staticmethod + def set_defaultAddress(): + """This method set's default address""" + if kivy_state.association == "": + if state.kivyapp.variable_1: + kivy_state.association = state.kivyapp.variable_1[0] + + def init_ui(self): + """Clock schdule for method inbox accounts""" + self.loadMessagelist() + + def loadMessagelist(self): + """Load Inbox list for Inbox messages""" + self.set_defaultAddress() + self.account = kivy_state.association + if kivy_state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 + self.ids.tag_label.text = "" + if self.queryreturn: + pass + else: + self.set_inboxCount("0") + content = MDLabel( + font_style="Caption", + theme_text_color="Primary", + text="No message found!" + if kivy_state.searcing_text + else "yet no message for this account!!!!!!!!!!!!!", + halign="center", + size_hint_y=None, + valign="top" + ) + self.ids.ml.add_widget(content) + + def set_inboxCount(self, msgCnt): # pylint: disable=no-self-use + """This method is used to sent inbox message count""" + src_mng_obj = state.kivyapp.root.ids.content_drawer.ids + src_mng_obj.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(msgCnt)) + state.kivyapp.get_sent_count() + kivy_state.all_count = str( + int(kivy_state.sent_count) + int(kivy_state.inbox_count)) + src_mng_obj.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.all_count)) + + def check_scroll_y(self): + """Loads data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 diff --git a/src/mock/baseclass/login.py b/src/mock/baseclass/login.py new file mode 100644 index 00000000..4d907cbb --- /dev/null +++ b/src/mock/baseclass/login.py @@ -0,0 +1,118 @@ +# pylint: disable=import-error, no-name-in-module, too-few-public-methods + + +""" +Kivy Login screen +""" + +from kivy.clock import Clock +from kivy.properties import StringProperty, BooleanProperty +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.screenmanager import Screen + +from baseclass.common import toast + +from kivymd.uix.behaviors.elevation import RectangularElevationBehavior + +from pybitmessage.bmconfigparser import BMConfigParser +from pybitmessage import queues +from pybitmessage import state + + +class Login(Screen): + """Login Screeen class for kivy Ui""" + # pylint: disable=too-few-public-methods + log_text1 = ( + 'You may generate addresses by using either random numbers' + ' or by using a passphrase If you use a passphrase, the address' + ' is called a deterministic; address The Random Number option is' + ' selected by default but deterministic addresses have several pros' + ' and cons:') + log_text2 = ('If talk about pros You can recreate your addresses on any computer' + ' from memory, You need-not worry about backing up your keys.dat file' + ' as long as you can remember your passphrase and aside talk about cons' + ' You must remember (or write down) your You must remember the address' + ' version number and the stream number along with your passphrase If you' + ' choose a weak passphrase and someone on the Internet can brute-force it,' + ' they can read your messages and send messages as you') + + +class Random(Screen): + """Random Screen class for Ui""" + + is_active = BooleanProperty(False) + checked = StringProperty("") + + def generateaddress(self): + """Method for Address Generator""" + # entered_label = str(self.ids.lab.text).strip() + entered_label = str(self.ids.add_random_bx.children[0].ids.lab.text).strip() + if not entered_label: + self.ids.add_random_bx.children[0].ids.lab.focus = True + streamNumberForAddress = 1 + eighteenByteRipe = False + nonceTrialsPerByte = 1000 + payloadLengthExtraBytes = 1000 + lables = [BMConfigParser().get(obj, 'label') + for obj in BMConfigParser().addresses()] + if entered_label and entered_label not in lables: + toast('Address Creating...') + queues.addressGeneratorQueue.put(( + 'createRandomAddress', 4, streamNumberForAddress, entered_label, 1, + "", eighteenByteRipe, nonceTrialsPerByte, + payloadLengthExtraBytes)) + self.parent.parent.ids.toolbar.opacity = 1 + self.parent.parent.ids.toolbar.disabled = False + state.kivyapp.loadMyAddressScreen(True) + self.manager.current = 'myaddress' + Clock.schedule_once(self.address_created_callback, 6) + + def address_created_callback(self, dt=0): # pylint: disable=unused-argument + """New address created""" + state.kivyapp.loadMyAddressScreen(False) + state.kivyapp.root.ids.sc10.ids.ml.clear_widgets() + state.kivyapp.root.ids.sc10.is_add_created = True + state.kivyapp.root.ids.sc10.init_ui() + self.reset_address_spinner() + toast('New address created') + + def reset_address_spinner(self): + """reseting spinner address and UI""" + addresses = [addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true'] + self.manager.parent.ids.content_drawer.ids.btn.values = [] + self.manager.parent.ids.sc3.children[1].ids.btn.values = [] + self.manager.parent.ids.content_drawer.ids.btn.values = addresses + self.manager.parent.ids.sc3.children[1].ids.btn.values = addresses + + @staticmethod + def add_validation(instance): + """Checking validation at address creation time""" + entered_label = str(instance.text.strip()) + lables = [BMConfigParser().get(obj, 'label') + for obj in BMConfigParser().addresses()] + if entered_label in lables: + instance.error = True + instance.helper_text = 'it is already exist you'\ + ' can try this Ex. ( {0}_1, {0}_2 )'.format( + entered_label) + elif entered_label: + instance.error = False + else: + instance.error = False + instance.helper_text = 'This field is required' + + def reset_address_label(self): + """Resetting address labels""" + if not self.ids.add_random_bx.children: + self.ids.add_random_bx.add_widget(RandomBoxlayout()) + + +class InfoLayout(BoxLayout, RectangularElevationBehavior): + """InfoLayout class for kivy Ui""" + # pylint: disable=too-few-public-methods + + +class RandomBoxlayout(BoxLayout): + """RandomBoxlayout class for BoxLayout behaviour""" + # pylint: disable=too-few-public-methods diff --git a/src/mock/baseclass/maildetail.py b/src/mock/baseclass/maildetail.py new file mode 100644 index 00000000..2f62bb87 --- /dev/null +++ b/src/mock/baseclass/maildetail.py @@ -0,0 +1,238 @@ +# pylint: disable=import-error, no-name-in-module, unused-argument +# pylint: disable=import-outside-toplevel, too-many-function-args + + +""" +Kivy Mail Detail screen +""" + +from datetime import datetime + +from kivy.core.clipboard import Clipboard +from kivy.clock import Clock +from kivy.properties import ( + StringProperty, + NumericProperty +) +from kivy.factory import Factory +from kivy.uix.screenmanager import Screen + +from kivymd.uix.button import MDFlatButton, MDIconButton +from kivymd.uix.dialog import MDDialog +from kivymd.uix.list import ( + OneLineListItem, + IRightBodyTouch +) + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + +from .common import ( + toast, avatarImageFirstLetter, ShowTimeHistoy +) +from .popup import SenderDetailPopup + + +# from pybitmessage.get_platform import platform +platform = "linux" + + +class OneLineListTitle(OneLineListItem): + """OneLineListTitle class for kivy Ui""" + __events__ = ('on_long_press', ) + long_press_time = NumericProperty(1) + + def on_state(self, instance, value): + """On state""" + if value == 'down': + lpt = self.long_press_time + self._clockev = Clock.schedule_once(self._do_long_press, lpt) + else: + self._clockev.cancel() + + def _do_long_press(self, dt): + """Do long press""" + self.dispatch('on_long_press') + + def on_long_press(self, *largs): + """On long press""" + self.copymessageTitle(self.text) + + def copymessageTitle(self, title_text): + """this method is for displaying dialog box""" + self.title_text = title_text + width = .8 if platform == 'android' else .55 + self.dialog_box = MDDialog( + text=title_text, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Copy", on_release=self.callback_for_copy_title + ), + MDFlatButton( + text="Cancel", on_release=self.callback_for_copy_title, + ), + ],) + self.dialog_box.open() + + def callback_for_copy_title(self, instance): + """Callback of alert box""" + if instance.text == 'Copy': + Clipboard.copy(self.title_text) + self.dialog_box.dismiss() + toast(instance.text) + + +class IconRightSampleWidget(IRightBodyTouch, MDIconButton): + """IconRightSampleWidget class for kivy Ui""" + + +class MailDetail(Screen): # pylint: disable=too-many-instance-attributes + """MailDetail Screen class for kivy Ui""" + + to_addr = StringProperty() + from_addr = StringProperty() + subject = StringProperty() + message = StringProperty() + status = StringProperty() + page_type = StringProperty() + time_tag = StringProperty() + avatarImg = StringProperty() + + def __init__(self, *args, **kwargs): + """Mail Details method""" + super().__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method MailDetail mails""" + self.page_type = state.detailPageType if kivy_state.detailPageType else '' + try: + # pylint: disable=consider-using-in + if kivy_state.detailPageType == 'sent' or kivy_state.detailPageType == 'draft': + data = [] + state.status = self + state.ackdata = data[0][5] + self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() + elif kivy_state.detailPageType == 'inbox': + data = [] + self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() + except Exception as e: + print('Something wents wrong!!') + + def assign_mail_details(self, data): + """Assigning mail details""" + subject = data[0][2].decode() if isinstance(data[0][2], bytes) else data[0][2] + body = data[0][3].decode() if isinstance(data[0][2], bytes) else data[0][3] + self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' ' + self.from_addr = data[0][1] + + self.subject = subject.capitalize( + ) if subject.capitalize() else '(no subject)' + self.message = body + if len(data[0]) == 7: + self.status = data[0][4] + self.time_tag = ShowTimeHistoy(data[0][4]) \ + if kivy_state.detailPageType == 'inbox' else ShowTimeHistoy(data[0][6]) + self.avatarImg = kivy_state.imageDir + '/avatar.png' if kivy_state.detailPageType == 'draft' else ( + kivy_state.imageDir + f'/text_images/{avatarImageFirstLetter(self.subject.strip(9))}.png') # noqa:E999 + self.timeinseconds = data[0][4] if kivy_state.detailPageType == 'inbox' else data[0][6] + + def delete_mail(self): + """Method for mail delete""" + msg_count_objs = state.kivyapp.root.ids.content_drawer.ids + kivy_state.searcing_text = '' + self.children[0].children[0].active = True + if kivy_state.detailPageType == 'sent': + state.kivyapp.root.ids.sc4.ids.sent_search.ids.search_field.text = '' + msg_count_objs.send_cnt.ids.badge_txt.text = str(int(kivy_state.sent_count) - 1) + kivy_state.sent_count = str(int(kivy_state.sent_count) - 1) + self.parent.screens[2].ids.ml.clear_widgets() + self.parent.screens[2].loadSent(kivy_state.association) + elif kivy_state.detailPageType == 'inbox': + state.kivyapp.root.ids.sc1.ids.inbox_search.ids.search_field.text = '' + msg_count_objs.inbox_cnt.ids.badge_txt.text = str( + int(kivy_state.inbox_count) - 1) + kivy_state.inbox_count = str(int(kivy_state.inbox_count) - 1) + self.parent.screens[0].ids.ml.clear_widgets() + self.parent.screens[0].loadMessagelist(kivy_state.association) + + elif kivy_state.detailPageType == 'draft': + msg_count_objs.draft_cnt.ids.badge_txt.text = str( + int(kivy_state.draft_count) - 1) + kivy_state.draft_count = str(int(kivy_state.draft_count) - 1) + self.parent.screens[13].clear_widgets() + self.parent.screens[13].add_widget(Factory.Draft()) + + if kivy_state.detailPageType != 'draft': + msg_count_objs.trash_cnt.ids.badge_txt.text = str( + int(kivy_state.trash_count) + 1) + msg_count_objs.allmail_cnt.ids.badge_txt.text = str( + int(kivy_state.all_count) - 1) + kivy_state.trash_count = str(int(kivy_state.trash_count) + 1) + kivy_state.all_count = str(int(kivy_state.all_count) - 1) if int(kivy_state.all_count) else '0' + self.parent.screens[3].clear_widgets() + self.parent.screens[3].add_widget(Factory.Trash()) + self.parent.screens[14].clear_widgets() + self.parent.screens[14].add_widget(Factory.Allmails()) + Clock.schedule_once(self.callback_for_delete, 4) + + def callback_for_delete(self, dt=0): + """Delete method from allmails""" + if kivy_state.detailPageType: + self.children[0].children[0].active = False + state.kivyapp.set_common_header() + self.parent.current = 'allmails' \ + if kivy_state.is_allmail else kivy_state.detailPageType + kivy_state.detailPageType = '' + toast('Deleted') + + def inbox_reply(self): + """Reply inbox messages""" + kivy_state.in_composer = True + data = [] + composer_obj = self.parent.screens[1].children[1].ids + composer_obj.ti.text = data[0][0] + composer_obj.btn.text = data[0][0] + composer_obj.txt_input.text = data[0][1] + split_subject = data[0][2].split('Re:', 1) + composer_obj.subject.text = 'Re: ' + (split_subject[1] if len(split_subject) > 1 else split_subject[0]) + time_obj = datetime.fromtimestamp(int(data[0][4])) + time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") + # sender_name = BMConfigParser().get(data[0][1], 'label') + sender_name = data[0][1] + composer_obj.body.text = ( + '\n\n --------------On ' + time_tag + ', ' + sender_name + ' wrote:--------------\n' + data[0][3]) + composer_obj.body.focus = True + composer_obj.body.cursor = (0, 0) + state.kivyapp.root.ids.sc3.children[1].ids.rv.data = '' + self.parent.current = 'create' + state.kivyapp.set_navbar_for_composer() + + def write_msg(self, navApp): + """Write on draft mail""" + kivy_state.send_draft_mail = kivy_state.mail_id + data = [] + composer_ids = ( + self.parent.parent.ids.sc3.children[1].ids) + composer_ids.ti.text = data[0][1] + composer_ids.btn.text = data[0][1] + composer_ids.txt_input.text = data[0][0] + composer_ids.subject.text = data[0][2] if data[0][2] != '(no subject)' else '' + composer_ids.body.text = data[0][3] + self.parent.current = 'create' + navApp.set_navbar_for_composer() + + def detailedPopup(self): + """Detailed popup""" + obj = SenderDetailPopup() + obj.open() + arg = (self.to_addr, self.from_addr, self.timeinseconds) + obj.assignDetail(*arg) + + @staticmethod + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + toast(text_item) diff --git a/src/mock/baseclass/msg_composer.py b/src/mock/baseclass/msg_composer.py new file mode 100644 index 00000000..9e030b0a --- /dev/null +++ b/src/mock/baseclass/msg_composer.py @@ -0,0 +1,263 @@ +# pylint: disable=import-error, no-name-in-module, unused-variable +# pylint: disable=too-many-ancestors, unused-argument, too-few-public-methods + +""" +Kivy Mail Composer screen +""" + +from kivy.clock import Clock +from kivy.core.window import Window +from kivy.factory import Factory +from kivy.properties import ( + BooleanProperty, + ListProperty, + NumericProperty, + ObjectProperty, +) +from kivy.uix.behaviors import FocusBehavior +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.label import Label +from kivy.uix.recycleview import RecycleView +from kivy.uix.recycleboxlayout import RecycleBoxLayout +from kivy.uix.recycleview.layout import LayoutSelectionBehavior +from kivy.uix.recycleview.views import RecycleDataViewBehavior +from kivy.uix.screenmanager import Screen + +from baseclass.common import ( + toast, showLimitedCnt +) + +from kivymd.uix.textfield import MDTextField +from kivymd.uix.button import MDFlatButton +from kivymd.uix.dialog import MDDialog + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state +from pybitmessage import queues + +from pybitmessage.addresses import decodeAddress, addBMIfNotPresent +from pybitmessage.bitmessagekivy.get_platform import platform +from pybitmessage.bmconfigparser import BMConfigParser + + +class Create(Screen): + """Creates Screen class for kivy Ui""" + + def __init__(self, **kwargs): + """Getting Labels and address from addressbook""" + super(Create, self).__init__(**kwargs) + Window.softinput_mode = "below_target" + widget_1 = DropDownWidget() + widget_1.ids.txt_input.word_list = [] + widget_1.ids.txt_input.starting_no = 2 + self.add_widget(widget_1) + self.children[0].ids.id_scroll.bind(scroll_y=self.check_scroll_y) + + def check_scroll_y(self, instance, somethingelse): + """show data on scroll down""" + if self.children[1].ids.btn.is_open: + self.children[1].ids.btn.is_open = False + + +class RV(RecycleView): + """Recycling View class for kivy Ui""" + + +class SelectableRecycleBoxLayout( + FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout +): + """Adds selection and focus behaviour to the view""" + + # pylint: disable = duplicate-bases + + +class DropDownWidget(BoxLayout): + """DropDownWidget class for kivy Ui""" + + # pylint: disable=too-many-statements + + txt_input = ObjectProperty() + rv = ObjectProperty() + + def send(self, navApp): + """Send message from one address to another""" + fromAddress = self.ids.ti.text.strip() + toAddress = self.ids.txt_input.text.strip() + subject = self.ids.subject.text.strip() + message = self.ids.body.text.strip() + print("message: ", self.ids.body.text) + if toAddress != "" and subject and message: + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress + ) + if status == "success": + navApp.root.ids.sc3.children[0].active = True + if kivy_state.detailPageType == "draft" and kivy_state.send_draft_mail: + self.parent.parent.screens[13].clear_widgets() + self.parent.parent.screens[13].add_widget(Factory.Draft()) + else: + if (addressVersionNumber > 4) or ( + addressVersionNumber <= 1): + print( + "addressVersionNumber > 4" + " or addressVersionNumber <= 1") + if streamNumber > 1 or streamNumber == 0: + print("streamNumber > 1 or streamNumber == 0") + stealthLevel = BMConfigParser().safeGetInt( + 'bitmessagesettings', 'ackstealthlevel') + + kivy_state.check_sent_acc = fromAddress + if kivy_state.detailPageType == 'draft' \ + and kivy_state.send_draft_mail: + kivy_state.draft_count = str(int(kivy_state.draft_count) - 1) + kivy_state.detailPageType = '' + kivy_state.send_draft_mail = None + self.parent.parent.parent.ids.sc4.update_sent_messagelist() + allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt + allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(kivy_state.all_count) + 1) + kivy_state.all_count = str(int(kivy_state.all_count) + 1) + Clock.schedule_once(self.callback_for_msgsend, 3) + queues.workerQueue.put(('sendmessage', addBMIfNotPresent(toAddress))) + print("sqlExecute successfully #######################") + kivy_state.in_composer = True + else: + msg = 'Enter a valid recipients address' + elif not toAddress: + msg = 'Please fill the form completely' + else: + msg = 'Please fill the form completely' + self.address_error_message(msg) + + @staticmethod + def callback_for_msgsend(dt=0): # pylint: disable=unused-argument + """Callback method for messagesend""" + state.kivyapp.root.ids.sc3.children[0].active = False + kivy_state.in_sent_method = True + state.kivyapp.back_press() + toast("sent") + + @staticmethod + def address_error_message(msg): + """Generates error message""" + width = .8 if platform == 'android' else .55 + dialog_box = MDDialog( + text=msg, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ],) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + dialog_box.dismiss() + toast(text_item) + + def reset_composer(self): + """Method will reset composer""" + self.ids.ti.text = "" + self.ids.btn.text = "Select" + self.ids.txt_input.text = "" + self.ids.subject.text = "" + self.ids.body.text = "" + toast("Reset message") + + def auto_fill_fromaddr(self): + """Fill the text automatically From Address""" + self.ids.ti.text = self.ids.btn.text + self.ids.ti.focus = True + + def is_camara_attached(self): + """Checks the camera availability in device""" + self.parent.parent.parent.ids.sc23.check_camera() + is_available = self.parent.parent.parent.ids.sc23.camera_avaialbe + return is_available + + @staticmethod + def camera_alert(): + """Show camera availability alert message""" + width = .8 if platform == 'android' else .55 + altet_txt = 'Currently this feature is not avaialbe!'if platform == 'android' else 'Camera is not available!' + dialog_box = MDDialog( + text=altet_txt, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ], + ) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + dialog_box.dismiss() + toast(text_item) + + +class MyTextInput(MDTextField): + """MyTextInput class for kivy Ui""" + + txt_input = ObjectProperty() + flt_list = ObjectProperty() + word_list = ListProperty() + starting_no = NumericProperty(3) + suggestion_text = '' + + def __init__(self, **kwargs): + """Getting Text Input.""" + super(MyTextInput, self).__init__(**kwargs) + self.__lineBreak__ = 0 + + def on_text(self, instance, value): # pylint: disable=unused-argument + """Find all the occurrence of the word""" + self.parent.parent.parent.parent.parent.ids.rv.data = [] + matches = [self.word_list[i] for i in range( + len(self.word_list)) if self.word_list[ + i][:self.starting_no] == value[:self.starting_no]] + display_data = [] + for i in matches: + display_data.append({'text': i}) + self.parent.parent.parent.parent.parent.ids.rv.data = display_data + if len(matches) <= 10: + self.parent.height = (250 + (len(matches) * 20)) + else: + self.parent.height = 400 + + def keyboard_on_key_down(self, window, keycode, text, modifiers): + """Keyboard on key Down""" + if self.suggestion_text and keycode[1] == 'tab': + self.insert_text(self.suggestion_text + ' ') + return True + return super(MyTextInput, self).keyboard_on_key_down( + window, keycode, text, modifiers) + + +class SelectableLabel(RecycleDataViewBehavior, Label): + """Add selection support to the Label""" + + index = None + selected = BooleanProperty(False) + selectable = BooleanProperty(True) + + def refresh_view_attrs(self, rv, index, data): + """Catch and handle the view changes""" + self.index = index + return super(SelectableLabel, self).refresh_view_attrs(rv, index, data) + + def on_touch_down(self, touch): # pylint: disable=inconsistent-return-statements + """Add selection on touch down""" + if super(SelectableLabel, self).on_touch_down(touch): + return True + if self.collide_point(*touch.pos) and self.selectable: + return self.parent.select_with_touch(self.index, touch) + + def apply_selection(self, rv, index, is_selected): + """Respond to the selection of items in the view""" + self.selected = is_selected + if is_selected: + rv.parent.txt_input.text = rv.parent.txt_input.text.replace( + rv.parent.txt_input.text, rv.data[index]["text"] + ) diff --git a/src/mock/baseclass/myaddress.py b/src/mock/baseclass/myaddress.py new file mode 100644 index 00000000..ca477c96 --- /dev/null +++ b/src/mock/baseclass/myaddress.py @@ -0,0 +1,239 @@ +# pylint: disable=import-error, no-name-in-module +# pylint: disable=import-outside-toplevel, too-many-function-args + +""" +Kivy My Address Book screen +""" + +from pybitmessage.bitmessagekivy.get_platform import platform +from functools import partial +from pybitmessage.bmconfigparser import BMConfigParser +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivymd.uix.button import MDFlatButton +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.list import ( + IRightBodyTouch, + TwoLineAvatarIconListItem, +) +from kivymd.uix.selectioncontrol import MDSwitch +from kivy.uix.screenmanager import Screen + +from pybitmessage import state + +from baseclass.common import ( + avatarImageFirstLetter, AvatarSampleWidget, ThemeClsColor, + toast +) +from baseclass.popup import MyaddDetailPopup + + +class ToggleBtn(IRightBodyTouch, MDSwitch): + """ToggleBtn class for kivy Ui""" + + +class CustomTwoLineAvatarIconListItem(TwoLineAvatarIconListItem): + """CustomTwoLineAvatarIconListItem class for kivy Ui""" + + +class BadgeText(IRightBodyTouch, MDLabel): + """BadgeText class for kivy Ui""" + + +class MyAddress(Screen): + """MyAddress screen class for kivy Ui""" + + address_label = StringProperty() + text_address = StringProperty() + addresses_list = ListProperty() + has_refreshed = True + is_add_created = False + + def __init__(self, *args, **kwargs): + """Clock schdule for method Myaddress accounts""" + super().__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock schdule for method Myaddress accounts""" + # pylint: disable=unnecessary-lambda + self.addresses_list = BMConfigParser().addresses() + if state.searcing_text: + self.ids.refresh_layout.scroll_y = 1.0 + filtered_list = [ + x for x in BMConfigParser().addresses() + if self.filter_address(x) + ] + self.addresses_list = filtered_list + self.addresses_list = list(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, 15) + self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + else: + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No address found!" if state.searcing_text + else "yet no address is created by user!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + if not state.searcing_text and not self.is_add_created: + try: + self.manager.current = 'login' + except Exception: + pass + + def set_mdList(self, first_index, last_index): + """Creating the mdlist""" + data = [] + for address in self.addresses_list[first_index:last_index]: + data.append({ + 'text': BMConfigParser().get(address, 'label'), + 'secondary_text': address}) + for item in data: + is_enable = BMConfigParser().get(item['secondary_text'], 'enabled') + meny = CustomTwoLineAvatarIconListItem( + text=item['text'], secondary_text=item['secondary_text'], + theme_text_color='Custom' if is_enable == 'true' else 'Primary', + text_color=ThemeClsColor,) + # meny._txt_right_pad = dp(70) + try: + meny.canvas.children[3].rgba = [0, 0, 0, 0] if is_enable == 'true' else [0.5, 0.5, 0.5, 0.5] + except Exception: + pass + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + f'/text_images/{avatarImageFirstLetter(item["text"].strip())}.png')) # noqa:E999 + meny.bind(on_press=partial( + self.myadd_detail, item['secondary_text'], item['text'])) + if state.association == item['secondary_text'] and is_enable == 'true': + badge_obj = BadgeText( + size_hint=(None, None), + size=[90 if platform == 'android' else 50, 60], + text='Active', halign='center', + font_style='Body1', theme_text_color='Custom', + text_color=ThemeClsColor + ) + badge_obj.font_size = '13sp' + meny.add_widget(badge_obj) + else: + meny.add_widget(ToggleBtn(active=True if is_enable == 'true' else False)) + self.ids.ml.add_widget(meny) + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll down""" + if self.ids.refresh_layout.scroll_y <= -0.0 and self.has_refreshed: + self.ids.refresh_layout.scroll_y = 0.06 + + def myadd_detail(self, fromaddress, label, *args): + """Load myaddresses details""" + if BMConfigParser().get(fromaddress, 'enabled') == 'true': + obj = MyaddDetailPopup() + self.address_label = obj.address_label = label + self.text_address = obj.address = fromaddress + width = .9 if platform == 'android' else .6 + self.myadddetail_popup = MDDialog( + type="custom", + size_hint=(width, .25), + content_cls=obj, + ) + # self.myadddetail_popup.set_normal_height() + self.myadddetail_popup.auto_dismiss = False + self.myadddetail_popup.open() + # p.set_address(fromaddress, label) + else: + width = .8 if platform == 'android' else .55 + dialog_box = MDDialog( + text='Address is not currently active. Please click on Toggle button to active it.', + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ], + ) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + 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""" + state.searcing_text = '' + # state.kivyapp.root.ids.sc10.children[2].active = False + 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() + # self.tick = 0 + Clock.schedule_once(self.address_permision_callback, 0) + Clock.schedule_once(refresh_callback, 1) + + @staticmethod + def filter_address(address): + """Method will filter the my address list data""" + if [ + x for x in [ + BMConfigParser().get(address, 'label').lower(), + address.lower() + ] + if (state.searcing_text).lower() in x + ]: + return True + return False + + def disableAddress(self, address, instance): + """This method is use for disabling address""" + BMConfigParser().set(str(address), 'enabled', 'false') + BMConfigParser().save() + instance.parent.parent.theme_text_color = 'Primary' + instance.parent.parent.canvas.children[3].rgba = [0.5, 0.5, 0.5, 0.5] + # try: + # instance.parent.parent.canvas.children[6].rgba = [0.5, 0.5, 0.5, 0.5] + # except Exception: + # instance.parent.parent.canvas.children[9].rgba = [0.5, 0.5, 0.5, 0.5] + toast('Address disabled') + Clock.schedule_once(self.address_permision_callback, 0) + + def enableAddress(self, address, instance): + """This method is use for enabling address""" + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().save() + instance.parent.parent.theme_text_color = 'Custom' + instance.parent.parent.canvas.children[3].rgba = [0, 0, 0, 0] + # try: + # instance.parent.parent.canvas.children[6].rgba = [0, 0, 0, 0] + # except Exception: + # instance.parent.parent.canvas.children[9].rgba = [0, 0, 0, 0] + 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 BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true'] + self.parent.parent.ids.content_drawer.ids.btn.values = addresses + self.parent.parent.ids.sc3.children[1].ids.btn.values = addresses + state.kivyapp.variable_1 = addresses + + def toggleAction(self, instance): + """This method is used for enable or disable address""" + addr = instance.parent.parent.secondary_text + if instance.active: + self.enableAddress(addr, instance) + else: + self.disableAddress(addr, instance) diff --git a/src/mock/baseclass/network.py b/src/mock/baseclass/network.py new file mode 100644 index 00000000..7bd59fd4 --- /dev/null +++ b/src/mock/baseclass/network.py @@ -0,0 +1,32 @@ +# pylint: disable=consider-using-f-string, no-name-in-module, too-few-public-methods + +""" +Kivy Network screen +""" + +from kivy.clock import Clock +from kivy.properties import StringProperty +from kivy.uix.screenmanager import Screen + + +class NetworkStat(Screen): + """NetworkStat class for kivy Ui""" + + text_variable_1 = StringProperty( + '{0}::{1}'.format('Total Connections', '0')) + text_variable_2 = StringProperty( + 'Processed {0} per-to-per messages'.format('0')) + text_variable_3 = StringProperty( + 'Processed {0} brodcast messages'.format('0')) + text_variable_4 = StringProperty( + 'Processed {0} public keys'.format('0')) + text_variable_5 = StringProperty( + 'Processed {0} object to be synced'.format('0')) + + def __init__(self, *args, **kwargs): + """Init method for network stat""" + super(NetworkStat, self).__init__(*args, **kwargs) + Clock.schedule_interval(self.init_ui, 1) + + def init_ui(self, dt=0): + """Clock Schdule for method networkstat screen""" diff --git a/src/mock/baseclass/payment.py b/src/mock/baseclass/payment.py new file mode 100644 index 00000000..f3cfceb6 --- /dev/null +++ b/src/mock/baseclass/payment.py @@ -0,0 +1,44 @@ +# pylint: disable=too-many-ancestors, abstract-method, too-few-public-methods + +''' + This is for pamyent related part +''' +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.screenmanager import Screen +from kivymd.uix.behaviors.elevation import RectangularElevationBehavior + +from kivymd.uix.label import MDLabel +from kivymd.uix.list import ( + IRightBodyTouch, + OneLineAvatarIconListItem +) + + +class Payment(Screen): + """Payment Screen class for kivy Ui""" + + @staticmethod + def create_hidden_payment_address(): + """This is basically used for creating hidden address used in payment for purchasing credits""" + + +class Category(BoxLayout, RectangularElevationBehavior): + """Category class for kivy Ui""" + elevation_normal = .01 + + +class ProductLayout(BoxLayout, RectangularElevationBehavior): + """ProductLayout class for kivy Ui""" + elevation_normal = .01 + + +class PaymentMethodLayout(BoxLayout): + """PaymentMethodLayout class for kivy Ui""" + + +class ListItemWithLabel(OneLineAvatarIconListItem): + """ListItemWithLabel class for kivy Ui""" + + +class RightLabel(IRightBodyTouch, MDLabel): + """RightLabel class for kivy Ui""" diff --git a/src/mock/baseclass/popup.py b/src/mock/baseclass/popup.py new file mode 100644 index 00000000..0ff03d7a --- /dev/null +++ b/src/mock/baseclass/popup.py @@ -0,0 +1,155 @@ +# pylint: disable=import-error, no-name-in-module, import-outside-toplevel +# pylint: disable=too-few-public-methods, attribute-defined-outside-init + + +""" +Kivy All common pop managed here +""" + +from datetime import datetime + +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import StringProperty +from kivy.uix.popup import Popup +from kivy.uix.boxlayout import BoxLayout + +from baseclass.common import toast + +from pybitmessage import state + + +platform = "linux" + + +class LoadingPopup(Popup): + """LoadingPopup class for kivy Ui""" + + def __init__(self, **kwargs): + super(LoadingPopup, self).__init__(**kwargs) + # call dismiss_popup in 2 seconds + Clock.schedule_once(self.dismiss_popup, 0.5) + + def dismiss_popup(self): + """Dismiss popups""" + self.dismiss() + + +class GrashofPopup(BoxLayout): + """GrashofPopup class for kivy Ui""" + + valid = False + + def checkAddress_valid(self, instance): + """Checking address is valid or not""" + + def checkLabel_valid(self, instance): + """Checking address label is unique or not""" + + def _onSuccess(self, addressVersion, streamNumber, ripe): + """Called when the popup is open""" + + +class AddbookDetailPopup(BoxLayout): + """AddbookDetailPopup class for kivy Ui""" + + address_label = StringProperty() + address = StringProperty() + + def checkLabel_valid(self, instance): + """Checking address label is unique of not""" + entered_label = str(instance.text.strip()) + address_list = [] + addr_labels = [labels[0] for labels in address_list] + add_dict = dict(address_list) + if self.address and entered_label in addr_labels \ + and self.address != add_dict[entered_label]: + self.ids.add_label.error = True + self.ids.add_label.helper_text = 'label name already exists.' + elif entered_label: + self.ids.add_label.error = False + else: + self.ids.add_label.error = False + self.ids.add_label.helper_text = 'This field is required' + + +class MyaddDetailPopup(BoxLayout): + """MyaddDetailPopup class for kivy Ui""" + + address_label = StringProperty() + address = StringProperty() + + def send_message_from(self): + """Method used to fill from address of composer autofield""" + state.kivyapp.set_navbar_for_composer() + window_obj = state.kivyapp.root.ids + window_obj.sc3.children[1].ids.ti.text = self.address + window_obj.sc3.children[1].ids.btn.text = self.address + window_obj.sc3.children[1].ids.txt_input.text = '' + window_obj.sc3.children[1].ids.subject.text = '' + window_obj.sc3.children[1].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.parent.parent.parent.dismiss() + + # @staticmethod + def close_pop(self): + """Pop is Canceled""" + self.parent.parent.parent.dismiss() + toast('Canceled') + + +class AppClosingPopup(Popup): + """AppClosingPopup class for kivy Ui""" + + def closingAction(self, text): + """Action on closing window""" + if text == 'Yes': + print("*******************EXITING FROM APPLICATION*******************") + from pybitmessage import shutdown + shutdown.doCleanShutdown() + else: + self.dismiss() + toast(text) + + +class SenderDetailPopup(Popup): + """SenderDetailPopup class for kivy Ui""" + + to_addr = StringProperty() + from_addr = StringProperty() + time_tag = StringProperty() + + def assignDetail(self, to_addr, from_addr, timeinseconds): + """Detailes assigned""" + self.to_addr = to_addr + self.from_addr = from_addr + time_obj = datetime.fromtimestamp(int(timeinseconds)) + self.time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") + device_type = 2 if platform == 'android' else 1.5 + pop_height = 1.2 * device_type * (self.ids.sd_label.height + self.ids.dismiss_btn.height) + if len(to_addr) > 3: + self.height = pop_height + self.ids.to_addId.size_hint_y = None + self.ids.to_addId.height = 50 + self.ids.to_addtitle.add_widget(ToAddressTitle()) + frmaddbox = ToAddrBoxlayout() + frmaddbox.set_toAddress(to_addr) + self.ids.to_addId.add_widget(frmaddbox) + else: + self.ids.space_1.height = dp(0) + self.ids.space_2.height = dp(0) + self.ids.myadd_popup_box.spacing = dp(8 if platform == 'android' else 3) + self.height = pop_height / 1.2 + + +class ToAddrBoxlayout(BoxLayout): + """ToAddrBoxlayout class for kivy Ui""" + to_addr = StringProperty() + + def set_toAddress(self, to_addr): + """This method is use to set to address""" + self.to_addr = to_addr + + +class ToAddressTitle(BoxLayout): + """ToAddressTitle class for BoxLayout behaviour""" diff --git a/src/mock/baseclass/qrcode.py b/src/mock/baseclass/qrcode.py new file mode 100644 index 00000000..4c5438da --- /dev/null +++ b/src/mock/baseclass/qrcode.py @@ -0,0 +1,27 @@ + +# pylint: disable=no-name-in-module, too-few-public-methods + +""" +QRCode generator +""" + +from kivy.uix.screenmanager import Screen +from kivy.properties import StringProperty +from kivy_garden.qrcode import QRCodeWidget +from baseclass.common import toast +from pybitmessage import state + + +class ShowQRCode(Screen): + """ShowQRCode Screen class for kivy Ui""" + address = StringProperty() + + def qrdisplay(self, instasnce, address): + """Method used for showing QR Code""" + self.ids.qr.clear_widgets() + state.kivyapp.set_toolbar_for_QrCode() + self.address = address + self.ids.qr.add_widget(QRCodeWidget(data=address)) + self.ids.qr.children[0].show_border = False + instasnce.parent.parent.parent.dismiss() + toast('Show QR code') diff --git a/src/mock/baseclass/scan_screen.py b/src/mock/baseclass/scan_screen.py new file mode 100644 index 00000000..5ea2654a --- /dev/null +++ b/src/mock/baseclass/scan_screen.py @@ -0,0 +1,104 @@ +# pylint: disable=import-error, no-name-in-module, import-outside-toplevel +# pylint: disable=no-member, attribute-defined-outside-init, arguments-differ + +""" +Kivy QR Scan screen +""" + +import os + +from kivy.clock import Clock +from kivy.lang import Builder +from kivy.properties import ( + BooleanProperty, + ObjectProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from pybitmessage.bitmessagekivy.get_platform import platform + + +class ScanScreen(Screen): + """ScanScreen is for scaning Qr code""" + # pylint: disable=unused-argument + # pylint: disable=W0212 + camera_avaialbe = BooleanProperty(False) + previous_open_screen = StringProperty() + pop_up_instance = ObjectProperty() + + def __init__(self, *args, **kwargs): + """Getting AddressBook Details""" + super(ScanScreen, self).__init__(*args, **kwargs) + self.check_camera() + + def check_camera(self): + """This method is used for checking camera avaibility""" + if platform != "android": + import cv2 + cap = cv2.VideoCapture(0) + while cap.isOpened(): + print('Camera is available!') + self.camera_avaialbe = True + break + else: + print("Camera is not available!") + self.camera_avaialbe = False + else: + self.camera_avaialbe = True + + def get_screen(self, screen_name, instance=None): + """This method is used for getting previous screen name""" + self.previous_open_screen = screen_name + if screen_name != 'composer': + self.pop_up_instance = instance + + def on_pre_enter(self): + """ + on_pre_enter works little better on android + It affects screen transition on linux + """ + if not self.children: + tmp = Builder.load_file( + os.path.join( + os.path.dirname(os.path.dirname(__file__)), "kv/{}.kv").format("scanner") + ) + self.add_widget(tmp) + if platform == "android": + Clock.schedule_once(self.start_camera, 0) + + def on_enter(self): + """ + on_enter works better on linux + It creates a black screen on android until camera gets loaded + """ + # print(self.children) + if platform != "android": + # pass + Clock.schedule_once(self.start_camera, 0) + + def on_leave(self): + """this methos will call on leave""" + # pass + Clock.schedule_once(self.stop_camera, 0) + + def start_camera(self, *args): + """Its used for starting camera for scanning qrcode""" + self.xcam = self.children[0].ids.zbarcam.ids.xcamera + if platform == "android": + self.xcam.play = True + + else: + Clock.schedule_once(self.open_cam, 0) + + def stop_camera(self, *args): + """Its used for stop the camera""" + self.xcam.play = False + if platform != "android": + self.xcam._camera._device.release() + + def open_cam(self, *args): + """It will open up the camera""" + if not self.xcam._camera._device.isOpened(): + self.xcam._camera._device.open(self.xcam._camera._index) + self.xcam.play = True diff --git a/src/mock/baseclass/sent.py b/src/mock/baseclass/sent.py new file mode 100644 index 00000000..5c2aab30 --- /dev/null +++ b/src/mock/baseclass/sent.py @@ -0,0 +1,179 @@ +# pylint: disable=import-error, no-name-in-module, consider-using-f-string +# pylint: disable=simplifiable-if-expression, pointless-statement, no-memberi + +""" +Kivy Sent box screen +""" + +from functools import partial + +from kivy.clock import Clock +from kivy.properties import StringProperty, ListProperty +from kivy.uix.screenmanager import Screen + + +from baseclass.common import ( + showLimitedCnt, ThemeClsColor, avatarImageFirstLetter, + toast, SwipeToDeleteItem, ShowTimeHistoy +) + +from kivymd.uix.label import MDLabel + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class Sent(Screen): + """Sent Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Association with the screen""" + super(Sent, self).__init__(*args, **kwargs) + if kivy_state.association == '': + if state.kivyapp.variable_1: + kivy_state.association = state.kivyapp.variable_1[0] + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method sent accounts""" + self.loadSent() + print(dt) + + def loadSent(self): + """Load Sent list for Sent messages""" + self.account = kivy_state.association + if kivy_state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 + data = [] + self.ids.tag_label.text = '' + if self.queryreturn: + self.ids.tag_label.text = 'Sent' + self.set_sentCount(kivy_state.sent_count) + for mail in self.queryreturn: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': (mail[2][:50] + '........' if len( + mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( + '\t', '').replace(' ', ''), + 'ackdata': mail[5], 'senttime': mail[6]},) + self.set_mdlist(data, 0) + self.has_refreshed = True + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_sentCount('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No message found!" if kivy_state.searcing_text + else "yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def set_mdlist(self, data, set_index=0): + """This method is used to create the mdList""" + total_sent_msg = len(self.ids.ml.children) + for item in data: + message_row = SwipeToDeleteItem( + text=item["text"], + ) + listItem = message_row.ids.content + listItem.secondary_text = item["secondary_text"] + listItem.theme_text_color = "Custom" + listItem.text_color = ThemeClsColor + image = kivy_state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())) + message_row.ids.avater_img.source = image + listItem.bind(on_release=partial(self.sent_detail, item['ackdata'], message_row)) + message_row.ids.time_tag.text = str(ShowTimeHistoy(item['senttime'])) + message_row.ids.delete_msg.bind(on_press=partial(self.delete, item["ackdata"])) + self.ids.ml.add_widget(message_row, index=set_index) + + updated_msgs = len(self.ids.ml.children) + self.has_refreshed = True if total_sent_msg != updated_msgs else False + + def update_sent_messagelist(self): + """This method is used to update screen when new mail is sent""" + self.account = kivy_state.association + if len(self.ids.ml.children) < 3: + self.ids.ml.clear_widgets() + self.loadSent() + if kivy_state.association == kivy_state.check_sent_acc: + total_sent = int(kivy_state.sent_count) + 1 + kivy_state.sent_count = str(int(kivy_state.sent_count) + 1) + self.set_sentCount(total_sent) + else: + total_sent = int(kivy_state.sent_count) + else: + data = [] + if kivy_state.association == kivy_state.check_sent_acc: + total_sent = int(kivy_state.sent_count) + 1 + kivy_state.sent_count = str(int(kivy_state.sent_count) + 1) + self.set_sentCount(total_sent) + else: + total_sent = int(kivy_state.sent_count) + for mail in self.queryreturn: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': (mail[2][:50] + '........' if len( + mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( + '\t', '').replace(' ', ''), + 'ackdata': mail[5], 'senttime': mail[6]}) + self.set_mdlist(data, total_sent - 1) + if kivy_state.msg_counter_objs and kivy_state.association == ( + kivy_state.check_sent_acc): + kivy_state.all_count = str(int(kivy_state.all_count) + 1) + kivy_state.msg_counter_objs.allmail_cnt.badge_text = kivy_state.all_count + kivy_state.check_sent_acc = None + + def check_scroll_y(self): + """Load data on scroll down""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + + @staticmethod + def set_sentCount(total_sent): + """Set the total no. of sent message count""" + src_mng_obj = state.kivyapp.root.ids.content_drawer.ids.send_cnt + state.kivyapp.root.ids.content_drawer.ids.send_cnt.ids.badge_txt.text + if kivy_state.association: + src_mng_obj.ids.badge_txt.text = showLimitedCnt(int(total_sent)) + else: + src_mng_obj.ids.badge_txt.text = '0' + + def sent_detail(self, ackdata, instance): + """Load sent mail details""" + if instance.state == 'closed': + instance.ids.delete_msg.disabled = True + if instance.open_progress == 0.0: + kivy_state.detailPageType = 'sent' + kivy_state.mail_id = ackdata + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[11].clear_widgets() + # src_mng_obj.screens[11].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + else: + instance.ids.delete_msg.disabled = False + + def delete(self, instance): + """Delete sent mail from sent mail listing""" + msg_count_objs = self.parent.parent.ids.content_drawer.ids + if int(kivy_state.sent_count) > 0: + msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.sent_count) - 1) + msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.trash_count) + 1) + msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(kivy_state.all_count) - 1) + kivy_state.sent_count = str(int(kivy_state.sent_count) - 1) + kivy_state.trash_count = str(int(kivy_state.trash_count) + 1) + kivy_state.all_count = str(int(kivy_state.all_count) - 1) + if int(kivy_state.sent_count) <= 0: + self.ids.tag_label.text = '' + self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') diff --git a/src/mock/baseclass/settings.py b/src/mock/baseclass/settings.py new file mode 100644 index 00000000..8d0ab365 --- /dev/null +++ b/src/mock/baseclass/settings.py @@ -0,0 +1,10 @@ +# pylint: disable=too-few-public-methods + +""" +App Settings Screen +""" +from kivy.uix.screenmanager import Screen + + +class Setting(Screen): + """Setting Screen for kivy Ui""" diff --git a/src/mock/baseclass/trash.py b/src/mock/baseclass/trash.py new file mode 100644 index 00000000..3030a4f2 --- /dev/null +++ b/src/mock/baseclass/trash.py @@ -0,0 +1,79 @@ +# pylint: disable=import-error, no-name-in-module, simplifiable-if-expression, no-self-use + +""" +Kivy Trash Box screen +""" + +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.screenmanager import Screen + +from baseclass.common import showLimitedCnt + + +from kivymd.uix.label import MDLabel + +from pybitmessage import state +from pybitmessage.bitmessagekivy import kivy_state + + +class Trash(Screen): + """Trash Screen class for kivy Ui""" + + trash_messages = ListProperty() + has_refreshed = True + delete_index = None + table_name = StringProperty() + + def __init__(self, *args, **kwargs): + """Trash method, delete sent message and add in Trash""" + super(Trash, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self): + """Clock Schdule for method trash screen""" + if state.association == '': + if state.kivyapp.variable_1: + state.association = state.kivyapp.variable_1[0] + self.ids.tag_label.text = '' + if len(self.trash_messages): + self.ids.ml.clear_widgets() + self.ids.tag_label.text = 'Trash' + # src_mng_obj = state.kivyapp.root.children[2].children[0].ids + # src_mng_obj.trash_cnt.badge_text = state.trash_count + self.set_TrashCnt(kivy_state.trash_count) + self.set_mdList() + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_TrashCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no trashed message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def set_TrashCnt(self, Count): + """This method is used to set trash message count""" + trashCnt_obj = state.kivyapp.root.ids.content_drawer.ids.trash_cnt + trashCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdList(self): + """This method is used to create the mdlist""" + total_trash_msg = len(self.ids.ml.children) + self.has_refreshed = True if total_trash_msg != len( + self.ids.ml.children) else False + + def on_swipe_complete(self, instance): + """call on swipe left""" + instance.ids.delete_msg.disabled = bool(instance.state == 'closed') + + def check_scroll_y(self): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 diff --git a/src/mock/bitmessagemock.py b/src/mock/bitmessagemock.py new file mode 100644 index 00000000..4d357388 --- /dev/null +++ b/src/mock/bitmessagemock.py @@ -0,0 +1,45 @@ +# pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument, no-else-return, unused-variable +# pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation, attribute-defined-outside-init +# pylint: disable=protected-access, super-with-arguments, pointless-statement, no-method-argument, too-many-function-args +# pylint: disable=import-outside-toplevel,ungrouped-imports,wrong-import-order,unused-import,arguments-differ +# pylint: disable=invalid-name,unnecessary-comprehension,broad-except,simplifiable-if-expression,no-member, consider-using-in +# pylint: disable=too-many-return-statements, unnecessary-pass, bad-option-value, abstract-method, consider-using-f-string + + +""" +Bitmessage mock +""" + +from pybitmessage.class_addressGenerator import addressGenerator +from pybitmessage.inventory import Inventory +from pybitmessage.bmconfigparser import BMConfigParser +from pybitmessage import state + + +class MockMain: + """Mock main function""" + + def start(self): + """Start main application""" + # pylint: disable=too-many-statements,too-many-branches, unused-variable + config = BMConfigParser() + daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') + # Start the address generation thread + addressGeneratorThread = addressGenerator() + # close the main program even if there are threads left + addressGeneratorThread.daemon = True + addressGeneratorThread.start() + Inventory() + from pybitmessage.mpybit import NavigateApp + state.kivyapp = NavigateApp() + state.kivyapp.run() + + +def main(): + """Triggers main module""" + mainprogram = MockMain() + mainprogram.start() + + +if __name__ == "__main__": + main() diff --git a/src/mock/images b/src/mock/images new file mode 120000 index 00000000..847b03ed --- /dev/null +++ b/src/mock/images @@ -0,0 +1 @@ +../../images/ \ No newline at end of file diff --git a/src/mock/keys.dat b/src/mock/keys.dat new file mode 100644 index 00000000..d4db91d5 --- /dev/null +++ b/src/mock/keys.dat @@ -0,0 +1,6 @@ +[BM-2cUgQGcTLWAkC6dNsv2Bc8XB3Y1GEesVLV] +label = adfsdf +enabled = true +privsigningkey = 5KWXwYq1oJMzghUSJaJoWPn8VdeBbhDN8zFot1cBd6ezKKReqBd +privencryptionkey = 5JaeFJs8iPcQT3N8676r3gHKvJ5mTWXy1VLhGCEDqRs4vpvpxV8 + diff --git a/src/mock/mockbitmessagekivy/__init__.py b/src/mock/mockbitmessagekivy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/mock/mockbitmessagekivy/addresses.py b/src/mock/mockbitmessagekivy/addresses.py new file mode 120000 index 00000000..88fcee82 --- /dev/null +++ b/src/mock/mockbitmessagekivy/addresses.py @@ -0,0 +1 @@ +../../../addresses.py \ No newline at end of file diff --git a/src/mock/mockbitmessagekivy/bmconfigparser.py b/src/mock/mockbitmessagekivy/bmconfigparser.py new file mode 100644 index 00000000..618b5792 --- /dev/null +++ b/src/mock/mockbitmessagekivy/bmconfigparser.py @@ -0,0 +1,280 @@ +# pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument, no-else-return, unused-variable +# pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation, attribute-defined-outside-init +# pylint: disable=protected-access +# pylint: disable=import-outside-toplevel,ungrouped-imports,wrong-import-order,unused-import,arguments-differ +# pylint: disable=invalid-name,unnecessary-comprehension,broad-except,simplifiable-if-expression,no-member +# pylint: disable=too-many-return-statements + +""" +BMConfigParser class definition and default configuration settings +""" + +import os +import shutil +import sys # FIXME: bad style! write more generally +from datetime import datetime + +from six import string_types +from six.moves import configparser + +try: + import state + from singleton import Singleton +except ImportError: + from pybitmessage import state + from pybitmessage.singleton import Singleton + +SafeConfigParser = configparser.SafeConfigParser + + +BMConfigDefaults = { + "bitmessagesettings": { + "maxaddrperstreamsend": 500, + "maxbootstrapconnections": 20, + "maxdownloadrate": 0, + "maxoutboundconnections": 8, + "maxtotalconnections": 200, + "maxuploadrate": 0, + "apiinterface": "127.0.0.1", + "apiport": 8442, + "udp": "True" + }, + "threads": { + "receive": 3, + }, + "network": { + "bind": "", + "dandelion": 90, + }, + "inventory": { + "storage": "sqlite", + "acceptmismatch": "False", + }, + "knownnodes": { + "maxnodes": 20000, + }, + "zlib": { + "maxsize": 1048576 + } +} + + +@Singleton +class BMConfigParser(SafeConfigParser): + """ + Singleton class inherited from :class:`ConfigParser.SafeConfigParser` + with additional methods specific to bitmessage config. + """ + # pylint: disable=too-many-ancestors + _temp = {} + + def set(self, section, option, value=None): + if self._optcre is self.OPTCRE or value: + if not isinstance(value, string_types): + raise TypeError("option values must be strings") + if not self.validate(section, option, value): + raise ValueError("Invalid value %s" % value) + return SafeConfigParser.set(self, section, option, value) + + # pylint: disable=redefined-builtinm, too-many-return-statements + def get(self, section, option, raw=False, vars=None): + if sys.version_info[0] == 3: + # pylint: disable=arguments-differ + try: + if section == "bitmessagesettings" and option == "timeformat": + return SafeConfigParser.get( + self, section, option, raw=True, vars=vars) + try: + return self._temp[section][option] + except KeyError: + pass + return SafeConfigParser.get( + self, section, option, raw=True, vars=vars) + except configparser.InterpolationError: + return SafeConfigParser.get( + self, section, option, raw=True, vars=vars) + except (configparser.NoSectionError, configparser.NoOptionError) as e: + try: + return BMConfigDefaults[section][option] + except (KeyError, ValueError, AttributeError): + raise e + else: + # pylint: disable=arguments-differ + try: + if section == "bitmessagesettings" and option == "timeformat": + return SafeConfigParser.get( + self, section, option, raw, vars) + try: + return self._temp[section][option] + except KeyError: + pass + return SafeConfigParser.get( + self, section, option, True, vars) + except configparser.InterpolationError: + return SafeConfigParser.get( + self, section, option, True, vars) + except (configparser.NoSectionError, configparser.NoOptionError) as e: + try: + return BMConfigDefaults[section][option] + except (KeyError, ValueError, AttributeError): + raise e + + def setTemp(self, section, option, value=None): + """Temporary set option to value, not saving.""" + try: + self._temp[section][option] = value + except KeyError: + self._temp[section] = {option: value} + + def safeGetBoolean(self, section, field): + """Return value as boolean, False on exceptions""" + try: + # Used in the python2.7 + # return self.getboolean(section, field) + # Used in the python3.5.2 + # print(config, section, field) + return self.getboolean(section, field) + except (configparser.NoSectionError, configparser.NoOptionError, + ValueError, AttributeError): + return False + + def safeGetInt(self, section, field, default=0): + """Return value as integer, default on exceptions, + 0 if default missing""" + try: + # Used in the python2.7 + # return self.getint(section, field) + # Used in the python3.7.0 + return int(self.get(section, field)) + except (configparser.NoSectionError, configparser.NoOptionError, + ValueError, AttributeError): + return default + + def safeGetFloat(self, section, field, default=0.0): + """Return value as float, default on exceptions, + 0.0 if default missing""" + try: + return self.getfloat(section, field) + except (configparser.NoSectionError, configparser.NoOptionError, + ValueError, AttributeError): + return default + + def safeGet(self, section, option, default=None): + """Return value as is, default on exceptions, None if default missing""" + try: + return self.get(section, option) + except (configparser.NoSectionError, configparser.NoOptionError, + ValueError, AttributeError): + return default + + def items(self, section, raw=False, variables=None): + # pylint: disable=signature-differs + """Return section variables as parent, + but override the "raw" argument to always True""" + return SafeConfigParser.items(self, section, True, variables) + + def _reset(self): + """Reset current config. There doesn't appear to be a built in + method for this""" + sections = self.sections() + for x in sections: + self.remove_section(x) + + if sys.version_info[0] == 3: + @staticmethod + def addresses(hidden=False): + """Return a list of local bitmessage addresses (from section labels)""" + return [x for x in BMConfigParser().sections() if x.startswith('BM-') and ( + hidden or not BMConfigParser().safeGetBoolean(x, 'hidden'))] + + def read(self, filenames): + self._reset() + SafeConfigParser.read(self, filenames) + for section in self.sections(): + for option in self.options(section): + try: + # pylint: disable=unsubscriptable-object + if not self.validate( + section, option, + self[section][option] + ): + try: + newVal = BMConfigDefaults[section][option] + except configparser.NoSectionError: + continue + except KeyError: + continue + SafeConfigParser.set( + self, section, option, newVal) + except configparser.InterpolationError: + continue + + def readfp(self, fp, filename=None): + # pylint: disable=no-member + SafeConfigParser.read_file(self, fp) + else: + @staticmethod + def addresses(): + """Return a list of local bitmessage addresses (from section labels)""" + return [ + x for x in BMConfigParser().sections() if x.startswith('BM-')] + + def read(self, filenames): + """Read config and populate defaults""" + self._reset() + SafeConfigParser.read(self, filenames) + for section in self.sections(): + for option in self.options(section): + try: + if not self.validate( + section, option, + SafeConfigParser.get(self, section, option) + ): + try: + newVal = BMConfigDefaults[section][option] + except KeyError: + continue + SafeConfigParser.set( + self, section, option, newVal) + except configparser.InterpolationError: + continue + + def save(self): + """Save the runtime config onto the filesystem""" + fileName = os.path.join(state.appdata, 'keys.dat') + fileNameBak = '.'.join([ + fileName, datetime.now().strftime("%Y%j%H%M%S%f"), 'bak']) + # create a backup copy to prevent the accidental loss due to + # the disk write failure + try: + shutil.copyfile(fileName, fileNameBak) + # The backup succeeded. + fileNameExisted = True + except (IOError, Exception): + # The backup failed. This can happen if the file + # didn't exist before. + fileNameExisted = False + + with open(fileName, 'w') as configfile: + self.write(configfile) + # delete the backup + if fileNameExisted: + os.remove(fileNameBak) + + def validate(self, section, option, value): + """Input validator interface (using factory pattern)""" + try: + return getattr(self, 'validate_%s_%s' % (section, option))(value) + except AttributeError: + return True + + @staticmethod + def validate_bitmessagesettings_maxoutboundconnections(value): + """Reject maxoutboundconnections that are too high or too low""" + try: + value = int(value) + except ValueError: + return False + if value < 0 or value > 8: + return False + return True diff --git a/src/mock/mockbitmessagekivy/class_addressGenerator.py b/src/mock/mockbitmessagekivy/class_addressGenerator.py new file mode 100644 index 00000000..ebc2343e --- /dev/null +++ b/src/mock/mockbitmessagekivy/class_addressGenerator.py @@ -0,0 +1,79 @@ +""" +A thread for creating addresses +""" + +from six.moves import queue + +from pybitmessage import state +from pybitmessage import queues + +from pybitmessage.bmconfigparser import BMConfigParser + +from pybitmessage.network.threads import StoppableThread + + +fake_addresses = { + 'BM-2cUgQGcTLWAkC6dNsv2Bc8XB3Y1GEesVLV': { + 'privsigningkey': '5KWXwYq1oJMzghUSJaJoWPn8VdeBbhDN8zFot1cBd6ezKKReqBd', + 'privencryptionkey': '5JaeFJs8iPcQT3N8676r3gHKvJ5mTWXy1VLhGCEDqRs4vpvpxV8' + }, + 'BM-2cUd2dm8MVMokruMTcGhhteTpyRZCAMhnA': { + 'privsigningkey': '5JnJ79nkcwjo4Aj7iG8sFMkzYoQqWfpUjTcitTuFJZ1YKHZz98J', + 'privencryptionkey': '5JXgNzTRouFLqSRFJvuHMDHCYPBvTeMPBiHt4Jeb6smNjhUNTYq' + }, + 'BM-2cWyvL54WytfALrJHZqbsDHca5QkrtByAW': { + 'privsigningkey': '5KVE4gLmcfYVicLdgyD4GmnbBTFSnY7Yj2UCuytQqgBBsfwDhpi', + 'privencryptionkey': '5JTw48CGm5CP8fyJUJQMq8HQANQMHDHp2ETUe1dgm6EFpT1egD7' + }, + 'BM-2cTE65PK9Y4AQEkCZbazV86pcQACocnRXd': { + 'privsigningkey': '5KCuyReHx9MB4m5hhEyCWcLEXqc8rxhD1T2VWk8CicPFc8B6LaZ', + 'privencryptionkey': '5KBRpwXdX3n2tP7f583SbFgfzgs6Jemx7qfYqhdH7B1Vhe2jqY6' + }, + 'BM-2cX5z1EgmJ87f2oKAwXdv4VQtEVwr2V3BG': { + 'privsigningkey': '5K5UK7qED7F1uWCVsehudQrszLyMZxFVnP6vN2VDQAjtn5qnyRK', + 'privencryptionkey': '5J5coocoJBX6hy5DFTWKtyEgPmADpSwfQTazMpU7QPeART6oMAu' + } +} + + +class addressGenerator(StoppableThread): + """A thread for creating fake addresses""" + name = "addressGenerator" + address_list = list(fake_addresses.keys()) + + def stopThread(self): + """"To stop address generator thread""" + try: + queues.addressGeneratorQueue.put(("stopThread", "data")) + except queue.Full: + self.logger.warning('addressGeneratorQueue is Full') + super(addressGenerator, self).stopThread() + + def run(self): + """ + Process the requests for addresses generation + from `.queues.addressGeneratorQueue` + """ + while state.shutdown == 0: + queueValue = queues.addressGeneratorQueue.get() + try: + address = self.address_list.pop(0) + print("queueValue: ", queueValue) + if len(queueValue) >= 3: + label = queueValue[3] + else: + label = '' + + BMConfigParser().add_section(address) + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set( + address, 'privsigningkey', fake_addresses[address]['privsigningkey']) + BMConfigParser().set( + address, 'privencryptionkey', fake_addresses[address]['privencryptionkey']) + BMConfigParser().save() + + queues.addressGeneratorQueue.task_done() + except IndexError: + self.logger.error( + 'Program error: you can only create 5 fake addresses') diff --git a/src/mock/mockbitmessagekivy/get_platform.py b/src/mock/mockbitmessagekivy/get_platform.py new file mode 100644 index 00000000..e4fea889 --- /dev/null +++ b/src/mock/mockbitmessagekivy/get_platform.py @@ -0,0 +1,48 @@ +from sys import platform as _sys_platform +from os import environ + +""" +We need to check platform and set environ for KIVY_CAMERA, if requires, before importing kivy. + +We cannot use sys.platform directly because it returns 'linux' on android devices as well. +We cannot use kivy.util.platform beacuse it imports kivy beforehand and thus setting environ +after that doesn't make any sense. + +So we needed to copy the `_get_platform` function from kivy.utils +""" + + +def _get_platform(): + # On Android sys.platform returns 'linux2', so prefer to check the + # existence of environ variables set during Python initialization + kivy_build = environ.get("KIVY_BUILD", "") + if kivy_build in {"android", "ios"}: + return kivy_build + elif "P4A_BOOTSTRAP" in environ: + return "android" + elif "ANDROID_ARGUMENT" in environ: + # We used to use this method to detect android platform, + # leaving it here to be backwards compatible with `pydroid3` + # and similar tools outside kivy's ecosystem + return "android" + elif _sys_platform in ("win32", "cygwin"): + return "win" + elif _sys_platform == "darwin": + return "macosx" + elif _sys_platform.startswith("linux"): + return "linux" + elif _sys_platform.startswith("freebsd"): + return "linux" + return "unknown" + +platform = _get_platform() + +if platform not in ("android", "unknown"): + """ + After tweaking a little bit with opencv camera, it's possible to make camera + go on and off as required while the app is still running. + + Other camera provider such as `gi` has some issue upon closing the camera. + by setting KIVY_CAMERA environment variable before importing kivy, we are forcing it to use opencv camera provider. + """ + environ["KIVY_CAMERA"] = "opencv" diff --git a/src/mock/mockbitmessagekivy/inventory.py b/src/mock/mockbitmessagekivy/inventory.py new file mode 100644 index 00000000..6173c3cd --- /dev/null +++ b/src/mock/mockbitmessagekivy/inventory.py @@ -0,0 +1,15 @@ +"""The Inventory singleton""" + +# TODO make this dynamic, and watch out for frozen, like with messagetypes +from pybitmessage.singleton import Singleton + + +# pylint: disable=old-style-class,too-few-public-methods +@Singleton +class Inventory(): + """ + Inventory singleton class which uses storage backends + to manage the inventory. + """ + def __init__(self): + self.numberOfInventoryLookupsPerformed = 0 diff --git a/src/mock/mockbitmessagekivy/kivy_state.py b/src/mock/mockbitmessagekivy/kivy_state.py new file mode 100644 index 00000000..0013a50c --- /dev/null +++ b/src/mock/mockbitmessagekivy/kivy_state.py @@ -0,0 +1,72 @@ +""" +src/state.py +================================= +""" +import collections + + +# Network protocols availability, initialised below +networkProtocolAvailability = None + +sqlReady = False # set to true by sqlTread when ready for processing + +trustedPeer = None +Peer = collections.namedtuple('Peer', ['host', 'port']) + + +def resetNetworkProtocolAvailability(): + """This method helps to reset the availability of network protocol""" + # pylint: disable=global-statement + global networkProtocolAvailability + networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} + + +resetNetworkProtocolAvailability() + +association = '' + +navinstance = None + +mail_id = 0 + +myAddressObj = None + +detailPageType = None + +ackdata = None + +status = None + +screen_density = None + +msg_counter_objs = None + +check_sent_acc = None + +sent_count = 0 + +inbox_count = 0 + +trash_count = 0 + +draft_count = 0 + +all_count = 0 + +searcing_text = '' + +search_screen = '' + +send_draft_mail = None + +is_allmail = False + +in_composer = False + +availabe_credit = 0 + +in_sent_method = False + +in_search_mode = False + +imageDir = None diff --git a/src/mock/mockbitmessagekivy/kv b/src/mock/mockbitmessagekivy/kv new file mode 120000 index 00000000..6276c558 --- /dev/null +++ b/src/mock/mockbitmessagekivy/kv @@ -0,0 +1 @@ +../../../../../PyBitmessage/src/bitmessagekivy/kv \ No newline at end of file diff --git a/src/mock/mockbitmessagekivy/main.kv b/src/mock/mockbitmessagekivy/main.kv new file mode 100644 index 00000000..40adbe70 --- /dev/null +++ b/src/mock/mockbitmessagekivy/main.kv @@ -0,0 +1,422 @@ +#:import IconLeftWidget kivymd.uix.list.IconLeftWidget +#:import images_path kivymd.images_path +#:import Spinner kivy.uix.spinner.Spinner +#:import Factory kivy.factory.Factory + +#:import MDCheckbox kivymd.uix.selectioncontrol.MDCheckbox +#:import MDList kivymd.uix.list.MDList +#:import OneLineListItem kivymd.uix.list.OneLineListItem +#:import MDTextField kivymd.uix.textfield.MDTextField +#:import get_color_from_hex kivy.utils.get_color_from_hex +#:import MDCard kivymd.uix.card.MDCard +#:import colors kivymd.color_definitions.colors +#:import MDTabs kivymd.uix.tab.MDTabs +#:import MDFloatingActionButton kivymd.uix.button.MDFloatingActionButton +#:import Factory kivy.factory.Factory +#:import MDScrollViewRefreshLayout kivymd.uix.refreshlayout.MDScrollViewRefreshLayout +#:import MDSpinner kivymd.uix.spinner.MDSpinner +#:import MDTabsBase kivymd.uix.tab.MDTabsBase +##:import ZBarSymbol pyzbar.pyzbar.ZBarSymbol + + +#:set color_button (0.784, 0.443, 0.216, 1) # brown +#:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown +#:set color_font (0.957, 0.890, 0.843, 1) # off white + +: + font_size: '12.5sp' + #background_color: color_button if self.state == 'down' else color_button_pressed + #background_down: 'atlas://data/images/defaulttheme/button' + background_normal: 'atlas://data/images/defaulttheme/textinput_active' + background_color: app.theme_cls.primary_color + # text_autoupdate: True + color: color_font + + + #on_press: root.active = not root.active + on_press: root.currentlyActive() + active_color: root.theme_cls.primary_color if root.active else root.theme_cls.text_color + + IconLeftWidget: + icon: root.icon + theme_text_color: "Custom" + text_color: root.active_color + + BadgeText: + id: badge_txt + text: f"{root.badge_text}" + theme_text_color: "Custom" + #text_color: root.active_color + halign: 'right' + +: + canvas: + Color: + rgba: self.theme_cls.divider_color + Line: + points: root.x, root.y + dp(8), root.x + self.width, root.y + dp(8) + + + + BoxLayout: + orientation: 'vertical' + + FloatLayout: + size_hint_y: None + height: "200dp" + + MDIconButton: + id: reset_image + icon: "refresh" + x: root.parent.x + dp(10) + pos_hint: {"top": 1, 'left': 1} + color: [1,0,0,1] + on_release: app.rest_default_avatar_img() + theme_text_color: "Custom" + text_color: app.theme_cls.primary_color + # opacity: 1 if app.current_address_label() else 0 + # disabled: False if app.current_address_label() else True + opacity: 0 + disabled: True + + MDIconButton: + id: file_manager + icon: "file-image" + x: root.parent.x + dp(10) + pos_hint: {"top": 1, 'right': 1} + color: [1,0,0,1] + on_release: app.file_manager_open() + # md_bg_color: app.theme_cls.primary_color + theme_text_color: "Custom" + text_color: app.theme_cls.primary_color + opacity: 1 if app.current_address_label() else 0 + disabled: False if app.current_address_label() else True + + BoxLayout: + id: top_box + size_hint_y: None + height: "200dp" + #padding: "10dp" + x: root.parent.x + pos_hint: {"top": 1} + Image: + #source: './images/drawer_logo1.png' + source: app.get_default_logo(self) + + ScrollView: + id: scroll_y + pos_hint: {"top": 1} + + GridLayout: + id: box_item + cols: 1 + size_hint_y: None + height: self.minimum_height + NavigationDrawerDivider: + NavigationDrawerSubheader: + text: app.tr._('Accounts') + #text: app.tr._('Hello World') + height:"35dp" + NavigationItem: + # size: 50,50 + height: dp(48) + CustomSpinner: + id: btn + pos_hint:{"x":0,"y":0} + option_cls: Factory.get("MySpinnerOption") + font_size: '12.5sp' + text: app.getDefaultAccData(self) + color: color_font + background_normal: '' + background_color: app.theme_cls.primary_color + on_text:app.getCurrentAccountData(self.text) + ArrowImg: + NavigationItem: + id: inbox_cnt + text: app.tr._('Inbox') + #text: app.tr._('Hello World') + icon: 'email-open' + divider: None + on_release: app.root.ids.scr_mngr.current = 'inbox' + on_release: root.parent.set_state() + on_press: app.load_screen(self) + NavigationItem: + id: send_cnt + text: app.tr._('Sent') + icon: 'send' + divider: None + on_release: app.root.ids.scr_mngr.current = 'sent' + on_release: root.parent.set_state() + NavigationItem: + id: draft_cnt + text: app.tr._('Draft') + icon: 'message-draw' + divider: None + on_release: app.root.ids.scr_mngr.current = 'draft' + on_release: root.parent.set_state() + NavigationItem: + id: trash_cnt + text: app.tr._('Trash') + icon: 'delete' + divider: None + on_release: app.root.ids.scr_mngr.current = 'trash' + on_press: root.parent.set_state() + on_press: app.load_screen(self) + NavigationItem: + id: allmail_cnt + text: app.tr._('All Mails') + icon: 'mailbox' + divider: None + on_release: app.root.ids.scr_mngr.current = 'allmails' + on_release: root.parent.set_state() + on_press: app.load_screen(self) + # NavigationItem: + # id: chat_rm + # text: app.tr._('Chat Room') + # icon: 'wechat' + # divider: None + # on_release: app.root.ids.scr_mngr.current = 'chlist' + # on_release: root.parent.set_state() + NavigationDrawerDivider: + NavigationDrawerSubheader: + text: app.tr._("All labels") + NavigationItem: + text: app.tr._('Address Book') + icon: 'book-multiple' + divider: None + on_release: app.root.ids.scr_mngr.current = 'addressbook' + on_release: root.parent.set_state() + NavigationItem: + text: app.tr._('Settings') + icon: 'application-settings' + divider: None + on_release: app.root.ids.scr_mngr.current = 'set' + on_release: root.parent.set_state() + NavigationItem: + text: app.tr._('Purchase') + icon: 'shopping' + divider: None + on_release: app.root.ids.scr_mngr.current = 'payment' + on_release: root.parent.set_state() + # NavigationItem: + # text: app.tr._('Credits') + # icon: 'wallet' + # divider: None + # on_release: app.root.ids.scr_mngr.current = 'credits' + # on_release: root.parent.set_state() + NavigationItem: + text: app.tr._('New address') + icon: 'account-plus' + divider: None + on_release: app.root.ids.scr_mngr.current = 'login' + on_release: root.parent.set_state() + on_press: app.reset_login_screen() + NavigationItem: + text: app.tr._('Network status') + icon: 'server-network' + divider: None + on_release: app.root.ids.scr_mngr.current = 'networkstat' + on_release: root.parent.set_state() + NavigationItem: + text: app.tr._('My addresses') + icon: 'account-multiple' + divider: None + on_release: app.root.ids.scr_mngr.current = 'myaddress' + on_release: root.parent.set_state() + +MDNavigationLayout: + id: nav_layout + + MDToolbar: + id: toolbar + title: app.current_address_label() + opacity: 1 if app.addressexist() else 0 + disabled: False if app.addressexist() else True + pos_hint: {"top": 1} + md_bg_color: app.theme_cls.primary_color + elevation: 10 + left_action_items: [['menu', lambda x: nav_drawer.set_state("toggle")]] + right_action_items: [['account-plus', lambda x: app.addingtoaddressbook()]] + + ScreenManager: + id: scr_mngr + size_hint_y: None + height: root.height - toolbar.height + Inbox: + id:sc1 +# # Page: +# # id:sc2 + Create: + id:sc3 + Sent: + id:sc4 + Trash: + id:sc5 + Login: + id:sc6 + Random: + id:sc7 + # Spam: + # id:sc8 + Setting: + id:sc9 + MyAddress: + id:sc10 + AddressBook: + id:sc11 + Payment: + id:sc12 + NetworkStat: + id:sc13 + MailDetail: + id:sc14 + ShowQRCode: + id:sc15 + Draft: + id:sc16 + Allmails: + id:sc17 + # Credits: + # id:sc18 + # Starred: + # id:sc19 + # Archieve: + # id:sc20 + # ChatRoom: + # id:sc21 + # ChatList: + # id:sc22 + ScanScreen: + id:sc23 + + MDNavigationDrawer: + id: nav_drawer + + ContentNavigationDrawer: + id: content_drawer + + +: + source: app.image_path +('/down-arrow.png' if self.parent.is_open == True else '/right-arrow.png') + size: 15, 15 + x: self.parent.x + self.parent.width - self.width - 5 + y: self.parent.y + self.parent.height/2 - self.height + 5 + + +: + # id: search_bar + size_hint_y: None + height: self.minimum_height + + MDIconButton: + icon: 'magnify' + + MDTextField: + id: search_field + hint_text: 'Search' + on_text: app.searchQuery(self) + canvas.before: + Color: + rgba: (0,0,0,1) + + +: + id: spinner + size_hint: None, None + size: dp(46), dp(46) + pos_hint: {'center_x': 0.5, 'center_y': 0.5} + active: False + +: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} + + Widget: + + MDFloatingActionButton: + icon: 'plus' + opposite_colors: True + elevation_normal: 8 + md_bg_color: [0.941, 0, 0,1] + on_press: app.root.ids.scr_mngr.current = 'create' + on_press: app.clear_composer() + + +: + size_hint_y: None + height: content.height + + MDCardSwipeLayerBox: + padding: "8dp" + + MDIconButton: + id: delete_msg + icon: "trash-can" + pos_hint: {"center_y": .5} + md_bg_color: (1, 0, 0, 1) + disabled: True + + MDCardSwipeFrontBox: + + TwoLineAvatarIconListItem: + id: content + text: root.text + _no_ripple_effect: True + + AvatarSampleWidget: + id: avater_img + # source: './images/kivy/avatar.png' + source: None + + TimeTagRightSampleWidget: + id: time_tag + text: '' + font_size: "11sp" + font_style: "Caption" + size: [120, 140] if app.app_platform == "android" else [64, 80] + + +: + size_hint_y: None + height: content.height + + MDCardSwipeLayerBox: + padding: "8dp" + + MDIconButton: + id: delete_msg + icon: "trash-can" + pos_hint: {"center_y": .5} + md_bg_color: (1, 0, 0, 1) + disabled: True + + MDCardSwipeFrontBox: + + TwoLineAvatarIconListItem: + id: content + text: root.text + _no_ripple_effect: True + + AvatarSampleWidget: + id: avater_img + # source: './images/kivy/avatar.png' + source: None + + TimeTagRightSampleWidget: + id: time_tag + text: 'time' + font_size: "11sp" + font_style: "Caption" + size: [120, 140] if app.app_platform == "android" else [64, 80] + MDChip: + id: chip_tag + size_hint: (0.16 if app.app_platform == "android" else 0.08, None) + text: 'test' + icon: "" + pos_hint: {"center_x": 0.91 if app.app_platform == "android" else 0.94, "center_y": 0.3} + # height: dp(18) + height: '18dp' + text_color: (1,1,1,1) + radius: [8] diff --git a/src/mock/mockbitmessagekivy/network/__init__.py b/src/mock/mockbitmessagekivy/network/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/mock/mockbitmessagekivy/network/threads.py b/src/mock/mockbitmessagekivy/network/threads.py new file mode 120000 index 00000000..c95b4c36 --- /dev/null +++ b/src/mock/mockbitmessagekivy/network/threads.py @@ -0,0 +1 @@ +../../../../network/threads.py \ No newline at end of file diff --git a/src/mock/mockbitmessagekivy/queues.py b/src/mock/mockbitmessagekivy/queues.py new file mode 100644 index 00000000..64b553a1 --- /dev/null +++ b/src/mock/mockbitmessagekivy/queues.py @@ -0,0 +1,55 @@ +# pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument +# pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation +# pylint: disable=protected-access +# pylint: disable=import-outside-toplevel,ungrouped-imports,wrong-import-order,unused-import,arguments-differ +# pylint: disable=invalid-name,unnecessary-comprehension,broad-except,simplifiable-if-expression,no-member +# pylint: disable=too-many-return-statements + +"""Most of the queues used by bitmessage threads are defined here.""" + +import threading +import time + +from six.moves import queue + + +class ObjectProcessorQueue(queue.Queue): + """Special queue class using lock for `.threads.objectProcessor`""" + + maxSize = 32000000 + + def __init__(self): + queue.Queue.__init__(self) + self.sizeLock = threading.Lock() + #: in Bytes. We maintain this to prevent nodes from flooding us + #: with objects which take up too much memory. If this gets + #: too big we'll sleep before asking for further objects. + self.curSize = 0 + + def put(self, item, block=True, timeout=None): + while self.curSize >= self.maxSize: + time.sleep(1) + with self.sizeLock: + self.curSize += len(item[1]) + queue.Queue.put(self, item, block, timeout) + + def get(self, block=True, timeout=None): + item = queue.Queue.get(self, block, timeout) + with self.sizeLock: + self.curSize -= len(item[1]) + return item + + +workerQueue = queue.Queue() +UISignalQueue = queue.Queue() +addressGeneratorQueue = queue.Queue() +#: `.network.ReceiveQueueThread` instances dump objects they hear +#: on the network into this queue to be processed. +objectProcessorQueue = ObjectProcessorQueue() +portCheckerQueue = queue.Queue() +receiveDataQueue = queue.Queue() +#: The address generator thread uses this queue to get information back +#: to the API thread. +apiAddressGeneratorReturnQueue = queue.Queue() +#: for exceptions +excQueue = queue.Queue() diff --git a/src/mock/mockbitmessagekivy/screens_data.json b/src/mock/mockbitmessagekivy/screens_data.json new file mode 100644 index 00000000..e9bba36e --- /dev/null +++ b/src/mock/mockbitmessagekivy/screens_data.json @@ -0,0 +1,78 @@ +{ + "Inbox": { + "kv_string": "inbox", + "name_screen": "inbox", + "Import": "from baseclass.inbox import Inbox", + }, + "Sent": { + "kv_string": "sent", + "name_screen": "sent", + "Import": "from baseclass.sent import Sent", + }, + "Draft": { + "kv_string": "draft", + "name_screen": "draft", + "Import": "from baseclass.draft import Draft", + }, + "Trash": { + "kv_string": "trash", + "name_screen": "trash", + "Import": "from baseclass.trash import Trash", + }, + "All Mails": { + "kv_string": "allmails", + "name_screen": "allmails", + "Import": "from baseclass.allmail import Allmails", + }, + "Address Book": { + "kv_string": "addressbook", + "name_screen": "addressbook", + "Import": "from baseclass.addressbook import AddressBook", + }, + "Settings": { + "kv_string": "settings", + "name_screen": "set", + "Import": "from baseclass.settings import Setting", + }, + "Payment": { + "kv_string": "payment", + "name_screen": "payment", + "Import": "from baseclass.payment import Payment", + }, + "Network status": { + "kv_string": "network", + "name_screen": "networkstat", + "Import": "from baseclass.network import NetworkStat", + }, + "My addresses": { + "kv_string": "myaddress", + "name_screen": "myaddress", + "Import": "from baseclass.myaddress import MyAddress", + }, + "MailDetail": { + "kv_string": "maildetail", + "name_screen": "mailDetail", + "Import": "from baseclass.maildetail import MailDetail", + }, + "Create": { + "kv_string": "msg_composer", + "name_screen": "create", + "Import": "from baseclass.msg_composer import Create", + }, + "Login": { + "kv_string": "login", + "Import": "from baseclass.login import *", + }, + "Scanner": { + "kv_string": "scan_screen", + "Import": "from baseclass.scan_screen import ScanScreen", + }, + "Popups": { + "kv_string": "popup", + "Import": "from baseclass.popup import *", + }, + "Qrcode": { + "kv_string": "qrcode", + "Import": "from baseclass.qrcode import ShowQRCode", + }, +} diff --git a/src/mock/mockbitmessagekivy/shutdown.py b/src/mock/mockbitmessagekivy/shutdown.py new file mode 100644 index 00000000..c9118017 --- /dev/null +++ b/src/mock/mockbitmessagekivy/shutdown.py @@ -0,0 +1,24 @@ +# pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument +# pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation +# pylint: disable=protected-access +# pylint: disable=import-outside-toplevel,ungrouped-imports,wrong-import-order,unused-import,arguments-differ +# pylint: disable=invalid-name,unnecessary-comprehension,broad-except,simplifiable-if-expression,no-member +# pylint: disable=too-many-return-statements + +"""shutdown function""" + +import queue as Queue +import threading +import time + +from pybitmessage import state +from pybitmessage.network.threads import StoppableThread +from pybitmessage.queues import ( + addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue) + + +def doCleanShutdown(): + """ + Used to exit Kivy UI. + """ + state.shutdown = 1 diff --git a/src/mock/mockbitmessagekivy/singleton.py b/src/mock/mockbitmessagekivy/singleton.py new file mode 120000 index 00000000..5e112567 --- /dev/null +++ b/src/mock/mockbitmessagekivy/singleton.py @@ -0,0 +1 @@ +../../../singleton.py \ No newline at end of file diff --git a/src/mock/mockbitmessagekivy/state.py b/src/mock/mockbitmessagekivy/state.py new file mode 100644 index 00000000..62848c25 --- /dev/null +++ b/src/mock/mockbitmessagekivy/state.py @@ -0,0 +1,133 @@ +""" +src/state.py +================================= +""" +import collections + +neededPubkeys = {} +streamsInWhichIAmParticipating = [] +# For UPnP +extPort = None +# for Tor hidden service +socksIP = None +# Network protocols availability, initialised below +networkProtocolAvailability = None +appdata = '' # holds the location of the application data storage directory +# Set to 1 by the doCleanShutdown function. +# Used to tell the proof of work worker threads to exit. +shutdown = 0 +# Component control flags - set on startup, do not change during runtime +# The defaults are for standalone GUI (default operating mode) +enableNetwork = True # enable network threads +enableObjProc = True # enable object processing threads +enableAPI = True # enable API (if configured) +enableGUI = True # enable GUI (QT or ncurses) +enableSTDIO = False # enable STDIO threads +curses = False +sqlReady = False # set to true by sqlTread when ready for processing +maximumNumberOfHalfOpenConnections = 0 + +maximumLengthOfTimeToBotherResendingMessages = 0 + +invThread = None +addrThread = None +downloadThread = None +uploadThread = None +ownAddresses = {} +# If the trustedpeer option is specified in keys.dat then this will +# contain a Peer which will be connected to instead of using the +# addresses advertised by other peers. The client will only connect to +# this peer and the timing attack mitigation will be disabled in order +# to download data faster. The expected use case is where the user has +# a fast connection to a trusted server where they run a BitMessage +# daemon permanently. If they then run a second instance of the client +# on a local machine periodically when they want to check for messages +# it will sync with the network a lot faster without compromising +# security. +trustedPeer = None +discoveredPeers = {} +Peer = collections.namedtuple('Peer', ['host', 'port']) + + +def resetNetworkProtocolAvailability(): + """This method helps to reset the availability of network protocol""" + # pylint: disable=global-statement + global networkProtocolAvailability + networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} + + +resetNetworkProtocolAvailability() + +dandelion = 0 + +testmode = False + +kivy = False + +association = '' + +kivyapp = None + +navinstance = None + +mail_id = 0 + +myAddressObj = None + +detailPageType = None + +ackdata = None + +status = None + +screen_density = None + +msg_counter_objs = None + +check_sent_acc = None + +sent_count = 0 + +inbox_count = 0 + +trash_count = 0 + +draft_count = 0 + +all_count = 0 + +searcing_text = '' + +search_screen = '' + +send_draft_mail = None + +is_allmail = False + +in_composer = False + +availabe_credit = 0 + +in_sent_method = False + +in_search_mode = False + +clientHasReceivedIncomingConnections = False +"""used by API command clientStatus""" + +numberOfMessagesProcessed = 0 +numberOfBroadcastsProcessed = 0 +numberOfPubkeysProcessed = 0 + +statusIconColor = 'red' +""" +GUI status icon color +.. note:: bad style, refactor it +""" + +ackdataForWhichImWatching = {} + +thisapp = None +"""Singleton instance""" + +imageDir = None