From 92c0196887eb81f9b2b2c6c71315fe7047c3faa1 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 1 Aug 2019 13:19:56 +0300 Subject: [PATCH 001/306] Add self peer into knownnodes if detected external IP with UPnP --- src/upnp.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index da075c65..d4ffce36 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -16,6 +16,7 @@ from random import randint from urlparse import urlparse from xml.dom.minidom import Document, parseString +import knownnodes import queues import state import tr @@ -166,9 +167,11 @@ class Router: # pylint: disable=old-style-class def GetExternalIPAddress(self): """Get the external address""" - resp = self.soapRequest(self.upnp_schema + ':1', 'GetExternalIPAddress') - dom = parseString(resp) - return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data + resp = self.soapRequest( + self.upnp_schema + ':1', 'GetExternalIPAddress') + dom = parseString(resp.read()) + return dom.getElementsByTagName( + 'NewExternalIPAddress')[0].childNodes[0].data def soapRequest(self, service, action, arguments=None): """Make a request to a router""" @@ -261,6 +264,17 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Found UPnP router at %s", ip) self.routers.append(newRouter) self.createPortMapping(newRouter) + try: + self_peer = state.Peer( + newRouter.GetExternalIPAddress(), + self.extPort + ) + except: + logger.debug('Failed to get external IP') + else: + with knownnodes.knownNodesLock: + knownnodes.addKnownNode( + 1, self_peer, is_self=True) queues.UISignalQueue.put(('updateStatusBar', tr._translate( "MainWindow", 'UPnP port mapping established on port %1' ).arg(str(self.extPort)))) From 78636c468ef26e4849140ef7d3864bbb66004c90 Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 15:42:41 +0530 Subject: [PATCH 002/306] Implement new feature for back button for screen tracking back with keyboard event attach --- src/bitmessagekivy/main.kv | 11 ++++++++++- src/bitmessagekivy/mpybit.py | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index ea8936c5..1d86c133 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -54,7 +54,16 @@ BoxLayout: size_hint_x: 0.1 pos_hint: {'x': 0.8, 'y':0.4} on_press: app.say_exit() - + ActionBar: + size_hint_y: 0.4 + size_hint_x: 0.1 + pos_hint: {'x': 0.99, 'y':0.35} + background_color: (0,0,0,0) + ActionView: + use_separator: True + ActionPrevious: + with_previous: True + on_release: app.set_previous_screen() ScreenManager: id: scr_mngr diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 3f9b198b..b8d0a724 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -19,6 +19,7 @@ from bmconfigparser import BMConfigParser from helper_ackPayload import genAckPayload from addresses import decodeAddress, addBMIfNotPresent from helper_sql import sqlExecute +from kivy.core.window import Window statusIconColor = 'red' @@ -38,8 +39,19 @@ class NavigateApp(App, TextInput): main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigator() + Window.bind(on_keyboard=self._key_handler) return main_widget + def _key_handler(self, instance, key, *args): + if key is 27: + self.set_previous_screen() + return True + + def set_previous_screen(self): + if self.root.ids.scr_mngr.current != 'inbox': + self.root.ids.scr_mngr.transition.direction = 'left' + self.root.ids.scr_mngr.current = self.root.ids.scr_mngr.previous() + def getCurrentAccountData(self, text): """Get Current Address Account Data.""" state.association = text From cd4ff4f121212df7132f83278f910e67f79bae89 Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 17:03:01 +0530 Subject: [PATCH 003/306] Changes made for new feature for back button for screen tracking back with keyboard event attach --- src/bitmessagekivy/main.kv | 30 +++++++++++++++++++----------- src/bitmessagekivy/mpybit.py | 2 +- src/images/back-button.png | Bin 0 -> 52318 bytes 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 src/images/back-button.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1d86c133..4b4316d4 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -54,16 +54,6 @@ BoxLayout: size_hint_x: 0.1 pos_hint: {'x': 0.8, 'y':0.4} on_press: app.say_exit() - ActionBar: - size_hint_y: 0.4 - size_hint_x: 0.1 - pos_hint: {'x': 0.99, 'y':0.35} - background_color: (0,0,0,0) - ActionView: - use_separator: True - ActionPrevious: - with_previous: True - on_release: app.set_previous_screen() ScreenManager: id: scr_mngr @@ -352,8 +342,26 @@ BoxLayout: : name: 'page' + ActionBar: + background_color:0,0,0,0 + pos_hint: {'top':0.98} + size_hint_y: 0.05 + size_hint_x: 0.07 + ActionView: + ActionPrevious: + with_previous: False + app_icon: 'images/back-button.png' + markup:True + font_size:"16dp" + on_release: app.set_previous_screen() Label: - text: 'I am on description of my email yooooo' + text:"Message sent on 5 september 2018 05:44" + color: 0,0,0,1 + size: self.texture_size + size_hint: (None, None) + + Label: + text: 'I am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\n' color: 0,0,0,1 : diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b8d0a724..a5241e0a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -50,7 +50,7 @@ class NavigateApp(App, TextInput): def set_previous_screen(self): if self.root.ids.scr_mngr.current != 'inbox': self.root.ids.scr_mngr.transition.direction = 'left' - self.root.ids.scr_mngr.current = self.root.ids.scr_mngr.previous() + self.root.ids.scr_mngr.current = 'inbox' def getCurrentAccountData(self, text): """Get Current Address Account Data.""" diff --git a/src/images/back-button.png b/src/images/back-button.png new file mode 100644 index 0000000000000000000000000000000000000000..e260b08bd191ec7badbfa32baa1b1f10c1125251 GIT binary patch literal 52318 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

>+H{M~b8>%pf3JKtc-k{y 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%0D5`$twgTSVjp;W&a%weXFx{XI`>KYXf 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 literal 0 HcmV?d00001 From 2625d342a932bf33dac6209b97fb24432d31630d Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 19:42:55 +0530 Subject: [PATCH 004/306] Added Ui for Search bar for message searching and also manage exit button on Action bar --- src/bitmessagekivy/main.kv | 26 ++++++++++++++++++-------- src/bitmessagekivy/mpybit.py | 15 +++++++++++++++ src/images/search.png | Bin 0 -> 2982 bytes 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/images/search.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 4b4316d4..1b7b2a6b 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -46,14 +46,24 @@ BoxLayout: title: app.getCurrentAccount() background_color: app.theme_cls.primary_dark left_action_items: [['menu', lambda x: app.nav_drawer.toggle()]] - Button: - text:"EXIT" - color: 0,0,0,1 - background_color: (0,0,0,0) - size_hint_y: 0.4 - size_hint_x: 0.1 - pos_hint: {'x': 0.8, 'y':0.4} - on_press: app.say_exit() + + ActionView: + SearchBar: + size_hint_x: 1.7 + size_hint_y: .5 + pos_hint: {'x': 0, 'center_y':.5} + on_text_validate: searchbutt.trigger_action() + + ActionPrevious: + with_previous: False + app_icon: '' + + ActionOverflow: + ActionButton: + text: 'Filters' + ActionButton: + text: 'Exit' + on_press: app.say_exit() ScreenManager: id: scr_mngr diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a5241e0a..1d4f7178 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -20,6 +20,7 @@ from helper_ackPayload import genAckPayload from addresses import decodeAddress, addBMIfNotPresent from helper_sql import sqlExecute from kivy.core.window import Window +from kivy.uix.actionbar import ActionItem statusIconColor = 'red' @@ -43,11 +44,15 @@ class NavigateApp(App, TextInput): return main_widget def _key_handler(self, instance, key, *args): + """Escape key manages previous screen on back.""" if key is 27: + print(args) + print(instance) self.set_previous_screen() return True def set_previous_screen(self): + """Set previous screen based on back.""" if self.root.ids.scr_mngr.current != 'inbox': self.root.ids.scr_mngr.transition.direction = 'left' self.root.ids.scr_mngr.current = 'inbox' @@ -401,5 +406,15 @@ class NewIdentity(Screen): self.manager.current = 'add_sucess' +class SearchBar(TextInput, ActionItem): + def __init__(self, *args, **kwargs): + super(SearchBar, self).__init__(*args, **kwargs) + self.hint_text = 'Search' + + def search(self): + request = self.text + return str(request) + + if __name__ == '__main__': NavigateApp().run() diff --git a/src/images/search.png b/src/images/search.png new file mode 100644 index 0000000000000000000000000000000000000000..42a1e45a82f694cc0dc187370b080b43ef6b8040 GIT binary patch literal 2982 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 literal 0 HcmV?d00001 From e20b437b6ceef1fdcd52b44e21b5b5db57185e79 Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 19:48:57 +0530 Subject: [PATCH 005/306] fix pylint issues based on commit relevant to Search bar --- src/bitmessagekivy/mpybit.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 1d4f7178..28321e01 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -407,11 +407,15 @@ class NewIdentity(Screen): class SearchBar(TextInput, ActionItem): + """Create SearchBar for PyBitmessage.""" + def __init__(self, *args, **kwargs): + """Initailizes SearchBar with hint text.""" super(SearchBar, self).__init__(*args, **kwargs) self.hint_text = 'Search' def search(self): + """Search for message request.""" request = self.text return str(request) From ed6cd83caef18605384d755c38330db09f43d75b Mon Sep 17 00:00:00 2001 From: surbhi Date: Thu, 9 May 2019 18:18:29 +0530 Subject: [PATCH 006/306] rebase conflict fix and Ui Enhancement with dynamic addressbook updation and sent screen updation Ui Enhancement with dynamic addressbook updation and sent screen updation Changes made for Sent Items refresh feature with auto add new message in kivy --- build/README.md | 2 - build/changelang.sh | 16 - build/compiletest.py | 23 - build/mergepullrequest.sh | 11 - build/osx.sh | 26 - build/updatetranslations.sh | 22 - .../platform/python-for-android-new-toolchain | 1 + .../recipes/bitmsghash/__init__.py | 50 + .../recipes/kivymd/__init__.py | 60 + .../kivymd/kivymd-fix-dev-compatibility.patch | 36 + src/bitmessagekivy/kivy_helper_search.py | 4 +- src/bitmessagekivy/main.kv | 914 ++++++---- src/bitmessagekivy/mpybit.py | 1001 +++++++---- src/bitmessagekivy/uikivysignaler.py | 23 + src/bitmessagemain.py | 19 +- src/bitmsghash/bitmsghash.cpp | 44 +- src/buildozer.spec | 39 +- src/class_addressGenerator.py | 13 +- src/class_singleWorker.py | 3 + src/debug.py | 2 +- src/depends.py | 9 +- src/helper_generic.py | 114 ++ src/helper_startup.py | 2 + src/images/account_multiple.png | Bin 0 -> 9798 bytes src/images/addressbookadd.png | Bin 0 -> 7765 bytes src/kivymd/LICENSE | 21 - src/kivymd/__init__.py | 6 - src/kivymd/accordion.py | 254 --- src/kivymd/backgroundcolorbehavior.py | 23 - src/kivymd/bottomsheet.py | 211 --- src/kivymd/button.py | 453 ----- src/kivymd/card.py | 58 - src/kivymd/color_definitions.py | 360 ---- src/kivymd/date_picker.py | 325 ---- src/kivymd/dialog.py | 176 -- src/kivymd/elevationbehavior.py | 187 -- .../fonts/Material-Design-Iconic-Font.ttf | Bin 99212 -> 0 bytes src/kivymd/fonts/Roboto-Bold.ttf | Bin 163448 -> 0 bytes src/kivymd/fonts/Roboto-Italic.ttf | Bin 132440 -> 0 bytes src/kivymd/fonts/Roboto-Light.ttf | Bin 140276 -> 0 bytes src/kivymd/fonts/Roboto-LightItalic.ttf | Bin 133172 -> 0 bytes src/kivymd/fonts/Roboto-Medium.ttf | Bin 137308 -> 0 bytes src/kivymd/fonts/Roboto-MediumItalic.ttf | Bin 134312 -> 0 bytes src/kivymd/fonts/Roboto-Regular.ttf | Bin 145348 -> 0 bytes src/kivymd/fonts/Roboto-Thin.ttf | Bin 130044 -> 0 bytes src/kivymd/fonts/Roboto-ThinItalic.ttf | Bin 132860 -> 0 bytes src/kivymd/grid.py | 168 -- src/kivymd/icon_definitions.py | 1569 ----------------- src/kivymd/images/kivymd_512.png | Bin 30694 -> 0 bytes src/kivymd/images/kivymd_logo.png | Bin 42074 -> 0 bytes src/kivymd/images/quad_shadow-0.png | Bin 29962 -> 0 bytes src/kivymd/images/quad_shadow-1.png | Bin 30186 -> 0 bytes src/kivymd/images/quad_shadow-2.png | Bin 19289 -> 0 bytes src/kivymd/images/quad_shadow.atlas | 1 - src/kivymd/images/rec_shadow-0.png | Bin 46593 -> 0 bytes src/kivymd/images/rec_shadow-1.png | Bin 43957 -> 0 bytes src/kivymd/images/rec_shadow.atlas | 1 - src/kivymd/images/rec_st_shadow-0.png | Bin 30721 -> 0 bytes src/kivymd/images/rec_st_shadow-1.png | Bin 32265 -> 0 bytes src/kivymd/images/rec_st_shadow-2.png | Bin 28526 -> 0 bytes src/kivymd/images/rec_st_shadow.atlas | 1 - src/kivymd/images/round_shadow-0.png | Bin 39635 -> 0 bytes src/kivymd/images/round_shadow-1.png | Bin 40767 -> 0 bytes src/kivymd/images/round_shadow-2.png | Bin 26510 -> 0 bytes src/kivymd/images/round_shadow.atlas | 1 - src/kivymd/label.py | 94 - src/kivymd/list.py | 531 ------ src/kivymd/material_resources.py | 50 - src/kivymd/menu.py | 192 -- src/kivymd/navigationdrawer.py | 76 - src/kivymd/progressbar.py | 79 - src/kivymd/ripplebehavior.py | 169 -- src/kivymd/selectioncontrols.py | 240 --- src/kivymd/slider.py | 247 --- src/kivymd/slidingpanel.py | 92 - src/kivymd/snackbar.py | 115 -- src/kivymd/spinner.py | 149 -- src/kivymd/tabs.py | 303 ---- src/kivymd/textfields.py | 215 --- src/kivymd/theme_picker.py | 422 ----- src/kivymd/theming.py | 350 ---- src/kivymd/time_picker.py | 84 - src/kivymd/toolbar.py | 98 - src/kivymd/vendor/__init__.py | 1 - src/kivymd/vendor/circleLayout/LICENSE | 22 - src/kivymd/vendor/circleLayout/README.md | 21 - src/kivymd/vendor/circleLayout/__init__.py | 196 -- src/kivymd/vendor/circularTimePicker/LICENSE | 22 - .../vendor/circularTimePicker/README.md | 43 - .../vendor/circularTimePicker/__init__.py | 770 -------- src/main.py | 4 +- src/navigationdrawer/__init__.py | 82 - src/network/networkthread.py | 2 + src/paths.py | 21 +- src/plugins/menu_qrcode.py | 2 +- src/proofofwork.py | 14 +- src/pyelliptic/openssl.py | 9 +- src/semaphores.py | 3 + src/shared.py | 19 +- src/singleinstance.py | 3 +- src/state.py | 4 + src/tr.py | 10 +- 102 files changed, 1674 insertions(+), 9329 deletions(-) delete mode 100644 build/README.md delete mode 100755 build/changelang.sh delete mode 100755 build/compiletest.py delete mode 100755 build/mergepullrequest.sh delete mode 100755 build/osx.sh delete mode 100755 build/updatetranslations.sh create mode 160000 src/.buildozer/android/platform/python-for-android-new-toolchain create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch create mode 100644 src/bitmessagekivy/uikivysignaler.py create mode 100644 src/helper_generic.py create mode 100644 src/images/account_multiple.png create mode 100644 src/images/addressbookadd.png delete mode 100644 src/kivymd/LICENSE delete mode 100644 src/kivymd/__init__.py delete mode 100644 src/kivymd/accordion.py delete mode 100644 src/kivymd/backgroundcolorbehavior.py delete mode 100644 src/kivymd/bottomsheet.py delete mode 100644 src/kivymd/button.py delete mode 100644 src/kivymd/card.py delete mode 100644 src/kivymd/color_definitions.py delete mode 100644 src/kivymd/date_picker.py delete mode 100644 src/kivymd/dialog.py delete mode 100644 src/kivymd/elevationbehavior.py delete mode 100644 src/kivymd/fonts/Material-Design-Iconic-Font.ttf delete mode 100644 src/kivymd/fonts/Roboto-Bold.ttf delete mode 100644 src/kivymd/fonts/Roboto-Italic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Light.ttf delete mode 100644 src/kivymd/fonts/Roboto-LightItalic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Medium.ttf delete mode 100644 src/kivymd/fonts/Roboto-MediumItalic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Regular.ttf delete mode 100644 src/kivymd/fonts/Roboto-Thin.ttf delete mode 100644 src/kivymd/fonts/Roboto-ThinItalic.ttf delete mode 100644 src/kivymd/grid.py delete mode 100644 src/kivymd/icon_definitions.py delete mode 100644 src/kivymd/images/kivymd_512.png delete mode 100644 src/kivymd/images/kivymd_logo.png delete mode 100644 src/kivymd/images/quad_shadow-0.png delete mode 100644 src/kivymd/images/quad_shadow-1.png delete mode 100644 src/kivymd/images/quad_shadow-2.png delete mode 100644 src/kivymd/images/quad_shadow.atlas delete mode 100644 src/kivymd/images/rec_shadow-0.png delete mode 100644 src/kivymd/images/rec_shadow-1.png delete mode 100644 src/kivymd/images/rec_shadow.atlas delete mode 100644 src/kivymd/images/rec_st_shadow-0.png delete mode 100644 src/kivymd/images/rec_st_shadow-1.png delete mode 100644 src/kivymd/images/rec_st_shadow-2.png delete mode 100644 src/kivymd/images/rec_st_shadow.atlas delete mode 100644 src/kivymd/images/round_shadow-0.png delete mode 100644 src/kivymd/images/round_shadow-1.png delete mode 100644 src/kivymd/images/round_shadow-2.png delete mode 100644 src/kivymd/images/round_shadow.atlas delete mode 100644 src/kivymd/label.py delete mode 100644 src/kivymd/list.py delete mode 100644 src/kivymd/material_resources.py delete mode 100644 src/kivymd/menu.py delete mode 100644 src/kivymd/navigationdrawer.py delete mode 100644 src/kivymd/progressbar.py delete mode 100644 src/kivymd/ripplebehavior.py delete mode 100644 src/kivymd/selectioncontrols.py delete mode 100644 src/kivymd/slider.py delete mode 100644 src/kivymd/slidingpanel.py delete mode 100644 src/kivymd/snackbar.py delete mode 100644 src/kivymd/spinner.py delete mode 100644 src/kivymd/tabs.py delete mode 100644 src/kivymd/textfields.py delete mode 100644 src/kivymd/theme_picker.py delete mode 100644 src/kivymd/theming.py delete mode 100644 src/kivymd/time_picker.py delete mode 100644 src/kivymd/toolbar.py delete mode 100644 src/kivymd/vendor/__init__.py delete mode 100644 src/kivymd/vendor/circleLayout/LICENSE delete mode 100644 src/kivymd/vendor/circleLayout/README.md delete mode 100644 src/kivymd/vendor/circleLayout/__init__.py delete mode 100644 src/kivymd/vendor/circularTimePicker/LICENSE delete mode 100644 src/kivymd/vendor/circularTimePicker/README.md delete mode 100644 src/kivymd/vendor/circularTimePicker/__init__.py delete mode 100644 src/navigationdrawer/__init__.py create mode 100644 src/semaphores.py diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 248d2c41..00000000 --- a/build/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains scripts that are helpful for developers when building -or maintaining PyBitmessage. diff --git a/build/changelang.sh b/build/changelang.sh deleted file mode 100755 index 915c5dea..00000000 --- a/build/changelang.sh +++ /dev/null @@ -1,16 +0,0 @@ -export LANG=de_DE.UTF-8 -export LANGUAGE=de_DE -export LC_CTYPE="de_DE.UTF-8" -export LC_NUMERIC=de_DE.UTF-8 -export LC_TIME=de_DE.UTF-8 -export LC_COLLATE="de_DE.UTF-8" -export LC_MONETARY=de_DE.UTF-8 -export LC_MESSAGES="de_DE.UTF-8" -export LC_PAPER=de_DE.UTF-8 -export LC_NAME=de_DE.UTF-8 -export LC_ADDRESS=de_DE.UTF-8 -export LC_TELEPHONE=de_DE.UTF-8 -export LC_MEASUREMENT=de_DE.UTF-8 -export LC_IDENTIFICATION=de_DE.UTF-8 -export LC_ALL= -python2.7 src/bitmessagemain.py diff --git a/build/compiletest.py b/build/compiletest.py deleted file mode 100755 index fdbf7db1..00000000 --- a/build/compiletest.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python2.7 - -import ctypes -import fnmatch -import os -import sys -import traceback - -matches = [] -for root, dirnames, filenames in os.walk('src'): - for filename in fnmatch.filter(filenames, '*.py'): - matches.append(os.path.join(root, filename)) - -for filename in matches: - source = open(filename, 'r').read() + '\n' - try: - compile(source, filename, 'exec') - except Exception as e: - if 'win' in sys.platform: - ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) - else: - print "Exception in %s: %s" % (filename, traceback.format_exc()) - sys.exit(1) diff --git a/build/mergepullrequest.sh b/build/mergepullrequest.sh deleted file mode 100755 index 35e87566..00000000 --- a/build/mergepullrequest.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ]; then - echo "You must specify pull request number" - exit -fi - -git pull -git checkout v0.6 -git fetch origin pull/"$1"/head:"$1" -git merge --ff-only "$1" diff --git a/build/osx.sh b/build/osx.sh deleted file mode 100755 index e58a49f4..00000000 --- a/build/osx.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# OS X Build script wrapper around the py2app script. -# This build can only be generated on OS X. -# Requires all build dependencies for Bitmessage -# Especially important is OpenSSL installed through brew - -export ARCHFLAGS="-arch i386 -arch x86_64" - -if [[ -z "$1" ]]; then - echo "Please supply a version number for this release as the first argument." - exit -fi - -echo "Creating OS X packages for Bitmessage." - -export PYBITMESSAGEVERSION=$1 - -cd src && python2.7 build_osx.py py2app - -if [[ $? = "0" ]]; then - hdiutil create -fs HFS+ -volname "Bitmessage" -srcfolder dist/Bitmessage.app dist/bitmessage-v$1.dmg -else - echo "Problem creating Bitmessage.app, stopping." - exit -fi diff --git a/build/updatetranslations.sh b/build/updatetranslations.sh deleted file mode 100755 index ba5a3fdb..00000000 --- a/build/updatetranslations.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [ ! -f "$1" ]; then - echo "$1 not found, please specify the file name for source" - exit -fi - -srcdir=`mktemp -d` - -unzip "$1" -d $srcdir - -for i in $srcdir/*ts; do - o=`basename $i|cut -b3-` - o="${o,,}" - o="${o//@/_}" - echo "$i -> $o" - mv "$i" "$HOME/src/PyBitmessage/src/translations/$o" -done - -rm -rf -- $srcdir - -lrelease-qt4 "$HOME/src/PyBitmessage/src/translations/bitmessage.pro" diff --git a/src/.buildozer/android/platform/python-for-android-new-toolchain b/src/.buildozer/android/platform/python-for-android-new-toolchain new file mode 160000 index 00000000..5aa322da --- /dev/null +++ b/src/.buildozer/android/platform/python-for-android-new-toolchain @@ -0,0 +1 @@ +Subproject commit 5aa322da9179dae305fde5af1db516c1ad9baea4 diff --git a/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py new file mode 100644 index 00000000..4566ebfb --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py @@ -0,0 +1,50 @@ +from pythonforandroid.toolchain import Recipe, shprint, shutil, current_directory +from os.path import exists, join +import os +import sys +from multiprocessing import cpu_count +import sh + + +class BitmsghashRecipe(Recipe): + # This could also inherit from PythonRecipe etc. if you want to + # use their pre-written build processes + + url = 'https://github.com/surbhicis/bitmsghash/archive/master.zip' + # {version} will be replaced with self.version when downloading + + depends = ['openssl'] + + conflicts = [] + + def get_recipe_env(self, arch=None): + env = super(BitmsghashRecipe, self).get_recipe_env(arch) + r = Recipe.get_recipe('openssl', self.ctx) + b = r.get_build_dir(arch.arch) + env['CCFLAGS'] = env['CFLAGS'] = \ + env['CFLAGS'] + ' -I{openssl_build_path}/include ' \ + '-I{openssl_build_path}/include/openssl'.format( + openssl_build_path=b) + env['LDFLAGS'] = \ + env['LDFLAGS'] + ' -L{openssl_build_path} ' \ + '-lcrypto{openssl_version} ' \ + '-lssl{openssl_version}'.format( + openssl_build_path=b, + openssl_version=r.version) + return env + + def should_build(self, arch=None): + super(BitmsghashRecipe, self).should_build(arch) + return not exists( + join(self.ctx.get_libs_dir(arch.arch), 'libbitmsghash.so')) + + def build_arch(self, arch=None): + super(BitmsghashRecipe, self).build_arch(arch) + env = self.get_recipe_env(arch) + with current_directory(join(self.get_build_dir(arch.arch))): + dst_dir = join(self.get_build_dir(arch.arch)) + shprint(sh.make, '-j', str(cpu_count()), _env=env) + self.install_libs(arch, '{}/libbitmsghash.so'.format(dst_dir), + 'libbitmsghash.so') + +recipe = BitmsghashRecipe() diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py new file mode 100644 index 00000000..b49013a7 --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py @@ -0,0 +1,60 @@ +from os import environ +from os.path import exists, join + +import sh +from pythonforandroid.logger import shprint, info_main, info +from pythonforandroid.recipe import PythonRecipe +# from pythonforandroid.util import ensure_dir + + +class KivyMDRecipe(PythonRecipe): + # This recipe installs KivyMD into the android dist from source + version = 'master' + # url = 'https://gitlab.com/kivymd/KivyMD/repository/{version}/archive.zip' + url = 'https://github.com/HeaTTheatR/KivyMD/archive/master.zip' + depends = ['kivy'] + site_packages_name = 'kivymd' + call_hostpython_via_targetpython = False + # patches = ['kivymd-fix-dev-compatibility.patch'] + # Made commented as use different repo for updates + + def should_build(self, arch): + return True + + # def unpack(self, arch): + # info_main('Unpacking {} for {}'.format(self.name, arch)) + # + # build_dir = self.get_build_container_dir(arch) + # + # user_dir = environ.get('P4A_{}_DIR'.format(self.name.lower())) + # + # if user_dir is not None: + # info("Installing KivyMD development version (from modded source)") + # self.clean_build() + # shprint(sh.rm, '-rf', build_dir) + # shprint(sh.mkdir, '-p', build_dir) + # shprint(sh.rmdir, build_dir) + # ensure_dir(build_dir) + # ensure_dir(build_dir + "/kivymd") + # shprint(sh.cp, user_dir + '/setup.py', self.get_build_dir(arch) + "/setup.py") + # shprint(sh.cp, '-a', user_dir + "/kivymd", self.get_build_dir(arch) + "/kivymd") + # return + + def get_recipe_env(self, arch): + env = super(KivyMDRecipe, self).get_recipe_env(arch) + env['PYTHON_ROOT'] = self.ctx.get_python_install_dir() + env['CFLAGS'] += ' -I' + env['PYTHON_ROOT'] + '/include/python2.7' + env['LDFLAGS'] += ' -L' + env['PYTHON_ROOT'] + '/lib' + \ + ' -lpython2.7' + if 'sdl2' in self.ctx.recipe_build_order: + env['USE_SDL2'] = '1' + env['KIVY_SDL2_PATH'] = ':'.join([ + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'), + ]) + return env + + +recipe = KivyMDRecipe() diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch new file mode 100644 index 00000000..bc8d5dee --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch @@ -0,0 +1,36 @@ +diff -Naurp KivyMD.orig/kivymd/button.py KivyMD/kivymd/button.py +--- KivyMD.orig/kivymd/button.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/button.py 2018-07-10 10:37:55.719440354 +0200 +@@ -175,7 +175,8 @@ class BaseButton(ThemableBehavior, Butto + self._current_button_color = self.md_bg_color_disabled + else: + self._current_button_color = self.md_bg_color +- super(BaseButton, self).on_disabled(instance, value) ++ # To add compatibility to last kivy (disabled is now an Alias property) ++ # super(BaseButton, self).on_disabled(instance, value) + + + class BasePressedButton(BaseButton): +diff -Naurp KivyMD.orig/kivymd/selectioncontrols.py KivyMD/kivymd/selectioncontrols.py +--- KivyMD.orig/kivymd/selectioncontrols.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/selectioncontrols.py 2018-07-10 10:40:06.971439102 +0200 +@@ -45,6 +45,7 @@ Builder.load_string(''' + pos: self.pos + + : ++ _thumb_pos: (self.right - dp(12), self.center_y - dp(12)) if self.active else (self.x - dp(12), self.center_y - dp(12)) + canvas.before: + Color: + rgba: self._track_color_disabled if self.disabled else \ +diff -Naurp KivyMD.orig/kivymd/tabs.py KivyMD/kivymd/tabs.py +--- KivyMD.orig/kivymd/tabs.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/tabs.py 2018-07-10 10:39:20.603439544 +0200 +@@ -185,7 +185,7 @@ class MDBottomNavigationBar(ThemableBeha + + class MDTabHeader(MDFlatButton): + """ Internal widget for headers based on MDFlatButton""" +- ++ + width = BoundedNumericProperty(dp(0), min=dp(72), max=dp(264), errorhandler=lambda x: dp(72)) + tab = ObjectProperty(None) + panel = ObjectProperty(None) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 684a1722..6758f554 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -9,7 +9,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if folder == "sent": sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime + SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' else: sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read @@ -42,4 +42,4 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) + return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1b7b2a6b..dc74450d 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,203 +1,243 @@ -#:import la kivy.adapters.listadapter -#:import factory kivy.factory -#:import mpybit bitmessagekivy.mpybit -#:import C kivy.utils.get_color_from_hex -: - id: nav_drawer +#:import Toolbar kivymd.toolbar.Toolbar +#:import ThemeManager kivymd.theming.ThemeManager +#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer +#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout +#:import NavigationDrawerDivider kivymd.navigationdrawer.NavigationDrawerDivider +#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar +#:import NavigationDrawerSubheader kivymd.navigationdrawer.NavigationDrawerSubheader +#:import MDCheckbox kivymd.selectioncontrols.MDCheckbox +#:import MDSwitch kivymd.selectioncontrols.MDSwitch +#:import MDList kivymd.list.MDList +#:import OneLineListItem kivymd.list.OneLineListItem +#:import TwoLineListItem kivymd.list.TwoLineListItem +#:import ThreeLineListItem kivymd.list.ThreeLineListItem +#:import OneLineAvatarListItem kivymd.list.OneLineAvatarListItem +#:import OneLineIconListItem kivymd.list.OneLineIconListItem +#:import OneLineAvatarIconListItem kivymd.list.OneLineAvatarIconListItem +#:import MDTextField kivymd.textfields.MDTextField +#:import MDSpinner kivymd.spinner.MDSpinner +#:import MDCard kivymd.card.MDCard +#:import MDSeparator kivymd.card.MDSeparator +#:import MDDropdownMenu kivymd.menu.MDDropdownMenu +#:import get_color_from_hex kivy.utils.get_color_from_hex +#:import colors kivymd.color_definitions.colors +#:import SmartTile kivymd.grid.SmartTile +#:import MDSlider kivymd.slider.MDSlider +#:import MDTabbedPanel kivymd.tabs.MDTabbedPanel +#:import MDTab kivymd.tabs.MDTab +#:import MDProgressBar kivymd.progressbar.MDProgressBar +#:import MDAccordion kivymd.accordion.MDAccordion +#:import MDAccordionItem kivymd.accordion.MDAccordionItem +#:import MDAccordionSubItem kivymd.accordion.MDAccordionSubItem +#:import MDThemePicker kivymd.theme_picker.MDThemePicker +#:import MDBottomNavigation kivymd.tabs.MDBottomNavigation +#:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem +#:import MDFloatingActionButton kivymd.button.MDFloatingActionButton + +: + icon: 'checkbox-blank-circle' + +: + drawer_logo: './images/drawer_logo1.png' + NavigationDrawerDivider: + + NavigationDrawerTwoLineListItem: + text: "Accounts" NavigationDrawerIconButton: Spinner: - pos_hint:{"x":0,"y":.3} + pos_hint:{"x":0,"y":.25} id: btn - background_color: app.theme_cls.primary_dark - text: app.showmeaddresses(name='text') - values: app.showmeaddresses(name='values') + text: app.getDefaultAccData() + values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - NavigationDrawerIconButton: icon: 'email-open' - text: "inbox" + text: "Inbox" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "99+" + NavigationDrawerIconButton: + icon: 'send' + text: "Sent" + on_release: app.root.ids.scr_mngr.current = 'sent' + badge_text: "2" + NavigationDrawerIconButton: + icon: 'message-draw' + text: "Draft" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "99+" + NavigationDrawerIconButton: + text: "Starred" + icon:'star' on_release: app.root.ids.scr_mngr.current = 'inbox' NavigationDrawerIconButton: - icon: 'mail-send' - text: "sent" - on_release: app.root.ids.scr_mngr.current = 'sent' - NavigationDrawerIconButton: - icon: 'dropbox' - text: "trash" + icon: 'archive' + text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'trash' + badge_text: "9+" NavigationDrawerIconButton: - icon: 'email' - text: "drafts" - on_release: app.root.ids.scr_mngr.current = 'dialog' + icon: 'email-open-outline' + text: "Spam" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "8+" NavigationDrawerIconButton: - icon: 'markunread-mailbox' - text: "test" - on_release: app.root.ids.scr_mngr.current = 'test' + icon: 'delete' + text: "Trash" + on_release: app.root.ids.scr_mngr.current = 'trash' + badge_text: "9+" NavigationDrawerIconButton: - text: "new identity" - icon:'accounts-add' - on_release: app.root.ids.scr_mngr.current = 'newidentity' - -BoxLayout: - orientation: 'vertical' - Toolbar: - id: toolbar - title: app.getCurrentAccount() - background_color: app.theme_cls.primary_dark - left_action_items: [['menu', lambda x: app.nav_drawer.toggle()]] + text: "All Mails" + icon:'contact-mail' + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "999+" + NavigationDrawerDivider: + NavigationDrawerSubheader: + text: "All labels" + NavigationDrawerIconButton: + text: "Address Book" + icon:'book-multiple' + on_release: app.root.ids.scr_mngr.current = 'addressbook' + NavigationDrawerIconButton: + text: "Settings" + icon:'settings' + on_release: app.root.ids.scr_mngr.current = 'set' + NavigationDrawerIconButton: + text: "Subscriptions/Payment" + icon:'wallet' + on_release: app.root.ids.scr_mngr.current = 'payment' + NavigationDrawerIconButton: + text: "new address" + icon:'account-plus' + on_release: app.root.ids.scr_mngr.current = 'login' + NavigationDrawerIconButton: + text: "Network Status" + icon:'server-network' + on_release: app.root.ids.scr_mngr.current = 'networkstat' + NavigationDrawerIconButton: + text: "My Addresses" + icon:'account-multiple' + on_release: app.root.ids.scr_mngr.current = 'myaddress' - ActionView: - SearchBar: - size_hint_x: 1.7 - size_hint_y: .5 - pos_hint: {'x': 0, 'center_y':.5} - on_text_validate: searchbutt.trigger_action() +NavigationLayout: + id: nav_layout - ActionPrevious: - with_previous: False - app_icon: '' + ContentNavigationDrawer: + id: nav_drawer - ActionOverflow: - ActionButton: - text: 'Filters' - ActionButton: - text: 'Exit' - on_press: app.say_exit() - - ScreenManager: - id: scr_mngr - Inbox: - id:sc1 - Sent: - id:sc2 - Trash: - id:sc3 - Dialog: - id:sc4 - Test: - id:sc5 - Create: - id:sc6 - NewIdentity: - id:sc7 - Page: - id:sc8 - AddressSuccessful: - id:sc9 - - Button: - id:create - height:100 - size_hint_y: 0.13 - size_hint_x: 0.1 - pos_hint: {'x': 0.85, 'y': 0.5} - background_color: (0,0,0,0) - on_press: scr_mngr.current = 'create' - Image: - source: 'images/plus.png' - y: self.parent.y - 7.5 - x: self.parent.x + self.parent.width - 50 - size: 70, 70 - -: - text: '' - size_hint_y: None - height: 48 - ignore_perpendicular_swipes: True - data_index: 0 - min_move: 20 / self.width - - on__offset: app.update_index(root.data_index, self.index) - - canvas.before: - Color: - rgba: C('FFFFFF33') - - Rectangle: - pos: self.pos - size: self.size - - Line: - rectangle: self.pos + self.size - - Button: - text: 'delete ({}:{})'.format(root.text, root.data_index) - on_press: app.delete(root.data_index) - - Button: - text: root.text - on_press: app.getInboxMessageDetail(self.text) - - Button: - text: 'archive' - on_press: app.archive(root.data_index) + BoxLayout: + orientation: 'vertical' + Toolbar: + id: toolbar.. + md_bg_color: app.theme_cls.primary_color + background_palette: 'Primary' + background_hue: '500' + left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] + Button: + id: myButton + size_hint_y: 0.35 + size_hint_x: 0.2 + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.addingtoaddressbook() + Image: + source: './images/addressbookadd.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + ScreenManager: + id: scr_mngr + Inbox: + id:sc1 + Page: + id:sc2 + Create: + id:sc3 + Sent: + id:sc4 + Trash: + id:sc5 + Login: + id:sc6 + Random: + id:sc7 + AddressSuccessful: + id:sc8 + Setting: + id:sc9 + MyAddress: + id:sc10 + AddressBook: + id:sc11 + Payment: + id:sc12 + NetworkStat: + id:sc13 : name: 'inbox' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + 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' : name: 'sent' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + 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' : name: 'trash' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + Widget: -

: - name: 'dialog' + 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' + +: + name: 'draft' Label: text:"I have a good dialox box" color: 0,0,0,1 @@ -207,175 +247,391 @@ BoxLayout: text:"I am in test" color: 0,0,0,1 -: - name: 'create' - GridLayout: - rows: 5 - cols: 1 - padding: 60,60,60,60 - spacing: 50 - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'FROM' - color: 0,0,0,1 - Spinner: - size_hint: 1,1 - pos_hint: {"x":0,"top":1.} - pos: 10,10 - id: spinner_id - text: app.showmeaddresses(name='text') - values: app.showmeaddresses(name='values') - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'TO' - color: 0,0,0,1 - TextInput: - id: recipent - hint_text: 'To' - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'SUBJECT' - color: 0,0,0,1 - TextInput: - id: subject - hint_text: 'SUBJECT' - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'BODY' - color: 0,0,0,1 - TextInput: - id: message - multiline:True - size_hint: 1,2 - - Button: - text: 'send' - size_hint_y: 0.1 - size_hint_x: 0.2 - height: '32dp' - pos_hint: {'x': .5, 'y': 0.1} - on_press: root.send() - Button: - text: 'cancel' - size_hint_y: 0.1 - size_hint_x: 0.2 - height: '32dp' - pos_hint: {'x': .72, 'y': 0.1} - on_press: root.cancel() - -: - name: 'newidentity' - GridLayout: - padding: '120dp' - cols: 1 - Label: - text:"""Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged.""" - line_height:1.5 - text_size:(700,None) - color: 0,0,0,1 - BoxLayout: - CheckBox: - canvas.before: - Color: - rgb: 1,0,0 - Ellipse: - pos:self.center_x-8, self.center_y-8 - size:[16,16] - group: "money" - id:chk - text:"use a random number generator to make an address" - on_active: - root.checked = self.text - active:root.is_active - - Label: - text: "use a random number generator to make an address" - color: 0,0,0,1 - BoxLayout: - CheckBox: - canvas.before: - Color: - rgb: 1,0,0 - Ellipse: - pos:self.center_x-8, self.center_y-8 - size:[16,16] - group: "money" - id:chk - text:"use a pseudo number generator to make an address" - on_active: - root.checked = self.text - active:not root.is_active - Label: - text: "use a pseudo number generator to make an address" - color: 0,0,0,1 - Label: - color: 0,0,0,1 - size_hint_x: .35 - markup: True - text: "[b]{}[/b]".format("Randomly generated addresses") - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: "Label (not shown to anyone except you)" - color: 0,0,0,1 - BoxLayout: - size_hint_y: None - height: '32dp' - TextInput: - id: label - - Button: - text: 'Cancel' - size_hint_y: 0.1 - size_hint_x: 0.3 - height: '32dp' - pos_hint: {'x': .1, 'y': 0.1} - Button: - text: 'Ok' - size_hint_y: 0.1 - size_hint_x: 0.3 - height: '32dp' - pos_hint: {'x': .5, 'y': 0.1} - on_press: root.generateaddress() - : name: 'page' - ActionBar: - background_color:0,0,0,0 - pos_hint: {'top':0.98} - size_hint_y: 0.05 - size_hint_x: 0.07 - ActionView: - ActionPrevious: - with_previous: False - app_icon: 'images/back-button.png' - markup:True - font_size:"16dp" - on_release: app.set_previous_screen() Label: - text:"Message sent on 5 september 2018 05:44" + text:"I am on page" color: 0,0,0,1 - size: self.texture_size - size_hint: (None, None) - Label: - text: 'I am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\n' - color: 0,0,0,1 +: + name: 'create' + +: + ScrollView: + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(app.scr_size) + padding: dp(32) + spacing: 15 + BoxLayout: + orientation: 'vertical' + TextInput: + id: ti + hint_text: 'type or select sender address' + size_hint_y: None + height: 100 + multiline: False + + BoxLayout: + size_hint_y: None + height: 100 + Spinner: + background_color: app.theme_cls.primary_dark + id: btn + text: 'select' + values: app.variable_1 + on_text: ti.text = self.text + + BoxLayout: + orientation: 'vertical' + txt_input: txt_input + rv: rv + size : (890, 60) + size_hint: 1,2 + MyTextInput: + id: txt_input + size_hint_y: None + height: 100 + hint_text: 'type or search recipients address starting with BM-' + RV: + id: rv + TextInput: + id: subject + hint_text: 'subject' + size_hint_y: None + height: 100 + multiline: False + TextInput: + id: body + hint_text: 'body' + size_hint_y: None + height: 100 + multiline:True + size_hint: 1,2 + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'send' + on_press: root.send() + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'reset' + on_press: app.root.ids.scr_mngr.current = 'random' + +: + readonly: False + multiline: False + +: + # Draw a background to indicate selection + color: 0,0,0,1 + canvas.before: + Color: + rgba: app.theme_cls.primary_dark if self.selected else (1, 1, 1, 0) + Rectangle: + pos: self.pos + size: self.size + +: + canvas: + Color: + rgba: 0,0,0,.2 + + Line: + rectangle: self.x +1 , self.y, self.width - 2, self.height -2 + bar_width: 10 + scroll_type:['bars'] + viewclass: 'SelectableLabel' + SelectableRecycleBoxLayout: + default_size: None, dp(20) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + orientation: 'vertical' + multiselect: False + + +: + name: 'login' + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(800) + BoxLayout: + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "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 \n pros and cons:\n" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + BoxLayout: + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "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" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + MDCheckbox: + id: grp_chkbox_1 + group: 'test' + active: True + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "use a random number generator to make an address" + halign: 'center' + size_hint_y: None + bold: True + height: self.texture_size[1] + dp(4) + color: [0.941, 0, 0,1] + MDCheckbox: + id: grp_chkbox_1 + group: 'test' + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "use a pseudo number generator to make an address" + halign: 'center' + size_hint_y: None + bold: True + color: [0.941, 0, 0,1] + height: self.texture_size[1] + dp(4) + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .5 + text: 'proceed' + on_press: app.root.ids.scr_mngr.current = 'random' + +: + name: 'random' + ScrollView: + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: self.minimum_height + padding: dp(48) + spacing: 200 + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "Random Addresses" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "Here you may generate as many addresses as you like, Indeed creating and abandoning addresses is encouraged" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + + MDTextField: + id: label + multiline: True + hint_text: "Label" + helper_text: "Label (not shown to anyone except you)" + helper_text_mode: "persistent" + MDRaisedButton: + text: 'next' + size_hint_y: 0.13 + size_hint_x: 0.8 + pos_hint: {'x': .1, 'y': 0.3} + opposite_colors: True + on_release: root.generateaddress() : name: 'add_sucess' Label: text: 'Successfully created a new bit address' color: 0,0,0,1 + +: + name: 'set' + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(500) + OneLineListItem: + text: "SERVER SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Server ' + on_press: app.root.ids.scr_mngr.current = 'random' + OneLineListItem: + text: "DATA SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Import or export data' + on_press: app.root.ids.scr_mngr.current = 'random' + OneLineListItem: + text: "OTHER SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Restart background service' + on_press: app.root.ids.scr_mngr.current = 'random' + BoxLayout: + AnchorLayout: + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "bitmessage is 11 seconds behind the network" + halign: 'center' + bold: True + color: [0.941, 0, 0,1] + + BoxLayout: + MDCheckbox: + id: chkbox + size_hint: None, None + size: dp(48), dp(48) + active: True + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "show settings (for advanced users only)" + halign: 'left' + bold: True + color: app.theme_cls.primary_dark + +: + name: 'myaddress' + ScrollView: + do_scroll_x: False + MDList: + id: ml + +: + name: 'addressbook' + BoxLayout: + orientation:'vertical' + ScrollView: + do_scroll_x: False + MDList: + id: ml + +: + name: 'payment' + + +: + id: popup + title: 'add contact\'s' + background: './images/popup.jpeg' + title_size: sp(30) + title_color: 0.4, 0.3765, 0.3451, 1 + size_hint: 1, 1 + auto_dismiss: False + separator_color: 0.3529, 0.3922, 0.102, 0.7 + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:50 + id: popup_box + orientation: 'vertical' + MDTextField: + id: label + multiline: True + hint_text: "Label" + required: True + helper_text_mode: "on_error" + MDTextField: + id: address + hint_text: "Address" + required: True + helper_text_mode: "on_error" + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Save' + on_release: + root.savecontact() + app.root.ids.scr_mngr.current = 'addressbook' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Cancel' + on_press: root.dismiss() + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Scan QR code' + +: + name: 'networkstat' + MDTabbedPanel: + id: tab_panel + tab_display_mode:'text' + + MDTab: + name: 'connections' + text: "Total connections" + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(200) + OneLineListItem: + text: "Total Connections" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .5 + text: root.text_variable_1 + MDTab: + name: 'processes' + text: 'Processes' + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(500) + OneLineListItem: + text: "person-to-person" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_2 + OneLineListItem: + text: "Brodcast" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_3 + OneLineListItem: + text: "publickeys" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_4 + + OneLineListItem: + text: "objects" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_5 \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 28321e01..a6a29ead 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,349 +1,241 @@ -import kivy_helper_search -import os -import queues -import shutdown -import state -import time - +# -*- coding: utf-8 -*- from kivy.app import App from kivy.lang import Builder -from kivy.properties import BooleanProperty -from kivy.clock import Clock -from navigationdrawer import NavigationDrawer -from kivy.properties import ObjectProperty, StringProperty, ListProperty +from kivy.metrics import dp +from kivy.properties import ObjectProperty +from kivy.uix.image import Image from kivy.uix.screenmanager import Screen -from kivy.uix.textinput import TextInput +from kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet +from kivymd.button import MDIconButton +from kivymd.date_picker import MDDatePicker +from kivymd.dialog import MDDialog +from kivymd.label import MDLabel +from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch, BaseListItem +from kivymd.material_resources import DEVICE_TYPE +from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase +from kivymd.selectioncontrols import MDCheckbox +from kivymd.snackbar import Snackbar from kivymd.theming import ThemeManager -from kivymd.toolbar import Toolbar +from kivymd.time_picker import MDTimePicker +from kivymd.list import ThreeLineAvatarIconListItem, TwoLineAvatarIconListItem, TwoLineListItem +from kivy.properties import ListProperty, StringProperty, BooleanProperty +from kivy.clock import Clock from bmconfigparser import BMConfigParser -from helper_ackPayload import genAckPayload -from addresses import decodeAddress, addBMIfNotPresent -from helper_sql import sqlExecute +import state +import queues +from kivy.uix.popup import Popup +from helper_sql import * +from kivy.uix.gridlayout import GridLayout +from kivy.app import App +from kivy.uix.textinput import TextInput +from kivy.lang import Builder +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.floatlayout import FloatLayout +from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty +from kivy.uix.recycleview import RecycleView +from kivy.uix.recyclegridlayout import RecycleGridLayout +from kivy.uix.recycleview.views import RecycleDataViewBehavior +from kivy.uix.label import Label +from kivy.uix.recycleboxlayout import RecycleBoxLayout +from kivy.uix.behaviors import FocusBehavior +from kivy.uix.recycleview.layout import LayoutSelectionBehavior +import time +from uikivysignaler import UIkivySignaler +from semaphores import kivyuisignaler +from kivy.uix.button import Button +import kivy_helper_search from kivy.core.window import Window -from kivy.uix.actionbar import ActionItem - -statusIconColor = 'red' -class NavigateApp(App, TextInput): - """Application uses kivy in which base Class of Navigate App inherits from the App class.""" - - theme_cls = ThemeManager() - nav_drawer = ObjectProperty() - - def build(self): - """Return a main_widget as a root widget. - - An application can be built if you return a widget on build(), or if you set - self.root. - """ - main_widget = Builder.load_file( - os.path.join(os.path.dirname(__file__), 'main.kv')) - self.nav_drawer = Navigator() - Window.bind(on_keyboard=self._key_handler) - return main_widget - - def _key_handler(self, instance, key, *args): - """Escape key manages previous screen on back.""" - if key is 27: - print(args) - print(instance) - self.set_previous_screen() - return True - - def set_previous_screen(self): - """Set previous screen based on back.""" - if self.root.ids.scr_mngr.current != 'inbox': - self.root.ids.scr_mngr.transition.direction = 'left' - self.root.ids.scr_mngr.current = 'inbox' - - def getCurrentAccountData(self, text): - """Get Current Address Account Data.""" - state.association = text - self.root.ids.sc1.clear_widgets() - self.root.ids.sc2.clear_widgets() - self.root.ids.sc3.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) - self.root.ids.sc2.add_widget(Sent()) - self.root.ids.sc3.add_widget(Trash()) - self.root.ids.toolbar.title = BMConfigParser().get( - state.association, 'label') + '({})'.format(state.association) - Inbox() - Sent() - Trash() - - def say_exit(self): - """Exit the application as uses shutdown PyBitmessage.""" - print("**************************EXITING FROM APPLICATION*****************************") - App.get_running_app().stop() - shutdown.doCleanShutdown() - - @staticmethod - def showmeaddresses(name="text"): - """Show the addresses in spinner to make as dropdown.""" - if name == "text": - return BMConfigParser().addresses()[0] - elif name == "values": - return BMConfigParser().addresses() - - def update_index(self, data_index, index): - """Update index after archieve message to trash.""" - if self.root.ids.scr_mngr.current == 'inbox': - self.root.ids.sc1.data[data_index]['index'] = index - elif self.root.ids.scr_mngr.current == 'sent': - self.root.ids.sc2.data[data_index]['index'] = index - elif self.root.ids.scr_mngr.current == 'trash': - self.root.ids.sc3.data[data_index]['index'] = index - - def delete(self, data_index): - """It will make delete using remove function.""" - print("delete {}".format(data_index)) - self._remove(data_index) - - def archive(self, data_index): - """It will make archieve using remove function.""" - print("archive {}".format(data_index)) - self._remove(data_index) - - def _remove(self, data_index): - """It will remove message by resetting the values in recycleview data.""" - if self.root.ids.scr_mngr.current == 'inbox': - self.root.ids.sc1.data.pop(data_index) - self.root.ids.sc1.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc1.data) - ] - elif self.root.ids.scr_mngr.current == 'sent': - self.root.ids.sc2.data.pop(data_index) - self.root.ids.sc2.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc2.data) - ] - elif self.root.ids.scr_mngr.current == 'trash': - self.root.ids.sc3.data.pop(data_index) - self.root.ids.sc3.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc3.data) - ] - - def getInboxMessageDetail(self, instance): - """It will get message detail after make selected message description.""" - try: - self.root.ids.scr_mngr.current = 'page' - except AttributeError: - self.parent.manager.current = 'page' - print('Message Clicked {}'.format(instance)) - - @staticmethod - def getCurrentAccount(): - """It uses to get current account label.""" - return BMConfigParser().get(state.association, 'label') + '({})'.format(state.association) - - -class Navigator(NavigationDrawer): - """Navigator class uses NavigationDrawer. - - It is an UI panel that shows our app's main navigation menu - It is hidden when not in use, but appears when the user swipes - a finger from the left edge of the screen or, when at the top - level of the app, the user touches the drawer icon in the app bar - """ +userAddress = '' +class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') + drawer_logo = StringProperty() + # print("priiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnnnttttttttttthethingsss.................", ) class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" - - data = ListProperty() - def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text + # if state.association == '': + # state.association = 'BM-2cTuPpAPbu44sbkfVJN2F99sXGJoeNpDBh' + # print(self.get_address_via_split(state.association)) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - self.inboxaccounts() - print(dt) - - def inboxaccounts(self): - """Load inbox accounts.""" - account = state.association - self.loadMessagelist(account, 'All', '') - - def loadMessagelist(self, account, where="", what=""): - """Load Inbox list for inbox messages.""" - xAddress = "toaddress" - queryreturn = kivy_helper_search.search_sql( - xAddress, account, 'inbox', where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[4]} - for i, row in enumerate(queryreturn) - ] + print("generateaddressgenerateaddressgenerateaddressgenerateaddressgenerateaddress", BMConfigParser().addresses()) + if BMConfigParser().addresses(): + data = [{'text': "surbhi cis222222", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "peter surda", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "uber", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "ola", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "glitch", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "github", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "kivy", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "andrew", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/kivymd_logo.png')) + self.ids.ml.add_widget(meny) else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] + self.manager.current = 'login' -class Page(Screen): - pass - - -class AddressSuccessful(Screen): - pass - - -class Sent(Screen): - """Sent Screen uses screen to show widgets of screens.""" - - data = ListProperty() - +class MyAddress(Screen): + """MyAddress Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): - super(Sent, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock Schdule for method sent accounts.""" - self.sentaccounts() - print(dt) - - def sentaccounts(self): - """Load sent accounts.""" - account = state.association - self.loadSent(account, 'All', '') - - def loadSent(self, account, where="", what=""): - """Load Sent list for Sent messages.""" - xAddress = 'fromaddress' - queryreturn = kivy_helper_search.search_sql( - xAddress, account, "sent", where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[2]} - for i, row in enumerate(queryreturn) - ] - else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] - - -class Trash(Screen): - """Trash Screen uses screen to show widgets of screens.""" - - data = ListProperty() - - def __init__(self, *args, **kwargs): - super(Trash, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text + super(MyAddress, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - self.inboxaccounts() - print(dt) - - def inboxaccounts(self): - """Load inbox accounts.""" - account = state.association - self.loadTrashlist(account, 'All', '') - - def loadTrashlist(self, account, where="", what=""): - """Load Trash list for trashed messages.""" - xAddress = "toaddress" - queryreturn = kivy_helper_search.search_sql( - xAddress, account, 'trash', where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[4]} - for i, row in enumerate(queryreturn) - ] - else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] + pass + # if BMConfigParser().AddressSuccessful(): + # data = [{'text': "me", 'secondary_text': "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyTfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyVfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWySfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyHfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyJfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyKfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyMnBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyOkBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyWuBdY2FbgyuCb7abFZ49JYxSzUhNFe"}] + # for item in data: + # meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + # meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + # self.ids.ml.add_widget(meny) + # else: + # self.manager.current = 'login' -class Dialog(Screen): - """Dialog Screen uses screen to show widgets of screens.""" - - pass - - -class Test(Screen): - """Test Screen uses screen to show widgets of screens.""" - - pass - - -class Create(Screen): - """Create Screen uses screen to show widgets of screens.""" +class AddressBook(Screen): + """AddressBook Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): - super(Create, self).__init__(*args, **kwargs) + super(AddressBook, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + # sqlExecute("DELETE FROM addressbook WHERE label='' ") + data = sqlQuery("SELECT label, address from addressbook") + if data: + for item in data: + meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="No Contact Found yet...... ", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + print("chek iniiiiiiiiiiiiiittttttttttttttttttttttttttttttttt", self) + # self.ids.ml.clear_widgets() + + def refreshs(self, *args): + state.navinstance.ids.sc11.clear_widgets() + state.navinstance.ids.sc11.add_widget(AddressBook()) + +class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, + RecycleBoxLayout): + ''' Adds selection and focus behaviour to the view. ''' + + +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): + ''' 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: + print("selection changed to {0}".format(rv.data[index])) + rv.parent.txt_input.text = rv.parent.txt_input.text.replace(rv.parent.txt_input.text, rv.data[index]['text']) + + +class RV(RecycleView): + def __init__(self, **kwargs): + super(RV, self).__init__(**kwargs) + + +class DropDownWidget(BoxLayout): + txt_input = ObjectProperty() + rv = ObjectProperty() def send(self): """Send message from one address to another.""" - fromAddress = self.ids.spinner_id.text + fromAddress = str(self.ids.ti.text) # For now we are using static address i.e we are not using recipent field value. - toAddress = "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe" - message = self.ids.message.text - subject = self.ids.subject.text + # toAddress = str(self.ids.txt_input.text) + # print("hiiiiiiiiiiiiiiiiii i am hereeeeeeeeeeeeeeeeeeeeee..............") + # print("hiiiiiiiiiseeeee to addresssssssssss..........................", self.ids) + # print("ssssssssssseeeeeeeeeeeeeeeeeeetheeeeeeeeeeetexttinput....data...", self.ids.txt_input.text) + # toAddress = "BM-2cVJ8Bb9CM5XTEjZK1CZ9pFhm7jNA1rsa6" + # print("every thng is good for the day..................", str(self.ids.txt_input.text)) + toAddress = str(self.ids.txt_input.text) + print("alllllllllllllllllllllllllllsss wel ends wellllllllllllllll", ) + subject = str(self.ids.subject.text) + message = str(self.ids.body.text) + print("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR") encoding = 3 - print("message: ", self.ids.message.text) + print("message: ", self.ids.body.text) sendMessageToPeople = True + print("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS") if sendMessageToPeople: + print("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT") + print("did_addresssssssssssssssss_existsssssssssssssssssssss.........buyyyyy", toAddress) if toAddress != '': + print("UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU") + from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) + print("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV") if status == 'success': + from addresses import * toAddress = addBMIfNotPresent(toAddress) - + statusIconColor = 'red' + print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") if addressVersionNumber > 4 or addressVersionNumber <= 1: print("addressVersionNumber > 4 or addressVersionNumber <= 1") if streamNumber > 1 or streamNumber == 0: print("streamNumber > 1 or streamNumber == 0") if statusIconColor == 'red': print("shared.statusIconColor == 'red'") + print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') + print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") + from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) + print("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY") t = () + print("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', @@ -361,64 +253,511 @@ class Create(Screen): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) + print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + self.parent.parent.screens[3].clear_widgets() + self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) - print("sqlExecute successfully ##### ##################") - self.ids.message.text = '' - self.ids.spinner_id.text = '' - self.ids.subject.text = '' - self.ids.recipent.text = '' - return None + +class MyTextInput(TextInput): + txt_input = ObjectProperty() + flt_list = ObjectProperty() + word_list = ListProperty() + # this is the variable storing the number to which the look-up will start + starting_no = NumericProperty(3) + suggestion_text = '' + + def __init__(self, **kwargs): + super(MyTextInput, self).__init__(**kwargs) + + def on_text(self, instance, value): + # find all the occurrence of the word + self.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 the data in the recycleview + display_data = [] + for i in matches: + display_data.append({'text': i}) + self.parent.parent.parent.parent.ids.rv.data = display_data + # ensure the size is okay + 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): + 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 NewIdentity(Screen): - """Create new address for PyBitmessage.""" +class Payment(Screen): + pass +class Login(Screen): + pass + + +class NetworkStat(Screen): + 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): + super(NetworkStat, self).__init__(*args, **kwargs) + Clock.schedule_interval(self.init_ui, 1) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + import network.stats + import shared + from network import objectracker + self.text_variable_1 = '{0} :: {1}'.format('Total Connections', str(len(network.stats.connectedHostsList()))) + self.text_variable_2 = 'Processed {0} per-to-per messages'.format(str(shared.numberOfMessagesProcessed)) + self.text_variable_3 = 'Processed {0} brodcast messages'.format(str(shared.numberOfBroadcastsProcessed)) + self.text_variable_4 = 'Processed {0} public keys'.format(str(shared.numberOfPubkeysProcessed)) + self.text_variable_5 = '{0} object to be synced'.format(len(objectracker.missingObjects)) + + +class ContentNavigationDrawer(Navigatorss): + pass + + +class Random(Screen): is_active = BooleanProperty(False) checked = StringProperty("") # self.manager.parent.ids.create.children[0].source = 'images/plus-4-xxl.png' def generateaddress(self): - """Generate new address.""" - if self.checked == 'use a random number generator to make an address': - queues.apiAddressGeneratorReturnQueue.queue.clear() - streamNumberForAddress = 1 - label = self.ids.label.text - eighteenByteRipe = False - nonceTrialsPerByte = 1000 - payloadLengthExtraBytes = 1000 + import queues + # queues.apiAddressGeneratorReturnQueue.queue.clear() + streamNumberForAddress = 1 + label = self.ids.label.text + eighteenByteRipe = False + nonceTrialsPerByte = 1000 + payloadLengthExtraBytes = 1000 + queues.addressGeneratorQueue.put(( + 'createRandomAddress', + 4, streamNumberForAddress, + label, 1, "", eighteenByteRipe, + nonceTrialsPerByte, + payloadLengthExtraBytes) + ) + self.manager.current = 'add_sucess' + print("whhhheeeeeeee55566666666666666666666..................", self) + print("what is the screeen forrrrrrrrrrrrrrrrr...............", self.ids) + self.ids.label.text = '' + # print("whatttttt99999999999999999999999999999999999988888888......", self.parent.parent) + # print("go.....more...parenxccccccccccccccccccccccc555559955555555555", self.parent.parent.parent) + # print("ssssshooooocxvxcvxcvoooouuuuuuuuuuuuuuuuuueeeettttttttteeeeeeeeeee............... ", ContentNavigationDrawer().ids.btn) + # print("spiiiiinnnxcvxcxc99999999999999999999999999999999999999tttt..........", ContentNavigationDrawer().ids.btn.text) + # print("text_dirrrrrrrrrrrrrrrrrrrrrr9999999999999999fgdg.............................", dir(ContentNavigationDrawer().ids.btn)) + # print("ttttttttttttttiiiiiiiiilllllllllllllllttttleeeeeeeee9999999999999999999", ContentNavigationDrawer().ids.btn.text) + # prnit("55555557777777777777777888888888888888888jjjjjjjjjj", ContentNavigationDrawer().ids.btn.text) + # print("what account is associated..............................", state.association) + # print("pppppppppp999999999666666666663333333333333333333333..............", BMConfigParser().addresses()) + # print("whatssssssssssssssssssssssstheva,lllllllllllleeeeeeeee...........") + # print("wh.....................8888888899999999999999999999999999", queues.addressGeneratorQueue.get()) - queues.addressGeneratorQueue.put(( - 'createRandomAddress', - 4, streamNumberForAddress, - label, 1, "", eighteenByteRipe, - nonceTrialsPerByte, - payloadLengthExtraBytes) - ) - self.manager.current = 'add_sucess' + # print("ljjkkkkkkkkkkkkkkkkkkk666666666666666666666666666666666", self.parent.parent.parent.parent.parent) + # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] + # if BMConfigParser().addresses(): + # print("iiiinnnnnnnnnnnnnnnnnnnnnnnnnnsssssssssssiiiiiiiiiideeeeeeeee") + # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] + # return BMConfigParser().addresses()[0] + # print("iiiiiiiiiiiiiihhhhhhhhhhhhhhhhh5555555555555555555....", ContentNavigationDrawer()) + # print("khhhhhhhhhhhhhyaaaaaaaaaaaaaaaa5555555555555555...............", ContentNavigationDrawer().ids) + # print("it is sccccccccccccefssssfulllllll............................", ContentNavigationDrawer().ids.btn.text) + # ids.btn.text -class SearchBar(TextInput, ActionItem): - """Create SearchBar for PyBitmessage.""" +class AddressSuccessful(Screen): + pass + + +class NavigationLayout(): + pass + +class Sent(Screen): + """Sent Screen uses screen to show widgets of screens.""" + data = ListProperty() def __init__(self, *args, **kwargs): - """Initailizes SearchBar with hint text.""" - super(SearchBar, self).__init__(*args, **kwargs) - self.hint_text = 'Search' + super(Sent, self).__init__(*args, **kwargs) + # print("I amuuuuuupfatgd vale should get..................... .", ContentNavigationDrawer().ids.btn.text) + # print("yyyyyyuuuuuuuuuuuuuuuuuoooooooooouuuyyyyyyyyyyyy...............", ContentNavigationDrawer().ids.btn.values) + # print("ccchekkkkkkkkkccccccccccclre..................................................", ContentNavigationDrawer().ids.btn) + # print("llllllllllleeeeetttttttttttttttttttttheeeeeeeeemmmmmmcheccccccccccckkk........", dir(ContentNavigationDrawer().ids.btn)) + # print("llllllllllllllllllllllllllleeeeeeeeeeeeeeeeeeeeeeeexfgcgcgvcgvcvgbeeechhhhhhhhhhheck", state.association) + if state.association == '': + # state.association = Navigatocoming inside thew methoddddddddddddddddddds1buildrss().ids.btn.text + print("uuuuuuuuuuuuuuuuuuuuuuuuu999999999999999999999999999999") + print("lllllllllllllllllllllllllllllll55555555556666666666", BMConfigParser().addresses()) + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + print("kkkkkkkkkkkkkkkkkkkkkkkkkkkk6666666666888888888888888888...................", state.association) + Clock.schedule_once(self.init_ui, 0) - def search(self): - """Search for message request.""" - request = self.text - return str(request) + def init_ui(self, dt=0): + """Clock Schdule for method sent accounts.""" + print("oooooooooooooooooooooooooooo999999999999999999999000000000") + self.sentaccounts() + print(dt) + + def sentaccounts(self): + """Load sent accounts.""" + print("mmmmmmmmmmmmmmmmmmmmmmmm44444444444444444455555555555__........") + account = state.association + print("zzzzzzzzzzzzzzzzzzzzzzz99999999999999999999999999999999999", account) + self.loadSent(account, 'All', '') + + def loadSent(self, account, where="", what=""): + """Load Sent list for Sent messages.""" + # print("uuuuuuuuuuuuuuuuyyyyyyyyyrrrrrrrrrrrinside_loadSent..........") + xAddress = 'fromaddress' + data = [] + # print("check--------thre.................somethiong.......cvmnvb mvn xmnvcxv.") + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "sent", where, what, False) + print("qqqqqqqq77777777777777777777777777777777555hhhhhhhhhhhhhhhfffffff....", queryreturn) + if queryreturn: + # for mail in sqlQuery("SELECT toaddress, subject, message FROM addressbook a, sent s WHERE a.address = s.fromaddress and s.fromaddress = 'BM-2cUz6dniZHjFTqv6j2es2wBSe3NydZdk4R';"): + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + print("whatttttttttttttttttttttttttttisssssssssssssssssssssssserrrrrrrrrrrrror") + print("nowwwwwwwwww9999999999999999999999999999999..................", third_text) + # print("sssssssssssssssseeeeeeeeeeeeeeeeeeeeeeeeeeeepprob.....", mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2]) + # data.append({'text': mail[0].strip(), 'secondary_text': mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) + # data.append({'text': '', 'secondary_text': mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) + data.append({'text': mail[0].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 }) + print("kyaaaaaaaaaaaaaaaaaaaaaaaaaayhaaaaaaaaaaaaerorrrrrrrrrr") + # self.data = [{ + # 'data_index': i, + # 'index': 1, + # 'height': 48, + # 'text': row[2], + # } + # for i, row in enumerate(queryreturn) + # ] + print("show 6666666666666666666eeeeeee555555555555555daaaaaaaaaaa.......", data) + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + print("uyyyyyyyyyyyyyyyyyyyyyyyyyuuuuuuuuuggg558888888888gggggggoooooooooooooooooooooooooooooooooooooooo....") + # print("ufffffffffffffffffffffffff6666666666666ffffyyyyyyyyyyyyyyyyyyyyyyyyypp.......", self.data) + else: + # self.data = [{ + # 'data_index': 1, + # 'index': 1, + # 'height': 48, + # 'text': "yet no message for this account!!!!!!!!!!!!!"} + # ] + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + +class Trash(Screen): + """Trash Screen uses screen to show widgets of screens.""" + def __init__(self, *args, **kwargs): + super(Trash, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + data = [{'text': "neha cis", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "paytm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "pol", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "akshayaura", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "codementor", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "yatra", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "mdtezm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "crewqt", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) -if __name__ == '__main__': - NavigateApp().run() +class Page(Screen): + pass + + +class Create(Screen): + def __init__(self, **kwargs): + super(Create, self).__init__(**kwargs) + # from kivy.core.window import Window + print("cheeeeeeeeeeeehn888888888888888888888888gggkkkkkkkthe windowwwwwwwwwwwwwwww", Window.size) + # print("take the onlyyyyyyyyyyyyyyyyyyyyyyyyyyyy x axssssssssssssssssssssssswindow", Window.size[0]) + # print("realllllllllllyyyyyyyyyyyyy yyyyyyyyyyyoooooouuuuuuu wwwwwwaaaaaaaaaaaannnnnnnnnntttt", Window._get_width) + # print("mmmmmmmmmmmmmminnnnnnnnnnnnnnnn and mmmmmmmmaaaaaaaaxxxxxxxesssssssss", Window.minimum_height, Window.minimum_width) + # print("dir in windowwwwwwwwwkkkkkkkkkkkww of the mobile screen", dir(Window)) + # print("cheeeeeeeeeeeeeeeeeckkkkkkkkkkkkkkkk width and heightttttttttttttttttttt", Window.width, window.height) + widget_1 = DropDownWidget() + from helper_sql import * + widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] + # widget_1.ids.txt_input.word_list = ['how to use python', 'how to use kivy', 'how to use django', 'BM-2cTik2JBHAS92U633LPY', 'BM-2cUYmQofWjTQeUitL7'] + widget_1.ids.txt_input.starting_no = 2 + self.add_widget(widget_1) + +class AddressSuccessful(Screen): + pass + + +class Setting(Screen): + pass + + +class NavigateApp(App): + theme_cls = ThemeManager() + previous_date = ObjectProperty() + obj_1 = ObjectProperty() + variable_1 = ListProperty(BMConfigParser().addresses()) + nav_drawer = ObjectProperty() + # user_address = StringProperty('jai') + scr_size = Window.size[0] + + title = "KivyMD" + count = 0 + menu_items = [ + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + ] + + def build(self): + print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllllllrrrrrrrrrrahut......') + print('chreckoooooooooooooooo........................', self.variable_1) + print("dsssssssssssoddddddddd77777777777777777777eeeeeeeeetheroot", dir(self)) + import os + main_widget = Builder.load_file( + os.path.join(os.path.dirname(__file__), 'main.kv')) + self.nav_drawer = Navigatorss() + self.obj_1 = AddressBook() + kivysignalthread = UIkivySignaler() + kivysignalthread.daemon = True + kivysignalthread.start() + return main_widget + + def run(self): + kivyuisignaler.release() + super(NavigateApp, self).run() + + def say_exit(self): + """Exit the application as uses shutdown PyBitmessage.""" + print("**************************EXITING FROM APPLICATION*****************************") + App.get_running_app().stop() + import shutdown + shutdown.doCleanShutdown() + + def show_address_success(self): + print("9062 I am pressed...............................................................") + content = MDLabel(font_style='Body1', + theme_text_color='Secondary', + text="Successfully Saved your contact address. " + "That's pretty awesome right!", + size_hint_y=None, + valign='top') + print("9063 I am pressed...............................................................") + content.bind(texture_size=content.setter('size')) + print("9064 I am pressed...............................................................") + # self.dialog = MDDialog(content=content, + # size_hint=(.8, None), + # height=dp(200), + # auto_dismiss=False) + print("9065 I am pressed...............................................................") + # self.dialog.add_action_button("Dismiss", + # action=lambda *x: self.dialog.dismiss()) + print("966 I am pressed...............................................................") + self.dialog.open() + + @staticmethod + def showmeaddresses(name="text"): + """Show the addresses in spinner to make as dropdown.""" + if name == "text": + # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' + if bmconfigparserigParser().addresses(): + return BMConfigParser().addresses()[0][:16] + '..' + else: + return "textdemo" + elif name == "values": + if BMConfigParser().addresses(): + return [address[:16] + '..' for address in BMConfigParser().addresses()] + else: + return "valuesdemo" + # return [BMConfigParser().get(address, 'label')[:12] + '..' for address in BMConfigParser().sections()[1:]] + # return BMConfigParser().addresses() + + def getCurrentAccountData(self, text): + """Get Current Address Account Data.""" + print("self tttttttttttttttttttttteeeeeeeeeexfgvbcvgfcgfdgfdgfgxxxxxxxxtttttttttzzzzzzzz ", text) + state.association = text + # print("eeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrorrrrrrrrrrrrrrrrrr", self.root) + # print("iiiiiiiiiiiiiidddddddddddddddddeeeeeeeessssssssssssssssss55......", self.root.ids) + self.root.ids.sc1.clear_widgets() + self.root.ids.sc4.clear_widgets() + self.root.ids.sc5.clear_widgets() + # print("resffffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuurrrrrrrrrrrrr......") + self.root.ids.sc1.add_widget(Inbox()) + self.root.ids.sc4.add_widget(Sent()) + self.root.ids.sc5.add_widget(Trash()) + # print("again aaaaddddddddddddddddddinggggggggggggggggguuuuuuuuuuuuuuuu1 ........") + + # self.root.ids.toolbar.title = BMConfigParser().get( + # state.association, 'label') + '({})'.format(state.association) + # print("what theyyyyyyyyyyyyyyyyyyyy areeeeeeeeeeeee printing11........", self.root.ids.toolbar.title) + # Inbox() + # Sent() + # Trash() + # print("finish gamneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!") + + def getInboxMessageDetail(self, instance): + """It will get message detail after make selected message description.""" + try: + self.root.ids._mngr.current = 'page' + except AttributeError: + self.parent.manager.current = 'page' + print('Message Clicked {}'.format(instance)) + + @staticmethod + def getCurrentAccount(): + """It uses to get current account label.""" + if state.association: + return state.association + else: + return "Bitmessage Login" + + def addingtoaddressbook(self): + p = GrashofPopup() + p.open() + + def getDefaultAccData(self): + print("coming inside thew methodddddddddddddddddddsdcassdfs1") + print("combbbbbbbbbbbbggggffffffdfgdgfffffffgggggggggggggggggggllllllloooo", BMConfigParser().addresses()) + # return BMConfigParser.addresses[0] + if BMConfigParser().addresses(): + return BMConfigParser().addresses()[0] + return 'Select Address' + + +class GrashofPopup(Popup): + def __init__(self, **kwargs): + super(GrashofPopup, self).__init__(**kwargs) + self.size_hint_y = 0.7 + self.size_hint_x = 0.9 + + def savecontact(self): + print("show the addedes addess in databaseeeeeeeeeeeeeeeeee............................") + print("1110 I am pressed...............................................................") + label = self.ids.label.text + print("2210 I am pressed...............................................................") + address = self.ids.address.text + print("3310 I am pressed...............................................................") + if label and address: + state.navinstance = self.parent.children[1] + queues.UISignalQueue.put(('rerenderAddressBook', '')) + self.dismiss() + sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + # self.parent.children[1].ids.sc11.clear_widgets() + # self.parent.children[1].ids.sc11.add_widget(AddressBook()) + + def show_error_message(self): + content = MDLabel(font_style='Body1', + theme_text_color='Secondary', + text="Hey you are not allowed to save blank address contact. " + "That's wrong!", + size_hint_y=None, + valign='top') + content.bind(texture_size=content.setter('size')) + self.dialog = MDDialog(content=content, + size_hint=(.8, None), + height=dp(200), + auto_dismiss=False) + + self.dialog.add_action_button("ok", + action=lambda *x: self.dialog.dismiss()) + self.dialog.open() + + +class AvatarSampleWidget(ILeftBody, Image): + pass + + +class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): + pass + + +class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): + + pass + + +class NavigationDrawerTwoLineListItem( + TwoLineListItem, NavigationDrawerHeaderBase): + + address_property = StringProperty() + + def __init__(self, **kwargs): + super(NavigationDrawerTwoLineListItem, self).__init__(**kwargs) + Clock.schedule_once(lambda dt: self.setup()) + + def setup(self): + """ + Binds Controller.current_account property. + """ + pass + # self.controller = App.get_running_app().controller + # self.controller.bind( + # current_account=lambda _, value: self.on_current_account(value)) + + def on_current_account(self, account): + pass + # e.g. deleting the last account, would set + # Controller.current_account to None + # if account is None: + # return + # address = "0x" + account.address.encode("hex") + # self.address_property = address + + def _update_specific_text_color(self, instance, value): + pass + + def _set_active(self, active, list): + pass \ No newline at end of file diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py new file mode 100644 index 00000000..41e532fe --- /dev/null +++ b/src/bitmessagekivy/uikivysignaler.py @@ -0,0 +1,23 @@ + +from threading import Thread +import state +import queues +from semaphores import kivyuisignaler +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure + +class UIkivySignaler(Thread): + + def run(self): + kivyuisignaler.acquire() + while state.shutdown == 0: + try: + command, data = queues.UISignalQueue.get() + print("ssssssseeeeeeeeeeeeeeeeeeeeeeeeeewuhatsacomment.................", command) + if command == 'writeNewAddressToTable': + label, address, streamNumber = data + state.kivyapp.variable_1.append(address) + elif command == 'rerenderAddressBook': + state.kivyapp.obj_1.refreshs() + + except Exception as e: + print(e) \ No newline at end of file diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 4efd0154..808b52da 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -18,6 +18,7 @@ sys.path.insert(0, app_dir) import depends + depends.check_dependencies() import ctypes @@ -231,7 +232,8 @@ class Main: if daemon: state.enableGUI = False # run without a UI - if state.enableGUI and not state.curses and not depends.check_pyqt(): + # is the application already running? If yes then exit. + if state.enableGUI and not state.curses and not state.kivy and not depends.check_pyqt(): sys.exit( 'PyBitmessage requires PyQt unless you want' ' to run it as a daemon and interact with it' @@ -269,9 +271,7 @@ class Main: defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) defaults.networkDefaultPayloadLengthExtraBytes = int( defaults.networkDefaultPayloadLengthExtraBytes / 100) - knownnodes.readKnownNodes() - # Not needed if objproc is disabled if state.enableObjProc: @@ -293,14 +293,11 @@ class Main: # The closeEvent should command this thread to exit gracefully. sqlLookup.daemon = False sqlLookup.start() - Inventory() # init # init, needs to be early because other thread may access it early Dandelion() - # Enable object processor and SMTP only if objproc enabled if state.enableObjProc: - # SMTP delivery thread if daemon and BMConfigParser().safeGet( "bitmessagesettings", "smtpdeliver", '') != '': @@ -322,18 +319,15 @@ class Main: # each object. objectProcessorThread.daemon = False objectProcessorThread.start() - # Start the cleanerThread singleCleanerThread = singleCleaner() # close the main program even if there are threads left singleCleanerThread.daemon = True singleCleanerThread.start() - # Not needed if objproc disabled if state.enableObjProc: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - # API is also objproc dependent if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): import api # pylint: disable=relative-import @@ -341,7 +335,6 @@ class Main: # close the main program even if there are threads left singleAPIThread.daemon = True singleAPIThread.start() - # start network components if networking is enabled if state.enableNetwork: BMConnectionPool() @@ -369,7 +362,6 @@ class Main: state.uploadThread.start() connectToStream(1) - if BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'upnp'): import upnp @@ -378,7 +370,6 @@ class Main: else: # Populate with hardcoded value (same as connectToStream above) state.streamsInWhichIAmParticipating.append(1) - if not daemon and state.enableGUI: if state.curses: if not depends.check_curses(): @@ -386,10 +377,12 @@ class Main: print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() + elif state.kivy: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') from bitmessagekivy.mpybit import NavigateApp - NavigateApp().run() + state.kivyapp = NavigateApp() + state.kivyapp.run() else: import bitmessageqt bitmessageqt.run() diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index 24775475..7c2188e6 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -78,7 +78,7 @@ void getnumthreads() #ifdef _WIN32 DWORD_PTR dwProcessAffinity, dwSystemAffinity; #elif __linux__ - cpu_set_t dwProcessAffinity; + // cpu_set_t dwProcessAffinity; #elif __OpenBSD__ int mib[2], core_count = 0; int dwProcessAffinity = 0; @@ -87,13 +87,13 @@ void getnumthreads() int dwProcessAffinity = 0; int32_t core_count = 0; #endif - size_t len = sizeof(dwProcessAffinity); - if (numthreads > 0) - return; + // size_t len = sizeof(dwProcessAffinity); + // if (numthreads > 0) + // return; #ifdef _WIN32 GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); #elif __linux__ - sched_getaffinity(0, len, &dwProcessAffinity); + // sched_getaffinity(0, len, &dwProcessAffinity); #elif __OpenBSD__ len2 = sizeof(core_count); mib[0] = CTL_HW; @@ -106,22 +106,22 @@ void getnumthreads() else if (sysctlbyname("hw.ncpu", &core_count, &len, 0, 0) == 0) numthreads = core_count; #endif - for (unsigned int i = 0; i < len * 8; i++) -#if defined(_WIN32) -#if defined(_MSC_VER) - if (dwProcessAffinity & (1i64 << i)) -#else // CYGWIN/MINGW - if (dwProcessAffinity & (1ULL << i)) -#endif -#elif defined __linux__ - if (CPU_ISSET(i, &dwProcessAffinity)) -#else - if (dwProcessAffinity & (1 << i)) -#endif - numthreads++; - if (numthreads == 0) // something failed - numthreads = 1; - printf("Number of threads: %i\n", (int)numthreads); +// for (unsigned int i = 0; i < len * 8; i++) +// #if defined(_WIN32) +// #if defined(_MSC_VER) +// if (dwProcessAffinity & (1i64 << i)) +// #else // CYGWIN/MINGW +// if (dwProcessAffinity & (1ULL << i)) +// #endif +// #elif defined __linux__ +// if (CPU_ISSET(i, &dwProcessAffinity)) +// #else +// if (dwProcessAffinity & (1 << i)) +// #endif +// numthreads++; +// if (numthreads == 0) // something failed +// numthreads = 1; +// printf("Number of threads: %i\n", (int)numthreads); } extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) @@ -146,7 +146,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # else pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); # ifdef __linux__ - pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); + pthread_setschedparam(threads[i], 0, &schparam); # else pthread_setschedparam(threads[i], SCHED_RR, &schparam); # endif diff --git a/src/buildozer.spec b/src/buildozer.spec index 07f9e6b2..cc91e880 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -1,10 +1,10 @@ [app] # (str) Title of your application -title = PyBitmessage +title = bluewhale # (str) Package name -package.name = PyBitmessage +package.name = bluewhale # (str) Package domain (needed for android/ios packaging) package.domain = org.test @@ -36,21 +36,20 @@ version = 0.1 # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy -requirements = python2, sqlite3, kivy, openssl +requirements = python2, sqlite3, kivy, openssl, bitmsghash, libexpat, kivymd # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes # requirements.source.kivy = ../../kivy -#requirements.source.sqlite3 = # (list) Garden requirements #garden_requirements = # (str) Presplash of the application -#presplash.filename = %(source.dir)s/data/presplash.png +presplash.filename = "images/presplas.gif" # (str) Icon of the application -#icon.filename = %(source.dir)s/data/icon.png +icon.filename ='images/if_android_1220385.png' # (str) Supported orientation (one of landscape, portrait or all) orientation = portrait @@ -66,8 +65,7 @@ orientation = portrait # author = © Copyright Info # change the major version of python used by the app -#osx.python_version = 2 - +osx.python_version = 3 # Kivy version to use osx.kivy_version = 1.9.1 @@ -87,31 +85,31 @@ fullscreen = 0 #android.presplash_color = #FFFFFF # (list) Permissions -android.permissions = INTERNET +android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE # (int) Android API to use -#android.api = 19 +android.api = 19 # (int) Minimum API required #android.minapi = 9 # (int) Android SDK version to use -#android.sdk = 20 +android.sdk = 20 # (str) Android NDK version to use -#android.ndk = 9c +android.ndk = 10e # (bool) Use --private data storage (True) or --dir public storage (False) #android.private_storage = True # (str) Android NDK directory (if empty, it will be automatically downloaded.) -#android.ndk_path = +android.ndk_path =/home/cis/Downloads/android-ndk-r10e # (str) Android SDK directory (if empty, it will be automatically downloaded.) -#android.sdk_path = +android.sdk_path =/home/cis/Android/Sdk # (str) ANT directory (if empty, it will be automatically downloaded.) -#android.ant_path = +android.ant_path =/home/cis/apache-ant-1.10.5 # (bool) If True, then skip trying to update the Android sdk # This can be useful to avoid excess Internet downloads or save time @@ -124,9 +122,6 @@ android.permissions = INTERNET # (list) Pattern to whitelist for the whole project #android.whitelist = -android.whitelist = /usr/lib/komodo-edit/python/lib/python2.7/lib-dynload/_sqlite3.so - - # (str) Path to a custom whitelist file #android.whitelist_src = @@ -150,9 +145,9 @@ android.whitelist = /usr/lib/komodo-edit/python/lib/python2.7/lib-dynload/_sqlit # (list) Gradle dependencies to add (currently works only with sdl2_gradle # bootstrap) #android.gradle_dependencies = -, /home/cis/Downloads/libssl1.0.2_1.0.2l-2+deb9u2_amd64 -# (str) python-for-android branch to use, defaults to stable -#p4a.branch = stable + +# (str) python-for-android branch to use, defaults to master +p4a.branch = master # (str) OUYA Console category. Should be one of GAME or APP # If you leave this blank, OUYA support will not be enabled @@ -198,7 +193,7 @@ android.arch = armeabi-v7a #p4a.source_dir = # (str) The directory in which python-for-android should look for your own build recipes (if any) -#p4a.local_recipes = +p4a.local_recipes =/home/cis/Desktop/Mobileandroid/peter_android/PyBitmessage/src/bitmessagekivy/android/python-for-android/recipes/ # (str) Filename to the hook for p4a #p4a.hook = diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 0893b73a..ac4c53da 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -5,7 +5,6 @@ import hashlib from binascii import hexlify from pyelliptic import arithmetic from pyelliptic.openssl import OpenSSL - import tr import queues import state @@ -34,6 +33,7 @@ class addressGenerator(threading.Thread, StoppableThread): super(addressGenerator, self).stopThread() def run(self): + while state.shutdown == 0: queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 @@ -115,9 +115,7 @@ class addressGenerator(threading.Thread, StoppableThread): defaults.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': queues.UISignalQueue.put(( - 'updateStatusBar', - tr._translate( - "MainWindow", "Generating one new address") + 'updateStatusBar' )) # This next section is a little bit strange. We're going # to generate keys over and over until we find one @@ -174,7 +172,6 @@ class addressGenerator(threading.Thread, StoppableThread): privEncryptionKey).digest()).digest()[0:4] privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKey + checksum, 256, 58) - BMConfigParser().add_section(address) BMConfigParser().set(address, 'label', label) BMConfigParser().set(address, 'enabled', 'true') @@ -194,11 +191,7 @@ class addressGenerator(threading.Thread, StoppableThread): queues.apiAddressGeneratorReturnQueue.put(address) queues.UISignalQueue.put(( - 'updateStatusBar', - tr._translate( - "MainWindow", - "Done generating address. Doing work necessary" - " to broadcast it...") + 'updateStatusBar' )) queues.UISignalQueue.put(('writeNewAddressToTable', ( label, address, streamNumber))) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index d979ae19..33542a73 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -32,6 +32,8 @@ from helper_sql import sqlExecute, sqlQuery from helper_threading import StoppableThread from inventory import Inventory +# This thread, of which there is only one, does the heavy lifting: +# calculating POWs. def sizeof_fmt(num, suffix='h/s'): """Format hashes per seconds nicely (SI prefix)""" @@ -50,6 +52,7 @@ class singleWorker(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="singleWorker") self.initStop() proofofwork.init() + print("I am in single worker 52.....................................................") def stopThread(self): """Signal through the queue that the thread should be stopped""" diff --git a/src/debug.py b/src/debug.py index d3730d7f..082497d2 100644 --- a/src/debug.py +++ b/src/debug.py @@ -32,7 +32,7 @@ import helper_startup import state helper_startup.loadConfig() - +print("333333333333333333333333333333333333333333333333333333333333333333333333333333333") # Now can be overriden from a config file, which uses standard python # logging.config.fileConfig interface # examples are here: diff --git a/src/depends.py b/src/depends.py index 0114ec94..5a8b9a74 100755 --- a/src/depends.py +++ b/src/depends.py @@ -17,7 +17,7 @@ if not hasattr(sys, 'hexversion') or sys.hexversion < 0x20300F0: import logging import os from importlib import import_module - +import state # We can now use logging so set up a simple configuration formatter = logging.Formatter('%(levelname)s: %(message)s') handler = logging.StreamHandler(sys.stdout) @@ -231,6 +231,7 @@ def check_sqlite(): def check_openssl(): + print(state.kivy, "state.kivystate.kivystate.kivystate.kivystate.kivystate.kivystate.kivystate.kivy") """Do openssl dependency check. Here we are checking for openssl with its all dependent libraries @@ -248,8 +249,12 @@ def check_openssl(): if getattr(sys, 'frozen', False): import os.path paths.insert(0, os.path.join(sys._MEIPASS, 'libeay32.dll')) + elif state.kivy: + print("kivykivykivykivykivykivykivy...........................") + return True else: paths = ['libcrypto.so', 'libcrypto.so.1.0.0'] + if sys.platform == 'darwin': paths.extend([ 'libcrypto.dylib', @@ -278,6 +283,7 @@ def check_openssl(): logger.info('Checking OpenSSL at %s', path) try: library = ctypes.CDLL(path) + print("I am loading here in depends file................................................................") except OSError: continue logger.info('OpenSSL Name: %s', library._name) @@ -425,7 +431,6 @@ def check_dependencies(verbose=False, optional=False): check_functions = [check_ripemd160, check_sqlite, check_openssl] if optional: check_functions.extend([check_msgpack, check_pyqt, check_curses]) - # Unexpected exceptions are handled here for check in check_functions: try: diff --git a/src/helper_generic.py b/src/helper_generic.py new file mode 100644 index 00000000..368a6c54 --- /dev/null +++ b/src/helper_generic.py @@ -0,0 +1,114 @@ +""" +Helper Generic perform generic operations for threading. + +Also perform some conversion operations. +""" + +import socket +import sys +import threading +import traceback +try: + import multiprocessing +except Exception as e: + pass +from binascii import hexlify, unhexlify + +import shared +import state +import queues +import shutdown +from debug import logger + + +def powQueueSize(): + curWorkerQueue = queues.workerQueue.qsize() + for thread in threading.enumerate(): + try: + if thread.name == "singleWorker": + curWorkerQueue += thread.busy + except Exception as err: + logger.info('Thread error %s', err) + return curWorkerQueue + + +def convertIntToString(n): + a = __builtins__.hex(n) + if a[-1:] == 'L': + a = a[:-1] + if (len(a) % 2) == 0: + return unhexlify(a[2:]) + else: + return unhexlify('0' + a[2:]) + + +def convertStringToInt(s): + return int(hexlify(s), 16) + + +def allThreadTraceback(frame): + id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) + code = [] + for threadId, stack in sys._current_frames().items(): + code.append( + '\n# Thread: %s(%d)' % (id2name.get(threadId, ''), threadId)) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append( + 'File: "%s", line %d, in %s' % (filename, lineno, name)) + if line: + code.append(' %s' % (line.strip())) + print('\n'.join(code)) + + +def signal_handler(signal, frame): + try: + process = multiprocessing.current_process() + except Exception as e: + process = threading.current_thread() + logger.error( + 'Got signal %i in %s/%s', + signal, process.name, threading.current_thread().name + ) + if process.name == "RegExParser": + # on Windows this isn't triggered, but it's fine, + # it has its own process termination thing + raise SystemExit + if "PoolWorker" in process.name: + raise SystemExit + if threading.current_thread().name not in ("PyBitmessage", "MainThread"): + return + logger.error("Got signal %i", signal) + if shared.thisapp.daemon or not state.enableGUI: # FIXME redundant? + shutdown.doCleanShutdown() + else: + allThreadTraceback(frame) + print('Unfortunately you cannot use Ctrl+C when running the UI' + ' because the UI captures the signal.') + + +def isHostInPrivateIPRange(host): + if ":" in host: # IPv6 + hostAddr = socket.inet_pton(socket.AF_INET6, host) + if hostAddr == ('\x00' * 15) + '\x01': + return False + if hostAddr[0] == '\xFE' and (ord(hostAddr[1]) & 0xc0) == 0x80: + return False + if (ord(hostAddr[0]) & 0xfe) == 0xfc: + return False + elif ".onion" not in host: + if host[:3] == '10.': + return True + if host[:4] == '172.': + if host[6] == '.': + if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: + return True + if host[:8] == '192.168.': + return True + # Multicast + if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.': + return True + return False + + +def addDataPadding(data, desiredMsgLength=12, paddingChar='\x00'): + return data + paddingChar * (desiredMsgLength - len(data)) diff --git a/src/helper_startup.py b/src/helper_startup.py index 1a1119f5..6b60bdd2 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -44,6 +44,8 @@ def _loadTrustedPeer(): def loadConfig(): """Load the config""" config = BMConfigParser() + print("I am coming in loadConfig now................................................................") + if state.appdata: config.read(state.appdata + 'keys.dat') # state.appdata must have been specified as a startup option. diff --git a/src/images/account_multiple.png b/src/images/account_multiple.png new file mode 100644 index 0000000000000000000000000000000000000000..112716197dbe10f0191e2cb2f03b11e623e9af62 GIT binary patch literal 9798 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 QA{c13Im8JGjX{o5? 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 literal 0 HcmV?d00001 diff --git a/src/kivymd/LICENSE b/src/kivymd/LICENSE deleted file mode 100644 index a17ea136..00000000 --- a/src/kivymd/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrés Rodríguez and KivyMD contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/src/kivymd/__init__.py b/src/kivymd/__init__.py deleted file mode 100644 index bc07270c..00000000 --- a/src/kivymd/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -import os - -path = os.path.dirname(__file__) -fonts_path = os.path.join(path, "fonts/") -images_path = os.path.join(path, 'images/') diff --git a/src/kivymd/accordion.py b/src/kivymd/accordion.py deleted file mode 100644 index 6e816ca6..00000000 --- a/src/kivymd/accordion.py +++ /dev/null @@ -1,254 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, OptionProperty -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.accordion import Accordion, AccordionItem -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivy.uix.boxlayout import BoxLayout - - -class MDAccordionItemTitleLayout(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - pass - - -class MDAccordion(ThemableBehavior, BackgroundColorBehavior, Accordion): - pass - - -class MDAccordionItem(ThemableBehavior, AccordionItem): - title_theme_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - ''' Color theme for title text and icon ''' - - title_color = ListProperty(None, allownone=True) - ''' Color for title text and icon if `title_theme_color` is Custom ''' - - background_color = ListProperty(None, allownone=True) - ''' Color for the background of the accordian item title in rgba format. - ''' - - divider_color = ListProperty(None, allownone=True) - ''' Color for dividers between different titles in rgba format - To remove the divider set a color with an alpha of 0. - ''' - - indicator_color = ListProperty(None, allownone=True) - ''' Color for the indicator on the side of the active item in rgba format - To remove the indicator set a color with an alpha of 0. - ''' - - font_style = OptionProperty( - 'Subhead', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - ''' Font style to use for the title text ''' - - title_template = StringProperty('MDAccordionItemTitle') - ''' Template to use for the title ''' - - icon = StringProperty(None,allownone=True) - ''' Icon name to use when this item is expanded ''' - - icon_expanded = StringProperty('chevron-up') - ''' Icon name to use when this item is expanded ''' - - icon_collapsed = StringProperty('chevron-down') - ''' Icon name to use when this item is collapsed ''' - - -Builder.load_string(''' -#:import MDLabel kivymd.label.MDLabel -#:import md_icons kivymd.icon_definitions.md_icons - - -: - canvas.before: - Color: - rgba: self.background_color or self.theme_cls.primary_color - Rectangle: - size:self.size - pos:self.pos - - PushMatrix - Translate: - xy: (dp(2),0) if self.orientation == 'vertical' else (0,dp(2)) - canvas.after: - PopMatrix - Color: - rgba: self.divider_color or self.theme_cls.divider_color - Rectangle: - size:(dp(1),self.height) if self.orientation == 'horizontal' else (self.width,dp(1)) - pos:self.pos - Color: - rgba: [0,0,0,0] if self.collapse else (self.indicator_color or self.theme_cls.accent_color) - Rectangle: - size:(dp(2),self.height) if self.orientation == 'vertical' else (self.width,dp(2)) - pos:self.pos - -[MDAccordionItemTitle@MDAccordionItemTitleLayout]: - padding: '12dp' - spacing: '12dp' - orientation: 'horizontal' if ctx.item.orientation=='vertical' else 'vertical' - canvas: - PushMatrix - Translate: - xy: (-dp(2),0) if ctx.item.orientation == 'vertical' else (0,-dp(2)) - - Color: - rgba: self.background_color or self.theme_cls.primary_color - Rectangle: - size:self.size - pos:self.pos - - canvas.after: - Color: - rgba: [0,0,0,0] if ctx.item.collapse else (ctx.item.indicator_color or self.theme_cls.accent_color) - Rectangle: - size:(dp(2),self.height) if ctx.item.orientation == 'vertical' else (self.width,dp(2)) - pos:self.pos - PopMatrix - MDLabel: - id:_icon - theme_text_color:ctx.item.title_theme_color if ctx.item.icon else 'Custom' - text_color:ctx.item.title_color if ctx.item.icon else [0,0,0,0] - text: md_icons[ctx.item.icon if ctx.item.icon else 'menu'] - font_style:'Icon' - size_hint: (None,1) if ctx.item.orientation == 'vertical' else (1,None) - size: ((self.texture_size[0],1) if ctx.item.orientation == 'vertical' else (1,self.texture_size[1])) \ - if ctx.item.icon else (0,0) - text_size: (self.width, None) if ctx.item.orientation=='vertical' else (None,self.width) - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin: self.center - canvas.after: - PopMatrix - MDLabel: - id:_label - theme_text_color:ctx.item.title_theme_color - text_color:ctx.item.title_color - text: ctx.item.title - font_style:ctx.item.font_style - text_size: (self.width, None) if ctx.item.orientation=='vertical' else (None,self.width) - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin: self.center - canvas.after: - PopMatrix - - MDLabel: - id:_expand_icon - theme_text_color:ctx.item.title_theme_color - text_color:ctx.item.title_color - font_style:'Icon' - size_hint: (None,1) if ctx.item.orientation == 'vertical' else (1,None) - size: (self.texture_size[0],1) if ctx.item.orientation == 'vertical' else (1,self.texture_size[1]) - text:md_icons[ctx.item.icon_collapsed if ctx.item.collapse else ctx.item.icon_expanded] - halign: 'right' if ctx.item.orientation=='vertical' else 'center' - #valign: 'middle' if ctx.item.orientation=='vertical' else 'bottom' - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin:self.center - canvas.after: - PopMatrix - -''') - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class AccordionApp(App): - theme_cls = ThemeManager() - - def build(self): - # self.theme_cls.primary_palette = 'Indigo' - return Builder.load_string(""" -#:import MDLabel kivymd.label.MDLabel -#:import MDList kivymd.list.MDList -#:import OneLineListItem kivymd.list.OneLineListItem -BoxLayout: - spacing: '64dp' - MDAccordion: - orientation:'vertical' - MDAccordionItem: - title:'Item 1' - icon: 'home' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 1" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 2" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 3" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordionItem: - title:'Item 2' - icon: 'globe' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 4" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 5" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 6" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordionItem: - title:'Item 3' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 7" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 8" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 9" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordion: - orientation:'horizontal' - MDAccordionItem: - title:'Item 1' - icon: 'home' - MDLabel: - text:'Content 1' - theme_text_color:'Primary' - MDAccordionItem: - title:'Item 2' - MDLabel: - text:'Content 2' - theme_text_color:'Primary' - MDAccordionItem: - title:'Item 3' - MDLabel: - text:'Content 3' - theme_text_color:'Primary' -""") - - - AccordionApp().run() diff --git a/src/kivymd/backgroundcolorbehavior.py b/src/kivymd/backgroundcolorbehavior.py deleted file mode 100644 index bd98f129..00000000 --- a/src/kivymd/backgroundcolorbehavior.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.properties import BoundedNumericProperty, ReferenceListProperty -from kivy.uix.widget import Widget - -Builder.load_string(''' - - canvas: - Color: - rgba: self.background_color - Rectangle: - size: self.size - pos: self.pos -''') - - -class BackgroundColorBehavior(Widget): - r = BoundedNumericProperty(1., min=0., max=1.) - g = BoundedNumericProperty(1., min=0., max=1.) - b = BoundedNumericProperty(1., min=0., max=1.) - a = BoundedNumericProperty(0., min=0., max=1.) - - background_color = ReferenceListProperty(r, g, b, a) diff --git a/src/kivymd/bottomsheet.py b/src/kivymd/bottomsheet.py deleted file mode 100644 index 901322b0..00000000 --- a/src/kivymd/bottomsheet.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Bottom Sheets -============= - -`Material Design spec Bottom Sheets page `_ - -In this module there's the :class:`MDBottomSheet` class which will let you implement your own Material Design Bottom Sheets, and there are two classes called :class:`MDListBottomSheet` and :class:`MDGridBottomSheet` implementing the ones mentioned in the spec. - -Examples --------- - -.. note:: - - These widgets are designed to be called from Python code only. - -For :class:`MDListBottomSheet`: - -.. code-block:: python - - bs = MDListBottomSheet() - bs.add_item("Here's an item with text only", lambda x: x) - bs.add_item("Here's an item with an icon", lambda x: x, icon='md-cast') - bs.add_item("Here's another!", lambda x: x, icon='md-nfc') - bs.open() - -For :class:`MDListBottomSheet`: - -.. code-block:: python - - bs = MDGridBottomSheet() - bs.add_item("Facebook", lambda x: x, icon_src='./assets/facebook-box.png') - bs.add_item("YouTube", lambda x: x, icon_src='./assets/youtube-play.png') - bs.add_item("Twitter", lambda x: x, icon_src='./assets/twitter.png') - bs.add_item("Da Cloud", lambda x: x, icon_src='./assets/cloud-upload.png') - bs.add_item("Camera", lambda x: x, icon_src='./assets/camera.png') - bs.open() - -API ---- -''' -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.gridlayout import GridLayout -from kivy.uix.modalview import ModalView -from kivy.uix.scrollview import ScrollView -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.label import MDLabel -from kivymd.list import MDList, OneLineListItem, ILeftBody, \ - OneLineIconListItem -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - background: 'atlas://data/images/defaulttheme/action_group_disabled' - background_color: 0,0,0,.8 - sv: sv - upper_padding: upper_padding - gl_content: gl_content - ScrollView: - id: sv - do_scroll_x: False - BoxLayout: - size_hint_y: None - orientation: 'vertical' - padding: 0,1,0,0 - height: upper_padding.height + gl_content.height + 1 # +1 to allow overscroll - BsPadding: - id: upper_padding - size_hint_y: None - height: root.height - min(root.width * 9 / 16, gl_content.height) - on_release: root.dismiss() - BottomSheetContent: - id: gl_content - size_hint_y: None - background_color: root.theme_cls.bg_normal - cols: 1 -''') - - -class BsPadding(ButtonBehavior, FloatLayout): - pass - - -class BottomSheetContent(BackgroundColorBehavior, GridLayout): - pass - - -class MDBottomSheet(ThemableBehavior, ModalView): - sv = ObjectProperty() - upper_padding = ObjectProperty() - gl_content = ObjectProperty() - dismiss_zone_scroll = 1000 # Arbitrary high number - - def open(self, *largs): - super(MDBottomSheet, self).open(*largs) - Clock.schedule_once(self.set_dismiss_zone, 0) - - def set_dismiss_zone(self, *largs): - # Scroll to right below overscroll threshold: - self.sv.scroll_y = 1 - self.sv.convert_distance_to_scroll(0, 1)[1] - - # This is a line where m (slope) is 1/6 and b (y-intercept) is 80: - self.dismiss_zone_scroll = self.sv.convert_distance_to_scroll( - 0, (self.height - self.upper_padding.height) * (1 / 6.0) + 80)[ - 1] - # Uncomment next line if the limit should just be half of - # visible content on open (capped by specs to 16 units to width/9: - # self.dismiss_zone_scroll = (self.sv.convert_distance_to_scroll( - # 0, self.height - self.upper_padding.height)[1] * 0.50) - - # Check if user has overscrolled enough to dismiss bottom sheet: - self.sv.bind(on_scroll_stop=self.check_if_scrolled_to_death) - - def check_if_scrolled_to_death(self, *largs): - if self.sv.scroll_y >= 1 + self.dismiss_zone_scroll: - self.dismiss() - - def add_widget(self, widget, index=0): - if type(widget) == ScrollView: - super(MDBottomSheet, self).add_widget(widget, index) - else: - self.gl_content.add_widget(widget,index) - - -Builder.load_string(''' -#:import md_icons kivymd.icon_definitions.md_icons - - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - halign: 'center' - theme_text_color: 'Primary' - valign: 'middle' -''') - - -class ListBSIconLeft(ILeftBody, MDLabel): - icon = StringProperty() - - -class MDListBottomSheet(MDBottomSheet): - mlist = ObjectProperty() - - def __init__(self, **kwargs): - super(MDListBottomSheet, self).__init__(**kwargs) - self.mlist = MDList() - self.gl_content.add_widget(self.mlist) - Clock.schedule_once(self.resize_content_layout, 0) - - def resize_content_layout(self, *largs): - self.gl_content.height = self.mlist.height - - def add_item(self, text, callback, icon=None): - if icon: - item = OneLineIconListItem(text=text, on_release=callback) - item.add_widget(ListBSIconLeft(icon=icon)) - else: - item = OneLineListItem(text=text, on_release=callback) - - item.bind(on_release=lambda x: self.dismiss()) - self.mlist.add_widget(item) - - -Builder.load_string(''' - - orientation: 'vertical' - padding: 0, dp(24), 0, 0 - size_hint_y: None - size: dp(64), dp(96) - BoxLayout: - padding: dp(8), 0, dp(8), dp(8) - size_hint_y: None - height: dp(48) - Image: - source: root.source - MDLabel: - font_style: 'Caption' - theme_text_color: 'Secondary' - text: root.caption - halign: 'center' -''') - - -class GridBSItem(ButtonBehavior, BoxLayout): - source = StringProperty() - - caption = StringProperty() - - -class MDGridBottomSheet(MDBottomSheet): - def __init__(self, **kwargs): - super(MDGridBottomSheet, self).__init__(**kwargs) - self.gl_content.padding = (dp(16), 0, dp(16), dp(24)) - self.gl_content.height = dp(24) - self.gl_content.cols = 3 - - def add_item(self, text, callback, icon_src): - item = GridBSItem( - caption=text, - on_release=callback, - source=icon_src - ) - item.bind(on_release=lambda x: self.dismiss()) - if len(self.gl_content.children) % 3 == 0: - self.gl_content.height += dp(96) - self.gl_content.add_widget(item) diff --git a/src/kivymd/button.py b/src/kivymd/button.py deleted file mode 100644 index 75016716..00000000 --- a/src/kivymd/button.py +++ /dev/null @@ -1,453 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Buttons -======= - -`Material Design spec, Buttons page `_ - -`Material Design spec, Buttons: Floating Action Button page `_ - -TO-DO: DOCUMENT MODULE -''' -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.utils import get_color_from_hex -from kivy.properties import StringProperty, BoundedNumericProperty, \ - ListProperty, AliasProperty, BooleanProperty, NumericProperty, \ - OptionProperty -from kivy.uix.anchorlayout import AnchorLayout -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.animation import Animation -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.ripplebehavior import CircularRippleBehavior, \ - RectangularRippleBehavior -from kivymd.elevationbehavior import ElevationBehavior, \ - RoundElevationBehavior -from kivymd.theming import ThemableBehavior -from kivymd.color_definitions import colors - -Builder.load_string(''' -#:import md_icons kivymd.icon_definitions.md_icons -#:import colors kivymd.color_definitions.colors -#:import MDLabel kivymd.label.MDLabel - - size_hint: (None, None) - size: (dp(48), dp(48)) - padding: dp(12) - theme_text_color: 'Primary' - MDLabel: - id: _label - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - halign: 'center' - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - valign: 'middle' - - - canvas: - Color: - #rgba: self.background_color if self.state == 'normal' else self._bg_color_down - rgba: self._current_button_color - Rectangle: - size: self.size - pos: self.pos - size_hint: (None, None) - height: dp(36) - width: _label.texture_size[0] + dp(16) - padding: (dp(8), 0) - theme_text_color: 'Custom' - text_color: root.theme_cls.primary_color - MDLabel: - id: _label - text: root._text - font_style: 'Button' - size_hint_x: None - text_size: (None, root.height) - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - valign: 'middle' - halign: 'center' - opposite_colors: root.opposite_colors - -: - canvas: - Clear - Color: - rgba: self.background_color_disabled if self.disabled else \ - (self.background_color if self.state == 'normal' else self.background_color_down) - Rectangle: - size: self.size - pos: self.pos - - anchor_x: 'center' - anchor_y: 'center' - background_color: root.theme_cls.primary_color - background_color_down: root.theme_cls.primary_dark - background_color_disabled: root.theme_cls.divider_color - theme_text_color: 'Primary' - MDLabel: - id: label - font_style: 'Button' - text: root._text - size_hint: None, None - width: root.width - text_size: self.width, None - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - disabled: root.disabled - halign: 'center' - valign: 'middle' - -: - canvas: - Clear - Color: - rgba: self.background_color_disabled if self.disabled else \ - (self.background_color if self.state == 'normal' else self.background_color_down) - Ellipse: - size: self.size - pos: self.pos - - anchor_x: 'center' - anchor_y: 'center' - background_color: root.theme_cls.accent_color - background_color_down: root.theme_cls.accent_dark - background_color_disabled: root.theme_cls.divider_color - theme_text_color: 'Primary' - MDLabel: - id: label - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - size_hint: None, None - size: dp(24), dp(24) - text_size: self.size - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - disabled: root.disabled - halign: 'center' - valign: 'middle' -''') - - -class MDIconButton(CircularRippleBehavior, ButtonBehavior, BoxLayout): - icon = StringProperty('circle') - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - opposite_colors = BooleanProperty(False) - - -class MDFlatButton(ThemableBehavior, RectangularRippleBehavior, - ButtonBehavior, BackgroundColorBehavior, AnchorLayout): - width = BoundedNumericProperty(dp(64), min=dp(64), max=None, - errorhandler=lambda x: dp(64)) - - text_color = ListProperty() - - text = StringProperty('') - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - _text = StringProperty('') - _bg_color_down = ListProperty([0, 0, 0, 0]) - _current_button_color = ListProperty([0, 0, 0, 0]) - - def __init__(self, **kwargs): - super(MDFlatButton, self).__init__(**kwargs) - self._current_button_color = self.background_color - self._bg_color_down = get_color_from_hex( - colors[self.theme_cls.theme_style]['FlatButtonDown']) - - Clock.schedule_once(lambda x: self.ids._label.bind( - texture_size=self.update_width_on_label_texture)) - - def update_width_on_label_texture(self, instance, value): - self.ids._label.width = value[0] - - def on_text(self, instance, value): - self._text = value.upper() - - def on_touch_down(self, touch): - if touch.is_mouse_scrolling: - return False - elif not self.collide_point(touch.x, touch.y): - return False - elif self in touch.ud: - return False - elif self.disabled: - return False - else: - self.fade_bg = Animation(duration=.2, _current_button_color=get_color_from_hex( - colors[self.theme_cls.theme_style]['FlatButtonDown'])) - self.fade_bg.start(self) - return super(MDFlatButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if touch.grab_current is self: - self.fade_bg.stop_property(self, '_current_button_color') - Animation(duration=.05, _current_button_color=self.background_color).start(self) - return super(MDFlatButton, self).on_touch_up(touch) - - -class MDRaisedButton(ThemableBehavior, RectangularRippleBehavior, - ElevationBehavior, ButtonBehavior, - AnchorLayout): - _bg_color_down = ListProperty([]) - background_color = ListProperty() - background_color_down = ListProperty() - background_color_disabled = ListProperty() - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - def _get_bg_color_down(self): - return self._bg_color_down - - def _set_bg_color_down(self, color, alpha=None): - if len(color) == 2: - self._bg_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_down[3] = alpha - elif len(color) == 4: - self._bg_color_down = color - - background_color_down = AliasProperty(_get_bg_color_down, - _set_bg_color_down, - bind=('_bg_color_down',)) - - _bg_color_disabled = ListProperty([]) - - def _get_bg_color_disabled(self): - return self._bg_color_disabled - - def _set_bg_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._bg_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_disabled[3] = alpha - elif len(color) == 4: - self._bg_color_disabled = color - - background_color_disabled = AliasProperty(_get_bg_color_disabled, - _set_bg_color_disabled, - bind=('_bg_color_disabled',)) - - _elev_norm = NumericProperty(2) - - def _get_elev_norm(self): - return self._elev_norm - - def _set_elev_norm(self, value): - self._elev_norm = value if value <= 12 else 12 - self._elev_raised = (value + 6) if value + 6 <= 12 else 12 - self.elevation = self._elev_norm - - elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm, - bind=('_elev_norm',)) - - _elev_raised = NumericProperty(8) - - def _get_elev_raised(self): - return self._elev_raised - - def _set_elev_raised(self, value): - self._elev_raised = value if value + self._elev_norm <= 12 else 12 - - elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised, - bind=('_elev_raised',)) - - text = StringProperty() - - _text = StringProperty() - - def __init__(self, **kwargs): - super(MDRaisedButton, self).__init__(**kwargs) - self.elevation_press_anim = Animation(elevation=self.elevation_raised, - duration=.2, t='out_quad') - self.elevation_release_anim = Animation( - elevation=self.elevation_normal, duration=.2, t='out_quad') - - def on_disabled(self, instance, value): - if value: - self.elevation = 0 - else: - self.elevation = self.elevation_normal - super(MDRaisedButton, self).on_disabled(instance, value) - - def on_touch_down(self, touch): - if not self.disabled: - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - if self in touch.ud: - return False - Animation.cancel_all(self, 'elevation') - self.elevation_press_anim.start(self) - return super(MDRaisedButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if not self.disabled: - if touch.grab_current is not self: - return super(ButtonBehavior, self).on_touch_up(touch) - Animation.cancel_all(self, 'elevation') - self.elevation_release_anim.start(self) - else: - Animation.cancel_all(self, 'elevation') - self.elevation = 0 - return super(MDRaisedButton, self).on_touch_up(touch) - - def on_text(self, instance, text): - self._text = text.upper() - - def on__elev_norm(self, instance, value): - self.elevation_release_anim = Animation(elevation=value, - duration=.2, t='out_quad') - - def on__elev_raised(self, instance, value): - self.elevation_press_anim = Animation(elevation=value, - duration=.2, t='out_quad') - - -class MDFloatingActionButton(ThemableBehavior, CircularRippleBehavior, - RoundElevationBehavior, ButtonBehavior, - AnchorLayout): - _bg_color_down = ListProperty([]) - background_color = ListProperty() - background_color_down = ListProperty() - background_color_disabled = ListProperty() - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - def _get_bg_color_down(self): - return self._bg_color_down - - def _set_bg_color_down(self, color, alpha=None): - if len(color) == 2: - self._bg_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_down[3] = alpha - elif len(color) == 4: - self._bg_color_down = color - - background_color_down = AliasProperty(_get_bg_color_down, - _set_bg_color_down, - bind=('_bg_color_down',)) - - _bg_color_disabled = ListProperty([]) - - def _get_bg_color_disabled(self): - return self._bg_color_disabled - - def _set_bg_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._bg_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_disabled[3] = alpha - elif len(color) == 4: - self._bg_color_disabled = color - - background_color_disabled = AliasProperty(_get_bg_color_disabled, - _set_bg_color_disabled, - bind=('_bg_color_disabled',)) - icon = StringProperty('android') - - _elev_norm = NumericProperty(6) - - def _get_elev_norm(self): - return self._elev_norm - - def _set_elev_norm(self, value): - self._elev_norm = value if value <= 12 else 12 - self._elev_raised = (value + 6) if value + 6 <= 12 else 12 - self.elevation = self._elev_norm - - elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm, - bind=('_elev_norm',)) - - # _elev_raised = NumericProperty(12) - _elev_raised = NumericProperty(6) - - def _get_elev_raised(self): - return self._elev_raised - - def _set_elev_raised(self, value): - self._elev_raised = value if value + self._elev_norm <= 12 else 12 - - elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised, - bind=('_elev_raised',)) - - def __init__(self, **kwargs): - if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12: - self.elevation_raised = self.elevation_normal + 6 - elif self.elevation_raised == 0: - self.elevation_raised = 12 - - super(MDFloatingActionButton, self).__init__(**kwargs) - - self.elevation_press_anim = Animation(elevation=self.elevation_raised, - duration=.2, t='out_quad') - self.elevation_release_anim = Animation( - elevation=self.elevation_normal, duration=.2, t='out_quad') - - def _set_ellipse(self, instance, value): - ellipse = self.ellipse - ripple_rad = self.ripple_rad - - ellipse.size = (ripple_rad, ripple_rad) - ellipse.pos = (self.center_x - ripple_rad / 2., - self.center_y - ripple_rad / 2.) - - def on_disabled(self, instance, value): - super(MDFloatingActionButton, self).on_disabled(instance, value) - if self.disabled: - self.elevation = 0 - else: - self.elevation = self.elevation_normal - - def on_touch_down(self, touch): - if not self.disabled: - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - if self in touch.ud: - return False - self.elevation_press_anim.stop(self) - self.elevation_press_anim.start(self) - return super(MDFloatingActionButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if not self.disabled: - if touch.grab_current is not self: - return super(ButtonBehavior, self).on_touch_up(touch) - self.elevation_release_anim.stop(self) - self.elevation_release_anim.start(self) - return super(MDFloatingActionButton, self).on_touch_up(touch) - - def on_elevation_normal(self, instance, value): - self.elevation = value - - def on_elevation_raised(self, instance, value): - if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12: - self.elevation_raised = self.elevation_normal + 6 - elif self.elevation_raised == 0: - self.elevation_raised = 12 diff --git a/src/kivymd/card.py b/src/kivymd/card.py deleted file mode 100644 index d411644b..00000000 --- a/src/kivymd/card.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.properties import BoundedNumericProperty, ReferenceListProperty, ListProperty,BooleanProperty -from kivy.uix.boxlayout import BoxLayout -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.theming import ThemableBehavior -from kivy.metrics import dp -from kivy.uix.widget import Widget - -Builder.load_string(''' - - canvas: - Color: - rgba: self.background_color - RoundedRectangle: - size: self.size - pos: self.pos - radius: [self.border_radius] - Color: - rgba: self.theme_cls.divider_color - a: self.border_color_a - Line: - rounded_rectangle: (self.pos[0],self.pos[1],self.size[0],self.size[1],self.border_radius) - background_color: self.theme_cls.bg_light - - - canvas: - Color: - rgba: self.theme_cls.divider_color - Rectangle: - size: self.size - pos: self.pos -''') - - -class MDSeparator(ThemableBehavior, BoxLayout): - """ A separator line """ - def __init__(self, *args, **kwargs): - super(MDSeparator, self).__init__(*args, **kwargs) - self.on_orientation() - - def on_orientation(self,*args): - self.size_hint = (1, None) if self.orientation == 'horizontal' else (None, 1) - if self.orientation == 'horizontal': - self.height = dp(1) - else: - self.width = dp(1) - - -class MDCard(ThemableBehavior, ElevationBehavior, BoxLayout): - r = BoundedNumericProperty(1., min=0., max=1.) - g = BoundedNumericProperty(1., min=0., max=1.) - b = BoundedNumericProperty(1., min=0., max=1.) - a = BoundedNumericProperty(0., min=0., max=1.) - - border_radius = BoundedNumericProperty(dp(3),min=0) - border_color_a = BoundedNumericProperty(0, min=0., max=1.) - background_color = ReferenceListProperty(r, g, b, a) diff --git a/src/kivymd/color_definitions.py b/src/kivymd/color_definitions.py deleted file mode 100644 index c81bd731..00000000 --- a/src/kivymd/color_definitions.py +++ /dev/null @@ -1,360 +0,0 @@ -colors = { - 'Pink': { - '50': 'fce4ec', - '100': 'f8bbd0', - '200': 'f48fb1', - '300': 'f06292', - '400': 'ec407a', - '500': 'e91e63', - '600': 'd81b60', - '700': 'C2185B', - '800': 'ad1457', - '900': '88e4ff', - 'A100': 'ff80ab', - 'A400': 'F50057', - 'A700': 'c51162', - 'A200': 'ff4081' - }, - - 'Blue': { - '200': '90caf9', - '900': '0D47A1', - '600': '1e88e5', - 'A100': '82b1ff', - '300': '64b5f6', - 'A400': '2979ff', - '700': '1976d2', - '50': 'e3f2fd', - 'A700': '2962ff', - '400': '42a5f5', - '100': 'bbdefb', - '800': '1565c0', - 'A200': '448aff', - '500': '2196f3' - }, - - 'Indigo': { - '200': '9fa8da', - '900': '1a237e', - '600': '3949ab', - 'A100': '8c9eff', - '300': '7986cb', - 'A400': '3d5afe', - '700': '303f9f', - '50': 'e8eaf6', - 'A700': '304ffe', - '400': '5c6bc0', - '100': 'c5cae9', - '800': '283593', - 'A200': '536dfe', - '500': '3f51b5' - }, - - 'BlueGrey': { - '200': 'b0bec5', - '900': '263238', - '600': '546e7a', - '300': '90a4ae', - '700': '455a64', - '50': 'eceff1', - '400': '78909c', - '100': 'cfd8dc', - '800': '37474f', - '500': '607d8b' - }, - - 'Brown': { - '200': 'bcaaa4', - '900': '3e2723', - '600': '6d4c41', - '300': 'a1887f', - '700': '5d4037', - '50': 'efebe9', - '400': '8d6e63', - '100': 'd7ccc8', - '800': '4e342e', - '500': '795548' - }, - - 'LightBlue': { - '200': '81d4fa', - '900': '01579B', - '600': '039BE5', - 'A100': '80d8ff', - '300': '4fc3f7', - 'A400': '00B0FF', - '700': '0288D1', - '50': 'e1f5fe', - 'A700': '0091EA', - '400': '29b6f6', - '100': 'b3e5fc', - '800': '0277BD', - 'A200': '40c4ff', - '500': '03A9F4' - }, - - 'Purple': { - '200': 'ce93d8', - '900': '4a148c', - '600': '8e24aa', - 'A100': 'ea80fc', - '300': 'ba68c8', - 'A400': 'D500F9', - '700': '7b1fa2', - '50': 'f3e5f5', - 'A700': 'AA00FF', - '400': 'ab47bc', - '100': 'e1bee7', - '800': '6a1b9a', - 'A200': 'e040fb', - '500': '9c27b0' - }, - - 'Grey': { - '200': 'eeeeee', - '900': '212121', - '600': '757575', - '300': 'e0e0e0', - '700': '616161', - '50': 'fafafa', - '400': 'bdbdbd', - '100': 'f5f5f5', - '800': '424242', - '500': '9e9e9e' - }, - - 'Yellow': { - '200': 'fff59d', - '900': 'f57f17', - '600': 'fdd835', - 'A100': 'ffff8d', - '300': 'fff176', - 'A400': 'FFEA00', - '700': 'fbc02d', - '50': 'fffde7', - 'A700': 'FFD600', - '400': 'ffee58', - '100': 'fff9c4', - '800': 'f9a825', - 'A200': 'FFFF00', - '500': 'ffeb3b' - }, - - 'LightGreen': { - '200': 'c5e1a5', - '900': '33691e', - '600': '7cb342', - 'A100': 'ccff90', - '300': 'aed581', - 'A400': '76FF03', - '700': '689f38', - '50': 'f1f8e9', - 'A700': '64dd17', - '400': '9ccc65', - '100': 'dcedc8', - '800': '558b2f', - 'A200': 'b2ff59', - '500': '8bc34a' - }, - - 'DeepOrange': { - '200': 'ffab91', - '900': 'bf36c', - '600': 'f4511e', - 'A100': 'ff9e80', - '300': 'ff8a65', - 'A400': 'FF3D00', - '700': 'e64a19', - '50': 'fbe9e7', - 'A700': 'DD2C00', - '400': 'ff7043', - '100': 'ffccbc', - '800': 'd84315', - 'A200': 'ff6e40', - '500': 'ff5722' - }, - - 'Green': { - '200': 'a5d6a7', - '900': '1b5e20', - '600': '43a047', - 'A100': 'b9f6ca', - '300': '81c784', - 'A400': '00E676', - '700': '388e3c', - '50': 'e8f5e9', - 'A700': '00C853', - '400': '66bb6a', - '100': 'c8e6c9', - '800': '2e7d32', - 'A200': '69f0ae', - '500': '4caf50' - }, - - 'Red': { - '200': 'ef9a9a', - '900': 'b71c1c', - '600': 'e53935', - 'A100': 'ff8a80', - '300': 'e57373', - 'A400': 'ff1744', - '700': 'd32f2f', - '50': 'ffebee', - 'A700': 'd50000', - '400': 'ef5350', - '100': 'ffcdd2', - '800': 'c62828', - 'A200': 'ff5252', - '500': 'f44336' - }, - - 'Teal': { - '200': '80cbc4', - '900': '004D40', - '600': '00897B', - 'A100': 'a7ffeb', - '300': '4db6ac', - 'A400': '1de9b6', - '700': '00796B', - '50': 'e0f2f1', - 'A700': '00BFA5', - '400': '26a69a', - '100': 'b2dfdb', - '800': '00695C', - 'A200': '64ffda', - '500': '009688' - }, - - 'Orange': { - '200': 'ffcc80', - '900': 'E65100', - '600': 'FB8C00', - 'A100': 'ffd180', - '300': 'ffb74d', - 'A400': 'FF9100', - '700': 'F57C00', - '50': 'fff3e0', - 'A700': 'FF6D00', - '400': 'ffa726', - '100': 'ffe0b2', - '800': 'EF6C00', - 'A200': 'ffab40', - '500': 'FF9800' - }, - - 'Cyan': { - '200': '80deea', - '900': '006064', - '600': '00ACC1', - 'A100': '84ffff', - '300': '4dd0e1', - 'A400': '00E5FF', - '700': '0097A7', - '50': 'e0f7fa', - 'A700': '00B8D4', - '400': '26c6da', - '100': 'b2ebf2', - '800': '00838F', - 'A200': '18ffff', - '500': '00BCD4' - }, - - 'Amber': { - '200': 'ffe082', - '900': 'FF6F00', - '600': 'FFB300', - 'A100': 'ffe57f', - '300': 'ffd54f', - 'A400': 'FFC400', - '700': 'FFA000', - '50': 'fff8e1', - 'A700': 'FFAB00', - '400': 'ffca28', - '100': 'ffecb3', - '800': 'FF8F00', - 'A200': 'ffd740', - '500': 'FFC107' - }, - - 'DeepPurple': { - '200': 'b39ddb', - '900': '311b92', - '600': '5e35b1', - 'A100': 'b388ff', - '300': '9575cd', - 'A400': '651fff', - '700': '512da8', - '50': 'ede7f6', - 'A700': '6200EA', - '400': '7e57c2', - '100': 'd1c4e9', - '800': '4527a0', - 'A200': '7c4dff', - '500': '673ab7' - }, - - 'Lime': { - '200': 'e6ee9c', - '900': '827717', - '600': 'c0ca33', - 'A100': 'f4ff81', - '300': 'dce775', - 'A400': 'C6FF00', - '700': 'afb42b', - '50': 'f9fbe7', - 'A700': 'AEEA00', - '400': 'd4e157', - '100': 'f0f4c3', - '800': '9e9d24', - 'A200': 'eeff41', - '500': 'cddc39' - }, - - 'Light': { - 'StatusBar': 'E0E0E0', - 'AppBar': 'F5F5F5', - 'Background': 'FAFAFA', - 'CardsDialogs': 'FFFFFF', - 'FlatButtonDown': 'cccccc' - }, - - 'Dark': { - 'StatusBar': '000000', - 'AppBar': '212121', - 'Background': '303030', - 'CardsDialogs': '424242', - 'FlatButtonDown': '999999' - } -} - -light_colors = { - 'Pink': ['50' '100', '200', 'A100'], - 'Blue': ['50' '100', '200', '300', '400', 'A100'], - 'Indigo': ['50' '100', '200', 'A100'], - 'BlueGrey': ['50' '100', '200', '300'], - 'Brown': ['50' '100', '200'], - 'LightBlue': ['50' '100', '200', '300', '400', '500', 'A100', 'A200', - 'A400'], - 'Purple': ['50' '100', '200', 'A100'], - 'Grey': ['50' '100', '200', '300', '400', '500'], - 'Yellow': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - '900', 'A100', 'A200', 'A400', 'A700'], - 'LightGreen': ['50' '100', '200', '300', '400', '500', '600', 'A100', - 'A200', 'A400', 'A700'], - 'DeepOrange': ['50' '100', '200', '300', '400', 'A100', 'A200'], - 'Green': ['50' '100', '200', '300', '400', '500', 'A100', 'A200', 'A400', - 'A700'], - 'Red': ['50' '100', '200', '300', 'A100'], - 'Teal': ['50' '100', '200', '300', '400', 'A100', 'A200', 'A400', 'A700'], - 'Orange': ['50' '100', '200', '300', '400', '500', '600', '700', 'A100', - 'A200', 'A400', 'A700'], - 'Cyan': ['50' '100', '200', '300', '400', '500', '600', 'A100', 'A200', - 'A400', 'A700'], - 'Amber': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - '900', 'A100', 'A200', 'A400', 'A700'], - 'DeepPurple': ['50' '100', '200', 'A100'], - 'Lime': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - 'A100', 'A200', 'A400', 'A700'], - 'Dark': [], - 'Light': ['White', 'MainBackground', 'DialogBackground'] -} diff --git a/src/kivymd/date_picker.py b/src/kivymd/date_picker.py deleted file mode 100644 index 5194298e..00000000 --- a/src/kivymd/date_picker.py +++ /dev/null @@ -1,325 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivymd.label import MDLabel -from kivymd.theming import ThemableBehavior -from kivy.uix.floatlayout import FloatLayout -from kivymd.elevationbehavior import ElevationBehavior -import calendar -from datetime import date -import datetime -from kivy.properties import StringProperty, NumericProperty, ObjectProperty, \ - BooleanProperty -from kivy.uix.anchorlayout import AnchorLayout -from kivy.uix.behaviors import ButtonBehavior -from kivymd.ripplebehavior import CircularRippleBehavior -from kivy.clock import Clock -from kivy.core.window import Window - -Builder.load_string(""" -#:import calendar calendar - - cal_layout: cal_layout - - size_hint: (None, None) - size: [dp(328), dp(484)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(512), dp(304)] - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgb: app.theme_cls.primary_color - Rectangle: - size: [dp(328), dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(168), dp(304)] - pos: [root.pos[0], root.pos[1] + root.height-dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [root.pos[0], root.pos[1] + root.height-dp(304)] - Color: - rgb: app.theme_cls.bg_normal - Rectangle: - size: [dp(328), dp(484)-dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(344), dp(304)] - pos: [root.pos[0], root.pos[1] + root.height-dp(96)-(dp(484)-dp(96))]\ - if self.theme_cls.device_orientation == 'portrait' else [root.pos[0]+dp(168), root.pos[1]] #+dp(334) - MDLabel: - id: label_full_date - font_style: 'Display1' - text_color: 1, 1, 1, 1 - theme_text_color: 'Custom' - size_hint: (None, None) - size: [root.width, dp(30)] if root.theme_cls.device_orientation == 'portrait'\ - else [dp(168), dp(30)] - pos: [root.pos[0]+dp(23), root.pos[1] + root.height - dp(74)] \ - if root.theme_cls.device_orientation == 'portrait' \ - else [root.pos[0]+dp(3), root.pos[1] + dp(214)] - line_height: 0.84 - valign: 'middle' - text_size: [root.width, None] if root.theme_cls.device_orientation == 'portrait'\ - else [dp(149), None] - bold: True - text: root.fmt_lbl_date(root.sel_year, root.sel_month, root.sel_day, root.theme_cls.device_orientation) - MDLabel: - id: label_year - font_style: 'Subhead' - text_color: 1, 1, 1, 1 - theme_text_color: 'Custom' - size_hint: (None, None) - size: root.width, dp(30) - pos: (root.pos[0]+dp(23), root.pos[1]+root.height-dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (root.pos[0]+dp(16), root.pos[1]+root.height-dp(41)) - valign: 'middle' - text: str(root.sel_year) - GridLayout: - id: cal_layout - cols: 7 - size: (dp(44*7), dp(40*7)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(46*7), dp(32*7)) - col_default_width: dp(42) if root.theme_cls.device_orientation == 'portrait'\ - else dp(39) - size_hint: (None, None) - padding: (dp(2), 0) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(7), 0) - spacing: (dp(2), 0) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(7), 0) - pos: (root.pos[0]+dp(10), root.pos[1]+dp(60)) if root.theme_cls.device_orientation == 'portrait'\ - else (root.pos[0]+dp(168)+dp(8), root.pos[1]+dp(48)) - MDLabel: - id: label_month_selector - font_style: 'Body2' - text: calendar.month_name[root.month].capitalize() + ' ' + str(root.year) - size_hint: (None, None) - size: root.width, dp(30) - pos: root.pos - theme_text_color: 'Primary' - pos_hint: {'center_x': 0.5, 'center_y': 0.75} if self.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.67, 'center_y': 0.915} - valign: "middle" - halign: "center" - MDIconButton: - icon: 'chevron-left' - theme_text_color: 'Secondary' - pos_hint: {'center_x': 0.09, 'center_y': 0.745} if root.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.39, 'center_y': 0.925} - on_release: root.change_month('prev') - MDIconButton: - icon: 'chevron-right' - theme_text_color: 'Secondary' - pos_hint: {'center_x': 0.92, 'center_y': 0.745} if root.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.94, 'center_y': 0.925} - on_release: root.change_month('next') - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72)*2, root.pos[1] + dp(7) - text: "Cancel" - on_release: root.dismiss() - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(7) - text: "OK" - on_release: root.ok_click() - - - size_hint: None, None - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - MDLabel: - font_style: 'Caption' - theme_text_color: 'Custom' if root.is_today and not root.is_selected else 'Primary' - text_color: root.theme_cls.primary_color - opposite_colors: root.is_selected if root.owner.sel_month == root.owner.month \ - and root.owner.sel_year == root.owner.year and str(self.text) == str(root.owner.sel_day) else False - size_hint_x: None - valign: 'middle' - halign: 'center' - text: root.text - - - font_style: 'Caption' - theme_text_color: 'Secondary' - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - size_hint: None, None - text_size: self.size - valign: 'middle' if root.theme_cls.device_orientation == 'portrait' else 'bottom' - halign: 'center' - - - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - size_hint: (None, None) - canvas: - Color: - rgba: self.theme_cls.primary_color if self.shown else [0, 0, 0, 0] - Ellipse: - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - pos: self.pos if root.theme_cls.device_orientation == 'portrait'\ - else [self.pos[0] + dp(3), self.pos[1]] -""") - - -class DaySelector(ThemableBehavior, AnchorLayout): - shown = BooleanProperty(False) - - def __init__(self, parent): - super(DaySelector, self).__init__() - self.parent_class = parent - self.parent_class.add_widget(self, index=7) - self.selected_widget = None - Window.bind(on_resize=self.move_resize) - - def update(self): - parent = self.parent_class - if parent.sel_month == parent.month and parent.sel_year == parent.year: - self.shown = True - else: - self.shown = False - - def set_widget(self, widget): - self.selected_widget = widget - self.pos = widget.pos - self.move_resize(do_again=True) - self.update() - - def move_resize(self, window=None, width=None, height=None, do_again=True): - self.pos = self.selected_widget.pos - if do_again: - Clock.schedule_once(lambda x: self.move_resize(do_again=False), 0.01) - - -class DayButton(ThemableBehavior, CircularRippleBehavior, ButtonBehavior, - AnchorLayout): - text = StringProperty() - owner = ObjectProperty() - is_today = BooleanProperty(False) - is_selected = BooleanProperty(False) - - def on_release(self): - self.owner.set_selected_widget(self) - - -class WeekdayLabel(MDLabel): - pass - - -class MDDatePicker(FloatLayout, ThemableBehavior, ElevationBehavior, - ModalView): - _sel_day_widget = ObjectProperty() - cal_list = None - cal_layout = ObjectProperty() - sel_year = NumericProperty() - sel_month = NumericProperty() - sel_day = NumericProperty() - day = NumericProperty() - month = NumericProperty() - year = NumericProperty() - today = date.today() - callback = ObjectProperty() - - class SetDateError(Exception): - pass - - def __init__(self, callback, year=None, month=None, day=None, - firstweekday=0, - **kwargs): - self.callback = callback - self.cal = calendar.Calendar(firstweekday) - self.sel_year = year if year else self.today.year - self.sel_month = month if month else self.today.month - self.sel_day = day if day else self.today.day - self.month = self.sel_month - self.year = self.sel_year - self.day = self.sel_day - super(MDDatePicker, self).__init__(**kwargs) - self.selector = DaySelector(parent=self) - self.generate_cal_widgets() - self.update_cal_matrix(self.sel_year, self.sel_month) - self.set_month_day(self.sel_day) - self.selector.update() - - def ok_click(self): - self.callback(date(self.sel_year, self.sel_month, self.sel_day)) - self.dismiss() - - def fmt_lbl_date(self, year, month, day, orientation): - d = datetime.date(int(year), int(month), int(day)) - separator = '\n' if orientation == 'landscape' else ' ' - return d.strftime('%a,').capitalize() + separator + d.strftime( - '%b').capitalize() + ' ' + str(day).lstrip('0') - - def set_date(self, year, month, day): - try: - date(year, month, day) - except Exception as e: - print(e) - if str(e) == "day is out of range for month": - raise self.SetDateError(" Day %s day is out of range for month %s" % (day, month)) - elif str(e) == "month must be in 1..12": - raise self.SetDateError("Month must be between 1 and 12, got %s" % month) - elif str(e) == "year is out of range": - raise self.SetDateError("Year must be between %s and %s, got %s" % - (datetime.MINYEAR, datetime.MAXYEAR, year)) - else: - self.sel_year = year - self.sel_month = month - self.sel_day = day - self.month = self.sel_month - self.year = self.sel_year - self.day = self.sel_day - self.update_cal_matrix(self.sel_year, self.sel_month) - self.set_month_day(self.sel_day) - self.selector.update() - - def set_selected_widget(self, widget): - if self._sel_day_widget: - self._sel_day_widget.is_selected = False - widget.is_selected = True - self.sel_month = int(self.month) - self.sel_year = int(self.year) - self.sel_day = int(widget.text) - self._sel_day_widget = widget - self.selector.set_widget(widget) - - def set_month_day(self, day): - for idx in range(len(self.cal_list)): - if str(day) == str(self.cal_list[idx].text): - self._sel_day_widget = self.cal_list[idx] - self.sel_day = int(self.cal_list[idx].text) - if self._sel_day_widget: - self._sel_day_widget.is_selected = False - self._sel_day_widget = self.cal_list[idx] - self.cal_list[idx].is_selected = True - self.selector.set_widget(self.cal_list[idx]) - - def update_cal_matrix(self, year, month): - try: - dates = [x for x in self.cal.itermonthdates(year, month)] - except ValueError as e: - if str(e) == "year is out of range": - pass - else: - self.year = year - self.month = month - for idx in range(len(self.cal_list)): - if idx >= len(dates) or dates[idx].month != month: - self.cal_list[idx].disabled = True - self.cal_list[idx].text = '' - else: - self.cal_list[idx].disabled = False - self.cal_list[idx].text = str(dates[idx].day) - self.cal_list[idx].is_today = dates[idx] == self.today - self.selector.update() - - def generate_cal_widgets(self): - cal_list = [] - for i in calendar.day_abbr: - self.cal_layout.add_widget(WeekdayLabel(text=i[0].upper())) - for i in range(6 * 7): # 6 weeks, 7 days a week - db = DayButton(owner=self) - cal_list.append(db) - self.cal_layout.add_widget(db) - self.cal_list = cal_list - - def change_month(self, operation): - op = 1 if operation is 'next' else -1 - sl, sy = self.month, self.year - m = 12 if sl + op == 0 else 1 if sl + op == 13 else sl + op - y = sy - 1 if sl + op == 0 else sy + 1 if sl + op == 13 else sy - self.update_cal_matrix(y, m) diff --git a/src/kivymd/dialog.py b/src/kivymd/dialog.py deleted file mode 100644 index cb6b7601..00000000 --- a/src/kivymd/dialog.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty, ListProperty -from kivy.metrics import dp -from kivy.uix.modalview import ModalView -from kivy.animation import Animation -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.button import MDFlatButton - -Builder.load_string(''' -: - canvas: - Color: - rgba: self.theme_cls.bg_light - Rectangle: - size: self.size - pos: self.pos - - _container: container - _action_area: action_area - elevation: 12 - GridLayout: - cols: 1 - - GridLayout: - cols: 1 - padding: dp(24), dp(24), dp(24), 0 - spacing: dp(20) - MDLabel: - text: root.title - font_style: 'Title' - theme_text_color: 'Primary' - halign: 'left' - valign: 'middle' - size_hint_y: None - text_size: self.width, None - height: self.texture_size[1] - - BoxLayout: - id: container - - AnchorLayout: - anchor_x: 'right' - anchor_y: 'center' - size_hint: 1, None - height: dp(48) - padding: dp(8), dp(8) - spacing: dp(4) - - GridLayout: - id: action_area - rows: 1 - size_hint: None, None if len(root._action_buttons) > 0 else 1 - height: dp(36) if len(root._action_buttons) > 0 else 0 - width: self.minimum_width -''') - - -class MDDialog(ThemableBehavior, ElevationBehavior, ModalView): - title = StringProperty('') - - content = ObjectProperty(None) - - background_color = ListProperty([0, 0, 0, .2]) - - _container = ObjectProperty() - _action_buttons = ListProperty([]) - _action_area = ObjectProperty() - - def __init__(self, **kwargs): - super(MDDialog, self).__init__(**kwargs) - self.bind(_action_buttons=self._update_action_buttons, - auto_dismiss=lambda *x: setattr(self.shadow, 'on_release', - self.shadow.dismiss if self.auto_dismiss else None)) - - def add_action_button(self, text, action=None): - """Add an :class:`FlatButton` to the right of the action area. - - :param icon: Unicode character for the icon - :type icon: str or None - :param action: Function set to trigger when on_release fires - :type action: function or None - """ - button = MDFlatButton(text=text, - size_hint=(None, None), - height=dp(36)) - if action: - button.bind(on_release=action) - button.text_color = self.theme_cls.primary_color - button.background_color = self.theme_cls.bg_light - self._action_buttons.append(button) - - def add_widget(self, widget): - if self._container: - if self.content: - raise PopupException( - 'Popup can have only one widget as content') - self.content = widget - else: - super(MDDialog, self).add_widget(widget) - - def open(self, *largs): - '''Show the view window from the :attr:`attach_to` widget. If set, it - will attach to the nearest window. If the widget is not attached to any - window, the view will attach to the global - :class:`~kivy.core.window.Window`. - ''' - if self._window is not None: - Logger.warning('ModalView: you can only open once.') - return self - # search window - self._window = self._search_window() - if not self._window: - Logger.warning('ModalView: cannot open view, no window found.') - return self - self._window.add_widget(self) - self._window.bind(on_resize=self._align_center, - on_keyboard=self._handle_keyboard) - self.center = self._window.center - self.bind(size=self._align_center) - a = Animation(_anim_alpha=1., d=self._anim_duration) - a.bind(on_complete=lambda *x: self.dispatch('on_open')) - a.start(self) - return self - - def dismiss(self, *largs, **kwargs): - '''Close the view if it is open. If you really want to close the - view, whatever the on_dismiss event returns, you can use the *force* - argument: - :: - - view = ModalView(...) - view.dismiss(force=True) - - When the view is dismissed, it will be faded out before being - removed from the parent. If you don't want animation, use:: - - view.dismiss(animation=False) - - ''' - if self._window is None: - return self - if self.dispatch('on_dismiss') is True: - if kwargs.get('force', False) is not True: - return self - if kwargs.get('animation', True): - Animation(_anim_alpha=0., d=self._anim_duration).start(self) - else: - self._anim_alpha = 0 - self._real_remove_widget() - return self - - def on_content(self, instance, value): - if self._container: - self._container.clear_widgets() - self._container.add_widget(value) - - def on__container(self, instance, value): - if value is None or self.content is None: - return - self._container.clear_widgets() - self._container.add_widget(self.content) - - def on_touch_down(self, touch): - if self.disabled and self.collide_point(*touch.pos): - return True - return super(MDDialog, self).on_touch_down(touch) - - def _update_action_buttons(self, *args): - self._action_area.clear_widgets() - for btn in self._action_buttons: - btn.ids._label.texture_update() - btn.width = btn.ids._label.texture_size[0] + dp(16) - self._action_area.add_widget(btn) diff --git a/src/kivymd/elevationbehavior.py b/src/kivymd/elevationbehavior.py deleted file mode 100644 index 19d7985d..00000000 --- a/src/kivymd/elevationbehavior.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.app import App -from kivy.lang import Builder -from kivy.properties import (ListProperty, ObjectProperty, NumericProperty) -from kivy.properties import AliasProperty -from kivy.metrics import dp - -Builder.load_string(''' - - canvas.before: - Color: - a: self._soft_shadow_a - Rectangle: - texture: self._soft_shadow_texture - size: self._soft_shadow_size - pos: self._soft_shadow_pos - Color: - a: self._hard_shadow_a - Rectangle: - texture: self._hard_shadow_texture - size: self._hard_shadow_size - pos: self._hard_shadow_pos - Color: - a: 1 - - - canvas.before: - Color: - a: self._soft_shadow_a - Rectangle: - texture: self._soft_shadow_texture - size: self._soft_shadow_size - pos: self._soft_shadow_pos - Color: - a: self._hard_shadow_a - Rectangle: - texture: self._hard_shadow_texture - size: self._hard_shadow_size - pos: self._hard_shadow_pos - Color: - a: 1 -''') - - -class ElevationBehavior(object): - _elevation = NumericProperty(1) - - def _get_elevation(self): - return self._elevation - - def _set_elevation(self, elevation): - try: - self._elevation = elevation - except: - self._elevation = 1 - - elevation = AliasProperty(_get_elevation, _set_elevation, - bind=('_elevation',)) - - _soft_shadow_texture = ObjectProperty() - _soft_shadow_size = ListProperty([0, 0]) - _soft_shadow_pos = ListProperty([0, 0]) - _soft_shadow_a = NumericProperty(0) - _hard_shadow_texture = ObjectProperty() - _hard_shadow_size = ListProperty([0, 0]) - _hard_shadow_pos = ListProperty([0, 0]) - _hard_shadow_a = NumericProperty(0) - - def __init__(self, **kwargs): - super(ElevationBehavior, self).__init__(**kwargs) - self.bind(elevation=self._update_shadow, - pos=self._update_shadow, - size=self._update_shadow) - - def _update_shadow(self, *args): - if self.elevation > 0: - ratio = self.width / (self.height if self.height != 0 else 1) - if ratio > -2 and ratio < 2: - self._shadow = App.get_running_app().theme_cls.quad_shadow - width = soft_width = self.width * 1.9 - height = soft_height = self.height * 1.9 - elif ratio <= -2: - self._shadow = App.get_running_app().theme_cls.rec_st_shadow - ratio = abs(ratio) - if ratio > 5: - ratio = ratio * 22 - else: - ratio = ratio * 11.5 - - width = soft_width = self.width * 1.9 - height = self.height + dp(ratio) - soft_height = self.height + dp(ratio) + dp(self.elevation) * .5 - else: - self._shadow = App.get_running_app().theme_cls.quad_shadow - width = soft_width = self.width * 1.8 - height = soft_height = self.height * 1.8 - # self._shadow = App.get_running_app().theme_cls.rec_shadow - # ratio = abs(ratio) - # if ratio > 5: - # ratio = ratio * 22 - # else: - # ratio = ratio * 11.5 - # - # width = self.width + dp(ratio) - # soft_width = self.width + dp(ratio) + dp(self.elevation) * .9 - # height = soft_height = self.height * 1.9 - - x = self.center_x - width / 2 - soft_x = self.center_x - soft_width / 2 - self._soft_shadow_size = (soft_width, soft_height) - self._hard_shadow_size = (width, height) - - y = self.center_y - soft_height / 2 - dp( - .1 * 1.5 ** self.elevation) - self._soft_shadow_pos = (soft_x, y) - self._soft_shadow_a = 0.1 * 1.1 ** self.elevation - self._soft_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation - 1)))] - - y = self.center_y - height / 2 - dp(.5 * 1.18 ** self.elevation) - self._hard_shadow_pos = (x, y) - self._hard_shadow_a = .4 * .9 ** self.elevation - self._hard_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation)))] - - else: - self._soft_shadow_a = 0 - self._hard_shadow_a = 0 - - -class RoundElevationBehavior(object): - _elevation = NumericProperty(1) - - def _get_elevation(self): - return self._elevation - - def _set_elevation(self, elevation): - try: - self._elevation = elevation - except: - self._elevation = 1 - - elevation = AliasProperty(_get_elevation, _set_elevation, - bind=('_elevation',)) - - _soft_shadow_texture = ObjectProperty() - _soft_shadow_size = ListProperty([0, 0]) - _soft_shadow_pos = ListProperty([0, 0]) - _soft_shadow_a = NumericProperty(0) - _hard_shadow_texture = ObjectProperty() - _hard_shadow_size = ListProperty([0, 0]) - _hard_shadow_pos = ListProperty([0, 0]) - _hard_shadow_a = NumericProperty(0) - - def __init__(self, **kwargs): - super(RoundElevationBehavior, self).__init__(**kwargs) - self._shadow = App.get_running_app().theme_cls.round_shadow - self.bind(elevation=self._update_shadow, - pos=self._update_shadow, - size=self._update_shadow) - - def _update_shadow(self, *args): - if self.elevation > 0: - width = self.width * 2 - height = self.height * 2 - - x = self.center_x - width / 2 - self._soft_shadow_size = (width, height) - - self._hard_shadow_size = (width, height) - - y = self.center_y - height / 2 - dp(.1 * 1.5 ** self.elevation) - self._soft_shadow_pos = (x, y) - self._soft_shadow_a = 0.1 * 1.1 ** self.elevation - self._soft_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation)))] - - y = self.center_y - height / 2 - dp(.5 * 1.18 ** self.elevation) - self._hard_shadow_pos = (x, y) - self._hard_shadow_a = .4 * .9 ** self.elevation - self._hard_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation - 1)))] - - else: - self._soft_shadow_a = 0 - self._hard_shadow_a = 0 diff --git a/src/kivymd/fonts/Material-Design-Iconic-Font.ttf b/src/kivymd/fonts/Material-Design-Iconic-Font.ttf deleted file mode 100644 index 5d489fdd1a04cf2169af5e4d29d2929432a73f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99212 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 Bf0O_K diff --git a/src/kivymd/fonts/Roboto-Bold.ttf b/src/kivymd/fonts/Roboto-Bold.ttf deleted file mode 100644 index 91ec21227866ca9d1cf77ec13660b7b85ec900dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163448 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 diff --git a/src/kivymd/fonts/Roboto-Italic.ttf b/src/kivymd/fonts/Roboto-Italic.ttf deleted file mode 100644 index 2041cbc002be810c50cc6a69e4e02b39f3457318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132440 zcmeFZcYIXU);GS(IWv<&64HAny(g1Ql1cBq_Z~<>5(4SH_d>wX5fB0CAR?dw77$Sp z(Tm7cY}ioIi-_IpRmjYF*PbMZKF|F<&*%4f-~TSUzo*P8d#}CLcdfnlK0z2Eq=SYL zMdb;xaq(J?T22Tz>cQE>gv^Yb)$gZ12FHa6Z8(>ZlNasaY<(ILY>E&Uo{{72`^+)d z41{nkTwk6an^xF(s}qj(rxD_>FKMV~e#mlLA3~<}@RFaF*7wxB@#*jXLdg3(!iMkH zR##O0>v&`}+{~Ud?+DaxO#!3>>GTX3i7^(-UaFn4nnRTsQ{r4&hBuJ8z3ZxHc%caGZmB_zft8 zIH4pi8)+2+ke3|f%rRQOAZUud=^@UzY~7sl2A4`E&L4a(dV8=IruB#U)&|(W2oPUB70Ox zN72jlC@SLe(TKI3-SZH$;prt`5cu(X(T=99j;0ElD>obh#uOHe-$p0qv%t* z9-X6)BVFjvXGOZ`gvbExgu1*fP7%gAPvpW^ASt&C1#$MT z!ganE`Qv{gFRlc6a)HQ-*dr@`Ir8V4kb}4x<%x|^0{$10lcPcszZhiRi=z1^*uIBK zuu9P2Y*9FU0-Ml&>_m&P7~jS^WDmx~UN}adLLZaw(Mu#-_!?;{e?pon3R^8G|3sQI zAL3gxr->Nb(qGZfWFguQb%^1|geUlHRLe_+^H5K1ek0ViTe!wQgckF)XcFv1ldDIG z++N`a`YjrVdd6@;$d%JYqpZ$c2Wlg$(FB(-JWbz65!_)^4s!d53qa}cdopK?R&a4> zDL;y$_#TuYYD6{M3Y5jUqopD{RKtIWcJpzlTT&rhlGLLZQ879J{T9uAhy3{K!UJL> z;RxuUBbxN-*<(Z zp!4xu50cRokoU8~YW^6O@Lj6K$#R?;s1tY+&JvRIeH$I^M_F?w-=71QJ*Li zbh8uM`60>|>A`hTPy&#js2sMb!V657!G6+3j|k^Q&%!;;a1758eT14sB9y^JATN;s z_Wus@;GPzq{F>Z6S-$Vkm^J7rqBBSVA+=AmbC!G86>w z%i>=_Z_v{yMZ!bdzeKly7e_@HofI8G8$|ojT2Tx-%XOkOz5!(XAn0!odJOC$3a(Eh zBEg(nhI|-b(;47VGh_yGh$6A58~jBx*!UN~ONFc*VwLci#9z%vRzxKnr{GKIhv;p( z0o}sCp&71T*bla7#Z{pMZYi>&Z$WtmjyHh*zKX2y7s!pC5q{;u;QSuonNQ$1IM3|{ zyNpwBn*e{>4)!tz+`;^p6Ue0+`nm>uYz^vX{uKOV4d}g0&B4sqga76ukT)w_ zBMM_alWY`zVSf1E7VypRzFFTqw`G3${sQ)>_Q}jI|EYjKWFn%;W~`Sva>fpWAv7Ct(2J7Mj>Ga7+@t0(}IrkJ_I?{KH}p;P4O@hs zzda3dWw99a$NzTAVm1~xF&$xjHy^vP_=&}E_itGo!{Qco9K&LkrNUF{!uWyl&A%(a zL6q^&eTDJQ{pB9_F#fr}Fy6VpFy6WUJ&fP(FY{b?-@Dj*)x5{JZ@$cOpf1$GbhaKs zA=}>1iHsNLi@JV{ALlu8zK)C|=L_S?`wNrHJa^vThPiz;m$LTEaVg_dRwRbVSZz1& zp(XsUsD-Qo`))@M@Fv1{d;;+0Y9v+v4l%siKA@kN?lB!^G5cTRb*3ZgeudaveGQAx zS=`2AHSo*o7!Beub==8po5i*ePqSDWep||7G_}pcRvn`;n}qm~=_q@i`k7!ejDyu< z28hG%)sI~V*F*hc?yncmVo5fZU_8L;$HonepP0?F_>0wp#rnV%YEFT=u-_<))xa*8 zJ*xQ$#tAG|W7o{<@?W>}x~(2xv2m9^yyFmRXEu((|Fe3rF~&WvDil*Nwf_AowW_5?98lMRbgS!~Jn@4bVK!JxhKHl^-I zXrDSpf;gVV^7HrIdp5|B$%e^Ny`ATjxtMT1HiWpSoyDOn9#-4*U$!hZ=2-j+F|j&s z1=+K{W@9mR9L?h1x%&OT+RnH4|L>N`lJ!4qb%4Kr{42lyuaD=)QUBBSue>@p?wTKe z{k!eF?){hT6!^F)h)0>tfc~m|2ODRAEwFJ0vj^5E^L;hHWp>AGU|u)w#oBDFaT9z8 zDJ+cFIK=y!+$U*oOIUz?tXXFIvf}83WW>bqi7TX7=t1KV^I`f9EujcL-8mEFagB^ zCZagNBor@vi;__SU z$`Wp&e3T7XfN}r}Q7&K+%7dIiG0F!lK?Q)Ns1UFW6$v-dB2)~x7?l8)qf)>MR3`ib zRiZ_JOVDD#DpU?w4fqwRK^1^YQ6*q4S^~HXRS93B<)|944%GnGqosfis8+av8qqSq zCbS%|8Px%{pnBm8)QTDa+fXB5J8A;#K+VGEs1vmScA-|lZqx?Y1Na&0MeTrnr~|Mc zbpj5cF5x;FMBRWxs0VNu^#YEdKH*a|iuwV^&;Z~#8U&m`L&7I$5)A{cKqG)tXcTZI z8WTQ7tI#;$184$p8chPO2K)%EK`Q{)qA9?2XeHo!v`Y98Z9oqIZbZ|7o6u^&2hkeg z8rqE30&YR;0Joy`fDfS!!Ut#@+6eeC+61^AJqWl1Z5G}~JJA-vN6=QlUFade-GJ|* zJ!l)?Ui2{FKC~ThKiVO@iw>ZjfCtedfQQg7z(>(;;T?1s?E!oY?FBr7_5nVQ_6t|h zQFH+C7&-`e9329D0zE3cjh;k@0iQyT0iHld08awGg-)Tz0iQ-k0iQv~0G~z2g}q^zo8caFQJzJ-#{-5m(XQ&9uV#Zyn-$O{vEw4{0+T@ zE&{%dUIV;}UI%;!{Y`isy^AgZzK7lbd>>r~`~bZvyoRo!D}W!OzXN`R-U9p>@FMyI zy$$#&x(aw5y#x3edRKTAeU9D(`~tlXcmsU^_$9g~TtHu;4*~yyJ_5XnJ_h_6eImSq zZlO;Bzd_dlZ==ruzeS%5=h1fvya4(h-2nUneF^v@;LGSI^cCRG=pTT;pqqgIL|+Rp zp=zG8!^aG$0{V1G+l=V-50{R&c(kQb1~h{*xe3T-2vF#30T|(*xL<4Td04y8`>>CWM8wzY24lEl9>>3TM8VhV14=kDp?3oO#nF?%~4lJ1o?3fL# zm{kq|R|;$gnIB*{@PtH@XcHY`M9hgbu_aPsM;wSfaU{;fmADW$;!Zq? z2k|1_L`Hmx50Mjp;ztxDfCQ2tTn}tk3Cy?@Hv(sk0naVN1Hfdp_yORd5j+K%o@u-q z__7_3;R!sBUc@VbAA7*U#({YTfnn?M3bYZg0voMEy|@`s!V?KG1BO|TEAbM%3@^vk zxCTw)H6#S`Debrix8gRufmY!L)QOkkI^06UM3;z&9$7&2i2*Sr3yBFag%%nUOJYSV zfYY`Cr!)fJ>;RtW0%myx7>EN>&ZhRd7fbU{~m=Oz*O%XXmUL~)QkIByzQ%W_cF14qt z=rr9xchlqaS^65iOy8pKa*mug2e~M&l5666xJm9Z_a65d_fH=4dc1)(wvMo#u>R5d zXY1c>(xh5aBdN92PU<9;N#)XDX{a<-+AbZE?voyr9)(-IU%tz!1VJf4rtw~DrJ#koKpu|+Kb`|Nx&jvc0}`+v z*2hlR1^eJ29EEdnIj&W=b{9Sdt-XV1h$(2zY-=w-Yu|^~qI<0!ht{s48|hy91bvRa zPX7+AMVu2StCR?NNON8kxHeG z&{|(<(7o2~h1Ndyr`DFtwRYist*wIAVrVT4i-Z|yE#^EpCy0X(_)x^yL3ja-KMqPH zlu#(aPy(R@K#@W5g=?_t7u7#-2T1B9_}^Ytg(?yqR$f)^SDsfMQ|?vnQSMM~RZhT_ zSxKHMSbD@Sa*uHO7xz_IKnoXYON!?TycTM@nv?}sT);syntO3p*M3gzbPHGd%a=#TwB_Q)l; z7RvwbA2~309q=z!f!*<7`(j`X;4?HtFz}f%vwyHhb2N-bz$zIFSQ8tFg~ov8Y=P(O zf$1E9g(iU6e1O~Jz-#^x6RiMlQ!sXec1#hN#zQL!L956zvYgbBdeT4|AvT&ut4SB> zCOxE=^pSot0MXG}GDwEVFc~4EWQ_3_*+4du&14JNN**E(P65M9-|AW z4%KBmLyf5kHAP3M88t`8s0FozSpzHd1hqy_QX48oPf=TlOiofe;1LJvNS&xNb)l~4 z1?o;cV5ZIuB8`_I!Z;6+#Rc>#^@MohHQGq!kiqvum#IGupbE%CzX{g;cN$EaXb5_X zhC+@#jE1ADGy)=qchP$^66QGHr%^PT#?V+AN8@P%#0=MHB25CH{}nL9O_~f|{ucTM zMsBykuYZTWr>W=%nnu&nk2C}QL^EkK%|c3=jZ`#;=F&Wx52gfzEm}ZZXdxz;VvaMX zt+Wjo#sC{)Bic?oXcz6o_Sk{5;iQ}yFs&1CtqXSLEI3Q-hTSkqq9i&5a7>D6-U}7g6fg?Fv&W_XL7IOBS1CF8(s9Ae8FxgtV4oBk{PM0``aah{w9?&5gxQsALzJ#F}pmjR#pA1@OMEcqWVqbBbE zc$xorng4j1|I1$H{?N%9MtslVc>EH+N;rsTib*G#CfmpwUl4yHag)SKvL*eJZIUCBE0UWUp&E@Emo!D1 z<(i$E`!t`?ybftnQ!SZRyjHH(a;-tFX{~KqziG#6PibFWV7VZ9!I1^m7R=}b>lEwM z>O84)UDr*wUH6>s=X#NPje6Vkj_O_3`);B6Lf?h$3r828*XQ(I^jr0xGcY!YH7GXt z&CtQ{sFBD>-^jt}l+k%(V(egCYJ9@@CF7q=^h~@=a!qPYj+#7Ya>?WqlOIfDO&d+u zna-H`nr$$*HXk=XXW?YgZn4MWsKq6V+m;f`V9S2X%T}3I?N-lNn_IVAAGf|`qi0iS z(`YkpbHL_2j5u7R#nNW!A?YdUdFf^8ueRE@ZnlB8?Y8~4Yi#$~Av;4mnO&@1mEAeJ zU+vTFk2@GTcsOiz_{}lWvEK2L<4;b$PCK2hINLdQI-hs`&c(^4+vSw2wd=U+OKx6n z%iW%Hm$)ao_quO(zvQm+@bH-S*ynNC;2Z8+>pSjy!1sN*jyzmGCBNpU=U3%-*zY(0 zK>t?%HU8HEoC2x>&L}h$9*RuGpyIef6&M+~Iq-T=ZqVz&*1@&G>w?dONJDxCEZO-JE+f&nquKuQ_j3-if?Rc{lR|@;mbnm8>4n=0-zt(7#TT^}ttxu5=&hn##iTg3cv11T;@?WlONvVl zm7FQ{D(x*jU;1vDc3D-~c-gr{nv1L#tyy$!(apt9ixU^;FCJZdVDYu`{_^qiGZm7G z@``hnhLygRnU(dGt16$Y{B?=xlBy-gt5B71)l}7us$Z*ptDCDgRKHdIRZVowbj_}s zTT5k22bW&2^{8#FJ-dusmb~ona&CF)^6BN*>H_M*>*DLu>!#~oujlF=>Pzcu>)Y#x z>!<6t*6*u7UVo-D$me{0|x^cpN1TpIiuA{$a03LB~#nj88XrW!Ui>}ojD z@Jz$`hARypHQa3Yr4co1H<~s&G|C!78xtFI8_OH(8@n6F8`m{%Z#>j^qVZhgrN;Lg zZ#4eUIMXC)GHjAIEo%Ct=~mOP&7@hU*}U1Q*|#~oIk`E%xw5&jxwm<;c|-Hg=8sw; zTT)vJTdG=`Tl!n3S~j)pYB|#KOw0L}D=i#*!_ z>G11_>`3h>?AX`wL&r>~q|>ld+Ue05*cscI*;(3I+u7bZ+&SI3wR2zR@y;`y7dx+Z zUhll!`5P>U(Cf17a_RExitI}5D(tH2YVPXqn(ErrwX5q$*E3z`yRLM7)OEA#mu}Rp z-EG?K&|TTx*xlPb*}b8AXZPXmQ{6B1pdRfW(;kN&Sx;zBVoz>Qc~5=Mww?n$PxhSc zdA;Y|p3i%}>$%e_>ecVH?se-8=#B18?=9}F>22*D>|NEnxpz|c_502H?fTvN zefxv^qx+Nl^ZP6N8~c0vC;K<_@9aO&f3*Kp|JnWv{crVu(toS}*8wu1GhjZ@KF~if zHLz}A>%hK&;{(qOoEx|}aAn}5fg1z22Ywlt8RQ1F2Mq@;2OS1I1_K8p2NMUU2R99F zA3QX8V(`r1`N1oL?+@M>{9$lrNHSzNBpvb?3LJ_Z${Z>jDj%vJ>K+;&njYFZv~TG6 z(3zo&Lsy4x4E-=PGb|Z49JU;G7?ur(4kr%h4wnzt4|flb4^Izo8s0v9X!ykNnc<7W zSBI|;-yZ&DcxFU0VmKllaT)O&i5y8CDIBR9X&&hxnHt$NvTNkX$cd3NBNs=mj$9wP zJ@VTqH>x*kIqEX%HySybI$AnfKiWMyJ~}nfPep=EN_PXi|I9bkbo`HW@mZIGH6F8i$5idq zzNwd{uCJ7=^j#UfGJEBsmCILlt{h#tX63e(&#k<+imY;3C0iA`Dqj6xJ!D8Patp}; zSewd2t{Y)0Hc;4LYHy%0!7Fnb!wjar&uI+TpW+);`!F8t(O3`L@m38Moe;=0BJL7@ z9J1gxaIZbwX0MP#u{DrWIV)m&bpbT6CmZiPxc5&TA+n3i^GqHo^%jYumaoZm-r$no z5@{rQifVggLY{P!tusJU0*z2IPc$ zEwoInnJg%Hpe91=!%r3#4Q$Qut1k>9*fyeA5tJL|X<(I7JyB4)x++BDg%=m3cW%xL zS(fgFv2_?^=Rne@g`2#Le-&mD+#%~<09kxw5Kf`ix>$#@R+-GzIYQk`)++oz{LVXL zlM7=W6P}|TGnzW=Ws7eUV~~`!ES_?6^|bh`RBHp*qO)%|G@jumnpEH<%s*1;er9=cV5;V0JV225sfu>usq-cE-^i6R!Y z2N}89=uuJl(p5Q;tvOyCb&1GuAOGDmNPG8!{OldCC*{1fyl7if2;S?GnhWAo+mqwY)Zs9_4g4zA7Ti;#*8K*R8#NHs!)z1Cg;$v95CYnQ zt*MFFiwjT;>-eWF9eZT4MdR+)L_?yr02|3NLOnCuGQA9VZIV*?=A{=8uk!BCe&_wdw)}T(rUdJze z>DaDCmJNH@3p8PtNtO}foza$|enC>@n}2)p(FeTSvfuj!OU85)_8mF8dm3Kw;IS9a zzX&ODX1`0wVmbzAr${zPKK>6nzr2eP)Xx|$Ii zn1edS<{dFS9siIV})$=JTOr%*`;lw&@U?> zzB$KF<0;L&si$i4*4O$=#L?v~{;Fv5!fK-BT2j*-E-#67CB!|WDH_)t>Wm=7zjAd^ z`r6TUxvG%W%^PHC1MiK50~251i2wRpwTHN$YS}g381L!|Ybg$qi1dB4gF>p(d^MpS zV+Tu$*Dvvw@V+VKe)1%*g`7s-isMU)AFNaGCpn9tf}rSzY`Iu$9a$baO?|O6sv=5J z677hweN0&pF5A3Zfl2VP2TMY$b0SQPV)Lp3s`s>p5IDD~6bF_@I}+lYv@9}WafB^l zbJoBEoE7MarrJ`N7iAg_32|EkF)cc8@p8zi5M{p+m0pJkf&s1EF)hZz}{G(R%X+53J zXV)yXkKVbca#gNWqLDUyydk->B-~z8qNNwUXyoAK0o7~1r5RDi8k~-mEYT;SG2Kfn zTHu|_Ke+=Z3>{w<9ZP7=_@RQDXCBC;M3z<8Hy%~c^7gY2HHImhv2{R-TfAdIVRnQI zp&=Fh5dm%G;UKpiAp2>M8|bwLOkjZNbGx1r;vzz zGM9#?r%1%<1N+MIR#(VW-;2zGih?2YWXNVBE_#mBqG{CYT58TeN6f9h?cSS)(M1ibOYp-O`qa2bIM- zV^F@O}sf6MM zma+uj#HMsFk!XQu&Ndt~c(TPV$i)PcycLJ@Yfi7pp+uhFHo7V%=5f_KpA2uuUlE(Y zWVa;8!s6U$S3<+81|$4CDx+Y=R)E!UKjVE|JgmdegQ;6F(nD)$n;-}et3Jl7;k+}P z>85Sa$2!`~R-({F`V5!B`W*9OXpI<)iNCGV$()uskYVL%+_wSuzM ztHxhra^5feOrHULa)$LGh*9N#%a-70z>t~8F%&V6gQLWD0m(9lYO*YuMlsqP>gjfoLN0%RUx8n@SWWfSg|(ir>Ha2 z2#7(Lvx0B@bYNx{*o9Nvb6T@LD*%EPYVXCXuj35)x$B6+PhsH1oSSHcrgKnQWp|=$ zg2GX39vYY78I<8`E)h$#+#+&n2a>XeBPPIOhz%XBa4E*v>@>D!6%zilYS#MmvSa8bEi=;T;OksK3+O!=0fOfGXW!^ANv zzpT`y^2KAD8zTvcY~A_nrP{KyPdwZngNd6{hncOB1gDH1d*idVo^RhfIgvz2%E+-x zpItQ#jR^Cx!Ne&f!A8vCJC>NZCN5f910U|fS_19?;2klrJ_4r*@d2YBN>?kNeDyVI zvL8#IRi4A2_TYZiIDh<3Cal&t2wE5-2;4Tf&luLZz*+#g0k3v#Y)Ay%qJ??2|8sJ7 zoZSKc>lmWMFBNZZ4wmqq2_eouJYh){UKb^)-)m5w;R9_Gzfqp0o zP<_rH$Hb#_&61Gv^iX5NxT2+g^}Fl*F?m$^3$~A~j_w@i9)|HvNq9)MpD8#owGV2C zujqaU?qC4}(-Fq@Y?xzW@1>4r<^otoD%^UbW!qkDD_vI??=03bGF87AedQxIjQ-8{QiB z*3&lXKc^D5>0fxZ>xI=t3l}U{n7XDJL_yom{Btt@!Mmqwc>TK%;H=dzwiK5?x1kgQ zJ7}u<9Z$eJ*oYeVK@5v|zyaIRE6VM~1|4`$kMIr8&C1vDzmYG5S+hPhK*0iJuE(Q) z_2$I#t!-)Unpz7Ds}J0IsCIuxjO01qIj$zA^WkB7}S7m^-aJ4ToxZYCd?0UPTWK&|a9ARNS6*xrCR3S|4g zl&7n@l=bUWGsP8Wlu*@0+#ay$NRoWFliRJFR=%x%kXo12vIL#5wa2WYm`U=K^0)KP zD^C%PS59-w?{0<%tcMR~K)<_$uX#=IBNni}@DHm4W@cl$xlzPDyW+}1^)Rx zSsy&0a!hgpxg1f{5ZWO+(|Rf?(dp#|g?c1Tzj z7gZJOFwfWS5YukuUr~=hS)6(=`C=cy9Q1v;HTKhdl8QDn#q!*xURhh(BE^!bEzd2gd~!0CKf}9cwZ;T@lt9 zD@v;#s`14nqIFNz#3q6*LrWt=b3>hVEfSZmDX-m93DHhi%id);VOatUt;~W;Ku#D| ziX$FOeKr~cDKVn^Ru%Hu>CaRlmRuaKf9E@1f9I@CE(O~FQ-+nhpmDP_0?afQnJWx< z%R>vRAAYs1{%E`3fR!I(RChp`QYRb5CN1$+8%lNcz+z=RF# z?5VRDK#tFHvG}P++B73@`-{p8j}3BeD%oSLPvaMlAE7_bpaZYbkMCr1o>lF4zkr88 zP61Zs@$Rq-zD7e$V8CIpL$={ZZz^BIId7{}s^ps_Ms?~69V4DfN2NPaC|@K0AP{!W z$c?tghy0We8bh+yECGsx0HdC$qhPcs5cpt2~^Z&g9Glta7{D_iM`nKvH>>`p zT4#D1^JhfEza?%JP0jXm2Kj*M!gJ=va4h+(t@`B&yt{wzPVQNil)R^OWzQTDmQiE4 z1>VO)GsxYUNekM$MVJeR4?QzBa@KS(Cc z+KSxduc-#e*O-VM)uSV4NJ_F{A9+Gdqj#3ZcIJC=qKZu?ik{cz^}Uj0ZrO3Z8mA;h zBijDqYd;}3wh~-&iM*k^s2+pV(PA%H%>v#}rootBMxj3mYU1mzfCwQW1E=%&0 zWhaE1Wmz`o<#cCzYY@}u6$AB|kUok}85AMqOYw<>jla8xLR|{;(?Wr7%se9C9o#=L!Xjl{{@d}7Ysg}*}AjL zPK#fV`@r*^c`M8P@T2Db>3%r_1##H@{Hh-tg+?0!l)c zt;zMtk9HwW_ePeNU~+?*GkBd2g#D`x~_p>=fd3d5JyZ*+(PZ~F9{hyH|^^a)b)xHzM&t2&e_8E1c>*7 zX%AL6m@%+b^Ot&XWxzO^XDW!VH|?%+)!-%Wv1M&5(waBrm@d#(hHK~tRV9^f2(5J} zt?P=3tIG;DAUd2xN0x0!3f4VW?H;#kurA%5(6R^5ROUnsR!0$%6;J6xMKKY{_-L*vRt1M`X zHk5Rp>=J1@#szq1Cxn?zo&*!4rxLOWj;vdgt_&d;eR3nf;hD=K9cO0Xi9~I=UqD<# z;hPjBXVEpw30M;&mWFov;>4K~>v6ERsk4riRZD2YmhB>`cE&0Jh&6|FGf=EA?DDMx!4=XXEyf6d)Gv= z=I?64!{4ZMasCDT^N?y_?Jt1O&KOQ%U-e2jNm!!~*f3m5tC&5gk>qMtW+buazUY6po)px2} zq~o3xP(1Fv^5hvVqzBjx8@fe%W-lTneA((OWe|DIFF(u<+|_1`H2yl`b=KI9nwqze|_Q4TXR@NfcOUVaU0 zpEF@>1fy)Vt=yYMgdq~gsOpczT&9L+{Nj!WGF$glI%*M}qO~t}w(PES(gHismHMao zNcYPfDh|*j(xlY`%Tgf2w)ml!YfKtn+g3zr+17J4ZpHa&Ar6Elw69Mz zb}K2!2z4YhsdHl@=+=9xayp}KFL0H5E(1G*$}7}uzvp8>`m?62pg&6-f-;s4rRF^t zP;nA-`wXKVshD*!qLUofw(?Du7mmwIteetv`tp4=|8OuN(aK->Ynb)PpFIr8iBEiAMg!>rTMyqv^Tpmg z@hOgITlggTxu?d2m@kqxq~!LqT1jJ94%BCOfL6pb-f<#aDA=4&*7EKF=Jql|oxn*u z2iOwBm}IC{*G9(cYTY1L;qP(i!GV*romwT;f&wxn=iJ;&R>&q!o;hYAA1^d-F;g*J2P1hA)3_aRy)|kT-B--3-s0 z3-`fYz>u809KCl@VMmOSr2S+EFOr7)Rc!H_I(g=?y4Wy6Vw%=vkkiU&kGxn9LNha| z;oS>RWq58QP|vsUTzHA2I(V1kLwNE9<)^EzKB=T(cP}urhwFyHQ>$Pfc#g%^_LN1E zEE#YM7oAoaY;0EbZtQqG8V_&4hz8%iKz(N}bHOv$sFV6V@I@t}zrg+XVtaT1d(aQq z=@V5tmb~(m>dlYw3j(@8j^kCz>&mb2CRIIr;0H+uc)ze;l>qBP)$M1uv4~2|@vQSB zK-zdO9=WI-H;>7$i?mdj>uH&4`=p2a8bzLd9{xs=>s@RAC8?f3=%UT=xr?cHj9V|q zoCSQbjwoy6pT_{C!ffWO33*z1$&^|dZ`rbrE_~<#Ru2@Y+DMH=5%5hUe5(YJ3)4!- z4nqioSx%UxBOqT1*(yjJ<4>|W63sO%MVd~r{(8+lx|ZfwPFRE$g*$0j>C~1x$jn8Y zg_zhx!9y*Ix;Esz>5~)gMA!3!^>04+rC*0(TuDRNoAnRNE#fl@+}{jXUX}tOK1Q~x zpYV%wV+-&ZPi??D8&p4u&a(DQtJaa_q7YU;FF2(-i9hj@w(-8@o zv6?l&cDdp9gm`5vRj8COxyXExzVIc#n)^{bcR0&TFa~p0&lzHcGgJ-YMQoxlQO_vC zau>1MGT5MFj?d|h+%wA-9f{k~@QAgMmQG<}$LiLs6II0rV~;gGE;Z5C$%<}UJM+1g zZSGi6`J-cb+M3dw@j}?kZwv)b85udXZZhv^asAn>9YdQGQIJ>(*}7q4!INc6PiAf& zBCT0FhcYQmA3t22xpOds(zMaTtZ#FG&m6#pz@QkP!0?~_2cZlMp4oqpIcUW1e5U*k zyBe#et#Aim(3wEhdSl#Z#V|nikH1k}Nc_qM_V=sK;^_YU1LO*miSRG5&kxl0DF$`{ z1vG%TR%6wvRfkTEpHlrqO=iBP7s;>cYd==$a+@Jfl?7iYGi$jw^BQrVpt#u~xmv1h zr1aMnVvfLtEM8`w5rZ~>Y&rO=sE%QoUV$zmN#(|q#nq4YM8F`6RkqG) zPAN6oA_Lcum;_s=6i3HsKYNkL$RjK!9zX40kf1OMT$NtEt_0H4f%UuUaLm#~2o+5I zb3ghl*cTX<}Z$f0=YSX9iS2Mom--GdlD~f}!z~?xO z**p`y^KAZbmf@KmJI;ot91}X5`V+IkEH7ruUU)8898lDkn$@0QCDPUiE}zUxY)-MK zYxvj_MRu^AXaOg&i}dr3_qCQNy*2fGvYMuI3iqz-Ee+Gs)RSd5&K{M8^=rk|t$FlZ z?UKV&H4!G7TCsCSE8&RbC3j`Hfse0SncSYfrY;;4&#bmYoL31ex{?;jI^BzsVR4L^ zEY4#vZOf|8LYM&b&hK8kJ11@P%8mlaYkTE)t=W~c8bL=jusqm~fM6FK_AiXVGWXO<*tC&Z&V z%r_@kN@&c|fzT!m${9IZ2NvjV7X=qK1cjGJTJb&-B2k_8&T+6TvyKjO;}E!;BTkg z{YVXncT^_navbXZyN){kO6@(pcSp zhtAbj9fl*5K22TL@41Eh*7cNyYRw*j7Od|n3&Y#}S506Xyez|=Bjzpv)|L(iJQZ`4 zkX0g%7l~!Do7P%~$?bWOzH6}UG+FiNO`)_q+ce~+h{-1#pbfKE}DBVELh@CuwE6h~8qxMCqR+{0?sJ$&S z?^wWx$^~0hm3Ze?y#1~YTN77G9ws;Vvutb+Z3DYkFq;?svC<1NRb-FyIYS(3B=eB+ zVt-k5rp`7|Ku&$Q-{N=|NrM3jJiVe8<6U`uCnZ5=BQYgqoNiJ|MEzVARj zdH-BK8HNJ*g|AeXck(LLHHbgIRF6%A=jJ8U3C7t03M3uv!A(IhhIcOIcuvnD*rRk> z_Q0t#yY>Ai3PKw_i%!7T*TKqlwn>T6u=bXwrc>Ly7uur}v8|iRjlZUTcOQ7vGyD^5 zF4ERuE>q1@qFItyv#ZWWQ>%3S*?Md=LnN5Q_8hEkI^G|R?_|!(c|Tc(Cuj=O47InI z%QAV9{W#3m)XiECNBXekj^tgo-cirm)zl{fwwA8Yu8XP^3>hj|=L~;NPQ5xx4BV#< zViX6BB4Fu6#Nt+e&LYI$iRaBd{EWO5I(d;%IX*_X9&4JoO08`dis*#84WE)dq?uQ* zH-tgE7}gu&Z@1NcWQwbd;Fr9>6)mj3Fk?-Q(FX8uY;Ee(x4J)Anf|th`7p>@$vx3o|O+JWTuSG z?-Hj}7}*nt&KGj8AX+Av(eA>1Eh8FNwP8O@rKMQe`oPQiS z;}=mn*$Ufskdp+iI8V;8X288C;F>P=HSO@FzC?X(5?m|BFHsnGs;_}*EqLADrM2Bg8VqE(B*mHL%W(>^r`L+V-fDDR!w2iuDS>m>oom*{1~%-9Xd=fx4Vp6OovQsR3*P zZeAVGKse>hj@d$}xk>iIseqBK7aY7ziN^eda^vox=?6bFv(d$pnQ##=GFV8C+cxIR zO}LZ08dy(RWm^>TmnnB2w*xA_zRA_`_a>H;Bc4)y< zlEm{r9$`{IYwnWnu8=7i`G9^t@>JV zO1W$?#!+31A~eM2;bkHGan*+qj4pquqHb@40;^ty6EVt9uwz1PY-o9$GhzK;4LM3P zkrAx3W7+E2fCtu?Lr}ohD9z?1=GN)Ls4JgXhkxUDLsKi^HvnLD^STZ<&p zp!iTH%Ez^A%u0SZB1G04;+Y!1t@a&`W-Wf_(Q zUkxX=XSwpCq7?^oKiB59onw8y3KM)KPif>0J)G`UnjLMJc)WhuhC&-{ePy)9!r+?p z;vLEUPNhp~X5MwpNQt+0|C_8TH$==Edq&bVFs&10Kr}@fI^Nmv*Erl`y%!h2d|_65 zQu$bh9nSa64u?#fiBFQZL0*3*%q$ozI`!U9z4tCzmL=Je+`BB}if!CwV;jrZ;6gEAnPQn5NC<&ILI~-U5FmwAO0aJA z|7Pz_l4(hPf5L^k)85YPlsB(@?|Zr9OEQ6|h}!KN>1lbCI0Zzye*zG7X+m&XuoIU+ z6PiYne6&3!QCLGQnAc)i7-S1(mN?r(&_aPXWNZ)@%&TP7N>K%^3yV=;;Mmg}sWdO!_ULfQPS8=s{Wayssdts+FPSNSBl#2fpKPL2asw(h zHzz1$4%(Ki_=ZAlu$x?PxLdsTSXbWeP0LEdD6N=ypuP9$gLSaI6Iw3njtp+rWI3O9 zZ!6q3G&^hKW$hQ^V?$t7YwgKzEG{nt)JW((!cFUpvF@!GdTAXnuGc$ z4yhA-6fD%Gbh0BeQTYbHeg#kD4mM(uv&KjA`p-N1smkS^_tjm?*Q6P|{nXjxOcY^^FMq}R z&*U9YwZij|cMi<%m7d17%eTLFp#36u*Gicp>b z>=)TXti8m4HcN=JWxKp~uDZ#U*Ica8e|DNK4ZRdfp%tKQ{GMtt7dZQf)`sCa48OkX zey{u1UmH5=b#%)#w>0f?nm&uJ)n3-p-{NQZUA$Nz;aK30S2DfHFNp15raxzZ^9RpB zz_Km=+aj@fyvjSp%gZIkEhIJARc0evzI0=Dntbsh5F7f^?H%#dLU}@N?w?fXU&D{y z+7F1@UHl5EjR3Kb`vc@DEFEHshuzkcc5!@e+&Sakr7i37oRyo*wauF=eUiPrT{LbX zDIu=1O)`0qF0FP){Qm2Rl-*s?0nEY5V^y>IlJT}UVxc@GSNbI6`EzCo?L`m|1(~xy z#eA^!P&@Z0c{}t(4>0qY5lPQL_>@U698ek@+y=$Nc_FaOF)*cUvk}AjlY%=7HeMeI zw~2OGGWGUE@xdZ4#(?R(byvbr!Yi@evE3(z^Q@!gj_T|d3Fk=^mXzzc@a7na-tf!w zZNypu+^4>fD&+i~fQpgA_4hW3uf`2@)?}~%00-XGk7aKoW)*`BgL;!T3u6Z^mD>&& z^xAkJnNX21rQ_IEgJ(rLZzNDat#$3*r`IMfYt^{~)^`u5_aDZI;-D{4SjM&%H{6q# z7SzP1 zg-vuN^%?rnsTL0UUS)h_Wr{DMmD?X`U!S&hX&&XY@mm67y{!^|zRqDT(Ir}c`K$bu@||4?7~2Cf#xFDq~CD>UwbD#5l*2=`zZPkGV{+{?Y zxTP|VXlfj)?2oz>=pl89GaG7 z@WGii(d6(WZn=}?|5Zd911*jF9vO#mXEMhy(%*;y3`ng{4KP3I_>=DqemffQO+}=x zFN3`LmX&_{cjE#PgA@w*gRI?eh(V$!IM_M)x5gq};&Q`X6+0C%bsK9Aep_5}g7-`) zi?3T>8N$uZV67{G?RXe+4tvIcb6m94$-^%(DO%-~fH}$sjkX_%hmh?3vz(o)=EGa$NbugB|N2Gx8~y7`Hh<<6|`o zZc?K#fWpc4F>&GF<9cweDe%E53Ng8O#8Z0?k6b-LoCo;7S<_1wIa|U4po9eR?{iya zM7lNux|2T_??R&cG= zp@j)voz%iDz{NEpz=h-3J2$)&)<%@4`1vFhg+{;{_lhqJcMA5hck~T+bq@A+aPotC zLgpS8%aO~P#Iz!TxdzxHyU2`gYAtc{$Vv|3KfEoz^jO@h;^+4WbK)B$N_+#?&V4KnkodXl7}r2}7~<053dF!V zTEkliPrO01Va6Df`Yx*Ii~zsnP*?ZJv;e=92)7#Q8EEgLvg4@S&fV70$IbrV0U6OA zZs93@{^^k_m(b(@?1?Z;ht-^{z#s?=ef7|-xG83GlE!v8JWEyp4Hzqx0bDCfklSq{eH7I z7O-V(F@N#ZwM>XF{|QUKH$5jgc=dsmvJ6I-%9;I>{|omCfV!}%aeheSV7kA-0R_`$ zzO^8_=jnrc#Fx+_^D?pQHBTEFWc&!HQ&g&Km-t06%TlxPkkD;xJ2|l~*&04Gv>WrM znf#bC@UWv<=F8zPK)*%~2ed!f0{m`$!@D>2T(1Nfhwq2ZJ%Vd~i)%QB^k4zcK;&c5 z`$_zlKgHa}zRA+CPV)v`tsiINEyO=Kto$@~PpvQZ)BNfF&AA5LL!!Bgd`48?bhQ6> zNf<|tkN@A(FtGoDG2ut>jCewp@5(mPpY@mCpmP_A?0J6YE#wfx70fXkhTkELg`C+G z4ExRUlh`Ym+wUz$S0T@5Xf!Rt7hPw~n5VqtK|v7^i161jfH2W!0xFwXg^~aU% z=uMN6tT)bdiAcgXg9O3MlVY*#oR@3mzH~$9uI4x^TN!5?klvcrH#v}L zWe2~wV^m3so9O59Rz<3#on?IG;2me0>-P>6hM1e%S|wC0%X!;F44HCTdFJu@m2pE$ z+X{f8s@nZf!^)`TW6Rs}ZO)yho#PgHJUK6pfwS0w6h*Z3C)Ia$$H)bBT4jW$D8iOk zRNZm4uk=uA-SvN4HQsT-CaJq5MkYANmc}G@m&YsjJ0)fp1muj>Cn{vNktN#WD&c!H zv3Fl>LZdF#)vcs$nYQoZT41^(V#PS&k%nV~Df&aiJGC(-syZF|Oi*rX!t4uP;VNqq zUcNjlrn4-TLm49cL(I0rx8n|-5_%WIen4X4(0!VmdRG5-#dPh{j}T`r;MTvySn?mMH!lpN-5sS`hV-g)qa!!;b&cyOlIx#r}?T3f5Y z9s2h4iDd-{x)1Fwa7@^=yj&^wNUCgVhvCS^Aq4vH@AxulHs_y(IY*?2VW+gw0m@Jh z5HrSWypd6E7S&#%mC1s0s)C~0D^tv;mCbjYuP!*WGEd+_vTCBeM-4%uq*SADkT>k>qbp$Pw26ZCH<~kT-C85;@!BGG}k&vV@XmSa=e7 z0n6;+Q(eSmiGvLp=H?;AV_{Vp{$S8aDe!Nx5B78CIj4Y7yQ)3ow#uR<>r+U+{xU~|K!>L>?ZsgI(rO7JK-gcm2KwHL+*xhcpk{l{{d0$&v+rgap>2f8Wg zc*&Wg+d30Cn%=wp;L*G%OHLo!+6DzJwR`-)(LA>#byr_^8DInR#Gc zi3F9flAfVKCN~JGwR}oG#G^BPTW9--lBD#?Xh%XONkGM>#>BSb1RD=a&xpLZ z$hwjo_j;$$$apVTA4f~U+O=@mp{}ZJJq4}~iTO3r+5P2-euyAIoyT)^%zetA#~i8f zK>{u>o+PGJf(nh_eSG+9lQkr6oVq@BUd4xSQ~DKOoi(~|ww;?g!Q>5{`!%ri|Hl6C zK>X3LiX~^dS~{c`97PLQ`oAdy63cov71tg~=)8UfJRZ4iE4Jp9ud7S&;N{nNLE#cr zln_&ytqF3IYrKa`E7sP;nv*ZHwyo|f0;^7Pw*GVO9WG~Lb$5XpX)e{vH}B3N>Xx?p zTwu+75=&|tg2gxUfvnFQ+?~(*NX*K_-P~`0Vb|gVCenzd1VKAnx3|r#?Hu$x=`?ZN1nZw)CaR zW;T}KkNcQ^kWWGF7UuI6ycnX_sG@Tk!I&)1WH}SuOg-ceiGR^0S#VZO`)&-EtZm5% zGzSAy!<|pBr17&&%pt0atKN(Qhsw=k+Dh5kqvWQzhS$bi`)}^6;z&ek|Jv<2F2m0s zsv-K7MX4a_{r0lAXo8 z*GA=+s$HDzC9ECpO^yr+?&(R|){@k454od*-}NAKJ7s82)7YI=UE51s&4&Ol84Bxd zK;lqPZc|rZ#5j?GHB!7aUUYE#NEPy=iZ@I(()}3UEYVL0MBQG0=CwtXRGVNAd^f{b zQWsO$m-)IRbWkLMzc_*Zx$^QrsI}vT{dLW29IYHO21_@{BlBD1m)_GCW^O%j|JxgD zr-^^n!R1BfJZI+@R}}57R@m5d9e-iuBC%}RrThLW-R>3TcJ#*ywW)wabsWFhzV(N9 z)tHM&W3?(6++XWoTVI*x%hMo)M2K0r7%T*1Oqd@~(!7kL!TPmW>E;?Q)E{0^Xzl0{ zIIXs|v+F&h=u&ccW0M01Q<9*9*vG=Z&^Bx$cJf*iAd@730Mq(SV1a~1)1zj~6U-_Y zN2>5IOpCS<6jpvPdyA7oz3gSt*P~?ABR4CqJT=tQUa)hIcs$C{PT`{|>e^hUZ7Ym1 zSLM|$$(gEg+)Jf3`r$k#~wsS^8Xsqiv(lXSuww-XkXc0rkw zU=l21AraRwsNZ}R9N&!$dzDSe`umr59_4st3_X&W!A z7|C^0r1)j~=zniMyg7vjw_QYNTBs{eN3E=cvt5@qWE(xp)`b%5(-aFp zuu{@>p{(PrIss;-3ymNVPBE#v82>b%C@WX1&?F~up!2EThb)5pt=+7h64Jx7WBn~T zs0P9L8V_P^eH;ZOVtn<>^l#8Yy1^SPGXi(Qjd;Z5AO=j?x{zgI@B5h*VrBR{I~q2p zY4+g|ks}%nJRLm9audA{!_u477FobnxuwD*GOKB|E)nytROQz8XB6~g`dZ55R#}== z9>RU%B}>6#_NTGsw!D&8xW|Md2ri4f3$N3{2W2)s^OUjPzYntQP z)Hh)2voQ6^t!p-KitoMAKu_pro2Q#e{mmY?iq`fr4aceC^2;iaoaj@mlT4wAl8&xs ztoNz8e+Z+{HQ8QUARwE^fMGzH;{|8rA4Pdx?!Lk$msTYy&07yYJ7iI`t_9pP9yxv4 zy1NS3&%7%RdGJMoy_o3a0krz)ealu|TCSy&L|w8%m(yPW1eTklzER5bC#akEF|UWd zA)S~;0gte{iFXF@3#0%T#||kKM{lE^u}Z8Nx${z&L_YHr$Y++641@8|iAHmKH?DhYuzy9Fl zXbw3=Qo6@???#npeT4p55P_8~&r9tAB^XWfz1)X&gQnn_XSnznSM!ZV{SiA$nu^k+aovE*3y-~|AM z=qY^GACowN_H;p8}u_L)v)S~FNB(uq93US>tJ%8GN<0~ZD&Ep<0b z6t)Q+g|+urZ<%>d9P{7{u};dJ8~{rixqk?<_y>8*ilHsI*z42S0wHGE;t63GZLrw5 z6#EA^4;CWHn0c2z{@x9}SeAY>L(G8Z>o0=Cmlfg(vV_eW>SxX&@4$qa@?A7Ci$;ZC zuW!(if{v+?Bqhe=<`Vt;a4OEe)j^7L*0y4D+|%1q(8ChI{g>X|Gko8QM1qm9)&GX5 ziKzJ-ayOBO?nQ^0WS;dNqILGZ= z`Fl_5og6jAz4`RfmqdT@Zqh5Bq#T!h|BaWrXz`bSp)Yql|HS1&j$g&bdhP*u#8;sW zIMt!QLR~eamr2yU5>SCZdTMNDy+%cwh+-D#3+JxJ;ARV`;{kjx2>dP}i4~ zyu2yH;wkgaL(^@omp0@mh1jyL_$BQMSzPtd#$CA`_pQwmp5g-wds4Et4HPLAeuYcZ z9`xYiJb*pRXn{UJeDELAGufvhG`44QNqSFZx=X|Z%XJ$%3nQHgO&UDiOVYaXus(cq z`wMc~Qz2j28i9XUS|fNG=BszW6lgg9f#>x%o|`@Jf_?_MWFX?GyLB13hRYbsAI^zF zFUAsa6n0>kwsI`n%0llfB$)X!n}CF}k-L{9*(0N*RO9EY+{13dc4piIM_w;GLMa`py?g=VqmvCowYP8xuS^U+@ zw1+FXm7UrJ(MSYglJf3hiC%qts2ObIW>oL}IqX4CutPGPUGkN3lCP8{UE=i9fL~+Y zOmlECYo(^_d_w?pOODp!#C-h-)uIK!QGD{1$lC3S? z_gp{YjE|-GsN32ic+%F>udf{c)!9b!;!EuPs_|dl(*)?t>6|t9cGgag<@1DFN@tJf zt~uW!ePm;hB~A%L7=wkq%4Wltq#O3?yGI8ur{DU_xK;m-Yy~)i+3#M%{3R{ShtYCg zNdFX)^fSv_XF8W%7>KYenb9e1wH<|B&$e%3Q$kxj-3Un;y>FO&UrdDf0IP-lH0@&j*FG#-P^^_RsBPY z#gD80;%(vwYb0-OPR3-NH6$_fP0zQbF>%UaHLy)Vj@{nc?98^?+M>^b$%|`S+}u~B zojwcgF!`DQ`HFah)aJLfxbwSP`_6{gx>$*v;4gvu0UnI`yxCDJXnhwv;aL2P*OIx5 zklqr_`Q#3k7p{U!SZ$?$)q{p8IlJJz-n_~!?O9GYoO_SGFxGZtd2xus!pSP3YIyhg zj^z)m$>hn8i`Ue`s~uX@JGLQ}oJm~0qPHxHa?y<&ipcQw@qCVIJGLIXxB6h+{gYc; zkY7@;`RX7WgCgjHuR?B`II9pr(i*X2UorX7Nz)U^u1f)=mb(UvLapVm4P(Ste%~63 z%)X0VUkM{Ea8`X2mzTC>)4?+p`UxCJJ@pTqoM29?|BBFy%^xZ(v-rXzh#7hy+JjB% z4|fm5iALZgSAgKa96p>^xA>g6?x$pCwBN$K>%{ZR$Qye7b%hGKbHuGj%-`IdB~cWu zNdCc=(TmHq$VK4(k+Gy0YBNnI{)IzqobsXLRmkk%-Glv%aWHw4Ign%Hm}H;|{EOLy z9nTyQ^Gpbo?&>?z8l>PXYxdk28=mS7w%~}uA}ptM!>NvthLR+UqspxQ9c48;mR5KL zR=4z66tAg+SP z+|D;Cx@mcCpp9K-$Ck37j0m?$s%_tt>k?XDU6klYXx7l4e3y(hZ7JAm(OCC#=>M+p z(8V&GlfZJ}kisIx2^Q_QKogsB6p5Z8`yxA<%9Ff!E-<+`I5;!RiSkvO?=F2WiFk!I z6lvr#kA#9i@ejWZZLdj{%Y(A30{#x(08r9|X4WM|>5{|kEF;r(p-tw?-QTr)A81p zWwEdsV2X-#5aR5_vp`>oNNviFvaO-_o!eP;O{)*oPFGVmo8aW~1oHds;xk9IYbNe0 zC&y-6#W0dCK2Lr|t%?rp+yFP~7m`e$y8vzvYqYUQUqKc-(v(cVN^WMNa=L1bxa;ra zy-#0zZfn_eIdU#O6bp&{&&gY2D0|UlY9?lqXW2{tC;hMRe7@k;xfd9hbgU$!uHr8( z8zu~-bu>@y`xRY2uxy0rNKkGqP*#%`pg{G(-h;w*WD5+Xsfeey>V$il1r$*WPZmMk9 zQW*&JcJ1bB5|JMRVg;v&{HVzEK)6@IwkUC-Ai+S&#b3}+XqmHTJ`ftRfKE1mVxYdeba`j`qNSfbTgh~CY{^#sWoqG}MGzo2ela9kD&0Iex zp2@cI3eRlaQk&=$s4Y(nbhDLrNFA6Gf0%P{&&Jkxaz3)St+y+Lye`ct^TY|8aZkj3 z!KEN6T8t!7L(h@V{xCDWQw-ny`u=M(AAHW`;5mfZTU_|;o4DTe>c}tKiA z?(o6ACZ0WaZA!e~ojKiRTe$Pg&4&G3B6bL=@N|bm+pRG(VYsm>6I{UFE*&O8YTQGn z_KW1T065@iVaBiIkfT~d;s`wQpfJL^n6`P%mT|3f#+Frm#i4}yiZ$etCy6ZU8(FRO^KWWt z$VZZdxpMZeO5js-hj->!#cv!e;)oLQ4uv^U=QMToKsvB>B|amqL(GLyDUx>opQfkC zyXU6QZSFajIQvJe!B*~GZ17-`h2Lzz;C%{zEY=g|?`tZWhD*AxOI@4RvZo=yJa$?m zGglWSWo$_6x=wc6V*RHM9BCq{;tO$2V6LWsaj6XJTc$9qi3L5&*MXd!B3q`W&ymgN zuFrh={*0+7+`ST82a7{JBk1wFZ_>|>F8ub~Q9Q^ky6E?_ZK9em?+rDp!~R%}ceaxC zY7iaFtk?QNhBIS6NKI8@$wX_6Ojfe)WQ`aCEAHA zRAf767gNhUPP~#N_P4G$BzTuBSv{T=w)DjlO(3jay04l<)iLVu^q$RWlL@1(K@0;dU_?gZ27%@hd%peKUuBBk5U^wK=b8ne;4cj+>jgUWC-PXMRlDYb#{3 z%8hrIi(d%#p=m+HFXQuw`ob6{naKqaEVrSjS{t@hhlmfT(?dbuj9Tc#C8~hUkvDMD zjK_@W%SL|;z|pq@sFAfk@6?5uV`yp+J<_Md52H;SXJJB?)<_*%w zkZ&a|BH%-$BizI|!uTo>jUa#cPYi;(m9>f1Cw&h!cde^(QLCxO3u-ICIa)oQ{dQ zM2En{>QuG6t*n%mW+Kz1E)Nv>&QaNFoM=5r0IyhEUO!P6MmQX>`G@yxXo@2zBXyli z`a;Q%^*<610CgW*921%z>O|R|0|o(o)1hw*{=In#!j3uS-!pcLG?I4U@27iJd%UK7P&WE$@e9*Z`6^W&|Mc-IS0p(TC7v>!O~x|;%^1!E zoJ}+06B*ai#Yc=X{nkt3Dbj-xVl^~Alrc^cmd#|qimPuwq|yO5T0|f#`^7b@lC@Kv zQB9@k_Bq!^n(nCaQ(l{SOi=h|gD$2pLNWdPV}fN!VPbMic8KB{Tt~lYJ+&O*Mdz^W zh=vx9%NaRV$NS&{3s4R<6-`Db`dfwbGEh?ro(NDe}Qx{x&XAk`U z_5s?U;t~KCdUux6U+9B^N;AQl;g?n&MSrOe3Mo%V#gBk=1OWlxqu?PExtlU))7n~C z_>c%pDIlDSac$AJ#FvxxWQO#@^O+U-q4SWD6!<5QWGCmngn+##-tcInvcP*Pr(Nbvy>Nm`{w~3 zMw|`^pbfJ8*iD<1+7)}ww=d$FUph5bXisfb`hUSFTcDf2zBo$2J-3>9HL_~&J-D_W zbF<*|uio=$^Q3Aq>pZuZrrup&j|GMPh9eeuC*&0(rReWB2`Ts{=3zyK-j+P!(75Z` z@B+`NK}tQK5}TQnDqJMgmL2a1;hw8td$qsku{%l^F`h2SD!P~)wQ|RUZDKT56`gwu zc6>FuX#p+6%-|VD&=xeh*s)yg{UuM79{cUf^vnCdctUh1JDSOLv6#Ii&sh`2v4MM> z!x?oFce8*t^woQ)<@COlano_57oVg3r~dVbxS9kO3aAb*{+zv}W9d1PU($>7;?Z^Fe$;dFkV3Aa%3}EOP)b@@{N7_P<*xo^8)(j53&^9%rW-)()Ts&V6QTC`Z>A|r>L>( zhVJWkN}ZSFZ4mmO2%ku>gt*cQNTu_V#2h4ll*BwA#dIGg_^>xL64|UkM+odiETwWcM1o!8LKQQ21Anz{tb)R{EfhCNS?Mu@X7>TO8B{%67^1<|ibT7G^2 zLVuKn#8ACSf1Iv$;D}HDUf2p#`71_`br`=>MT}}832=liiQf#(-uOoP~h)EDn}E>Crmmk zzjJ&NV1i-7(MK0dyTBj*&x54u5?763C9L4mME(CTQcn%&m%#_Nk#08*mNb`;w=%}3 z7szs9kiu>1&(}vy4ZIx&P2&U#6>9G0-XxwZ!ZR<7%jGmmb;d^qam;%Y? z_bp?nIC6(^0O{OoVj=G%-vz(44r|yHX+d?hMUD%U%acfj0KjD4ea(UwNedD_LtYGd zG-E9YJ*Wheij^4JQ(m{E77S z(}ww3uXWBSYl+wOrn{4%g8uB>t_&z>$GQ6!vU8X``5|&fkI7(TiLdx$58|4$cSVlCg=Ulo2W5o2P@!Sxxw0s))M)8RV^o#l z70JHrNjGJMgtb*B%jMy^<{&(2n(0Ytzg0kXe7M%fl8_Uyp$kSTqM38eCM>BSw0Uzm z$ZLQt^IP<+#eM1ScEP!^ap}IGhdIu9Eq+wkc&1ze6{H5!yO}CGU$a1x7Lvo76%2Qbz59a(cy&2Jam$u+z&0;t-tM^_@i=sETVkdZR6I^=Myd z^sNZeoXJaoqg8SJ1VhKGYig?roPBd8e#0SR&?#fSJ<>7T#Yj$vc$;+yu z=@sG@9Pe?9g;}KgZO2)d3LBN35H3<~upt9gLNT&?l9PP+Cl0Z>wFy4)ssM9G3#UMD zH>Fs<`}!k*sV${$5%qbYR@R5Gaa4YGv)3R$a7)bb7=KF^k5QB((w>F8v$Kr7Zkz3I z$^_+>T+5jj-<-~yras>>@!y>b%0EW7{X3oPB@g_6q>tb^vgdY#f0)%tlp{`r%mVfd z(zz@tVJ6f0>)D|6@#)OzKj5XG`=42fxqPw$IXKHn@c+zC%+~En==FQ#b&W_{=} zMCI-3Jx*fge>b6+Zd3A^#pWQ#h6LS|4H7HUnPbESxfGD3>_?rpzZ?-O4b#K3YdJ70dTLjKKJ2|zpAVOI%lP|LYUru^sy1$}DM!hnV z9xx9M))f^L6a^;aDd{FodB;%d@ZgGc{hMAIbNiDvGQa3#58+{vWbl6&Hxsso zVU!s7Ps+=H+mlEm2VT=}965ez?dm*NMW{tu@BY@%%EA-}*edm_^YN8sM*pF9yM)qs zZ+R$3Wj3CXzOY+@=v`&vZ)=W^W+8Zm4Y^?Sa4GR?IzE(6CuwAHYn1pK z*QBKQ5HR8ZV;%M9KZjSqcS2)ITf<3!x?Ts!=npY+!BJ|G%m!{~#5i!feDfmONv~gu zCIkb=>d?TBl=Ijj30Q3`tqEC4AnRjpuJ5)e=>-SQ(O!JU`Mfj7|8K^nY;tgL)25I9 zFBT^2vt(mJFT1VJ|CJR?^p2c^t@yOdc^7)|e=|IVyuraOTf|TQFXks?f1kLW{{S{1 zKn{>XCW0o;#Qezs$)IomNVNJ!-te({4{Nm*=;!V@-8lU4>SXzhpvoO8$sB4a(grGn z<#s`7jj0>N?PS<-{gqdGzpOlc=js}mdIeh^8!BAOC?Er~oBKx+_0dcFS_&d4F`O5r z;x^Q2s063pd>hQ)1U)OqmG4FU~FGbsJgDE6nsc%ogn&P#y=sXOF085bp)FY zWU}mqQw5)C_-xheAFql($~!X;{ox_x!Nzu;}48p0vqemE2Edmsw*omlM=D> z%E%==5Sjgmzi;k!VHWEE`59{XVqN6=DVKAh)WUu$Nbui8J{}}*BUjZzaE1l$D8=TO zISchyEl~jC==Im?Q!`hMtxWG-E^zB99~zr7wsK8+w54!V+C5}>pPD#EgIp~La%T%` zS9B4a#NW&6rI;hUi7s-{#qnWPV5#uI=KfU8CbH$r$pvI3RHAHY*{290W+70Ua7X2La^8y@)--o`&gH7C8vcx^%H&sK6b75R$YA6## zE64-!FN{MiDo+q3#05I25n+ZMDCfjv%LjTkPgz~*-9jETCt6$a*<1T9#Fyxy{A-9`d#;f zk4v-I$0fMxf3nEOh5EA3JvV#qD;_R({z7x){|LpDGgbv-rAnb{8BD#!mDBi#R*JtK z)xYtd>ZfVj$f*vo_q(d7q22j<4jdv*G4QXW-9QGAk(ep95`)h-RdqPMQv7lyX<5wc z^q*@x$UDf^_Ct%Ao&KBp4u~aTY<>zMrNqwmH;_`JPTppYNLk(V(UfVyRfbw%S4jnv z9jqobcU@Q`$u;IyU{J0e(FLdm@=@Y-LmZf}kPxoT5q~S?in9a)UrCxn&tn(|$%n&! z%#z0|@7?;s<^(INie1lbvPQlb*v#AjJ%0*tSe8^SBAi!q^v9dmzI?cv9-?_8hsqib zFGHfbzSCrD1c>i)aK1`$J)kEH7Q8VhN^Nj>wTYfFJ-zphX)TncYfserruLP@DCBOL zJvkd{41f&r_gvok%S)P0uB);?YO5_@l9@GJ5k*B$W_S>$fe3|Y5cZLh;+_!BlBd!5fmRx1{_3^)Edj-TE!WY|f018^#B= zAAcCPH{KKVq)hk3j?fbRuvkxoU)+dQAN22(h_5<>4u+`-!Vvm@Vd=k0UU=TXfAzDU z6Y`4To-^>Z{0RLtc_3N*-N2s3-SOxMfWC1mx^ww%+WNV^lgzwD_oG{`llskcn?7C- z@GyJURe07t=-1cpLH`c4!<0CxqB*xC9uRSrXt)fJ2iyaLCVvP0u#)E9=yL>s&sYAU z{@8nq3tDn&!S&0J7FV@oeZV>sj-n4=`@OJUJT|o$s6f5hs#}a!V8726e=F}o`wW9; zToJ~VXIv5Jl0XK&ap{e(oKLjpGQV;0>AOrB_)=fRcVrC1v#71xS08))caHZxur3wL zZ}nuYe`;@Ov_j#XKal%S%{+*L-a&KLT^Ya%thPTUt-##nWf53`CUgapqa$?V@~i83kn6MG9~lYDYkMW@rh)vEzvb-RY|K$<`5J7|z`S1K}v| zT6(xJeIl=HLvxy+LN2#R?LX3GpH!ytlqm#i;h`x>Kmo2ot+ka*6`EYqo}5^d5?~Kj zFW<8vm7(IWd2~T~j-@pxSO$lBNBOzgDmg3a?&lc(3c^%q9n?1XS~D7|In;gV>2E>2d_WUs zKloPI3&!-%cor5~0+xnJa;9;@fw7P{@n>WI&oBEb+*yAfU}u^)Dt`gOLJfYgu|??;1uKk=VZF@Y(W_wx;{GmH{*qc$Zh8vz)7^eww9S zC}9t4BBy!javXT%Xm~=Na(8I+ES$UVmmy9!h5Yhk|mkw5LstQynOV=E$3P|cHjg>3> ziUzZ;8hI;U`y=hJ)h*v&)o^6A)b5ydY;k8=eqSys$(x8Q+4JOxg%Wlj$FUT5XRgf! zK1qfU1vYeclunP`0HdU~Wh)pZ!Ach68p>G7*6Vf4ZvqIfAEt-?JzF}_9#1S4Mn*~c zGyN6}6xslnB+sxGrZ$*Y`@jvmeQA9CddHFVL~) zX7{!>Ja~FXX9DGhra#%fk+bZ6X0jc*j6nyzf?O0|zDSYGJ-8~F_&1(iFYQlamWtZg zEQberh9pZ36Uy*YCN4-=;Rt|mtMvyxxGERXzj=RKs9f20_(pHriKX$fr+9ZT)@Q72 zNm1Bs+k3xCz%TWg*WBJ|f+IHqM3@BKVb>|_ToCOwiRvhD_Fh2jW z-5~ur6<6XUs+;z6nLJ%_m$7R zj(!E1eOM~}{qFtJ-+#&e4mkk(g=d%!me*iLu-F3)F)ba8GnUt=He`Jd2Dw zjMGg2d)?x7D(AiLqM5JUw%*T(8U$W`Vg9kpyohcYOgMgV{OC&W8;rD zd?YlI;r;@ef~;XK5%>bIr(wg+w@7~3d3J?XO7H6@9X&VS)1`IhhnrjT4iDSdSXh>> zzqd;iyU>X>NFb9sLHIN@57a^uL2v#50+hPW$i1>1{OGHcuFT{CN=n{|m+S@$o`A1sSi2{QVg_tJvoR*>qr z$qI-tEtqmXDV5Egkv%W<5WI$ecy}`;4xxFP zdK6}f(DjUfXCxbCQ)xg(T}NM(Q|e~MFj}2$>un2J@E|Z1_ha01F|(3srZq)6)e8Yp z$ofSO4Hu6w6P}Lqwh<+XFMDju+t3MibI*+SWbuRtDQ~-XELACsF6~K*%MMToa!!ew zDVpl67(W-8t<3geOS!dqaC*(Mi89^tLLZ*2(lqCXar6vPrT6O6o01XDMCM~m*Rdtp zOKUP+T?!le;_|(dqdY0+pH|(}65R9s9z1K_?u{tDN=Q`AnqoXl|J?6+#^H#lRv=C( zi4@4Ra+v7(+VipV9w!BJywQWaUwCF`UWn2?_>zsig=O)Ysh;Fk9Jvb4B{C!MZMQ37 zO}coQOr_NYi=R7wQM7j;RmQ2)%0kPtKF(BC{$8q-UI z69a5f4V2ghWyeNl2HUgu)W3LDO{^{@%-(ZjWx2G+u8MDQM==jE5tMqf!rYnqQC^xSj2FRQ;g)6J!zsV{D~ zN*f>R;_jB5p6+!=d}~1{)&FqlMvg9XZ{=~ech8D1aSX#7#v-o{i~BwwQO5#e1#1jF z4_egmv#J*&no8p3GF1Y`^>-?wEZVaa0~?%H9#)mEv=Wrw^f6mdX>nGH#tQQCe4oja zY)o@BQJHFcGC!szDdBd$yK1{aOTC@!LL(wwI%_I$qs@9wxNVE&ot*A-}bXKh5ie|8#<3bY}3loA>a$CXf zVQgm`wwA@Hia#)*AIIxbor5Iwqm8VDPHo_1 z9`RuXy*X;7HD`CxN@-;<#>OcfVexwb0C z!j`wYY9+U}sbQnD8lw}XZ-Al;bv7xYPHHN~N zxPfGs#RJfGv#sq$`)vcj=ErORc~skAhvQrnkZLB;bVy8H5&;T2BPCAF&k;%-*X~+!R(eoZWD(vFXvq{!6Qoh{O7ZGmEx6~P48UHgqb#~F$#nAfhLzSz%3b0)xq1H3-trY^yMtJ5aKu*%_oXFi zMp7!)gRDi6TgG*6qYVwotCN#gB~@;$4n@W5W6$=64ZJwngbF_D{XU+gU}RrjXvVG) z9G9#wCy|Tmg|*^~4+fic(LBu`om#p?)Ohgi9%9%O$M%!7UhFvAhpc5bHq|?CtdrIY zbgVP81=u~ogezKg`!ZpRlZjEZxe2=6R;-V&x4EE2K)WDsix=Fv5qI%yr*tG|cI1Xa z*x281ZO26ay**WHio9gVRyn4>7EqjyLpC15z2aOsDZi((4Z&kV66f0-fUfHWe>^)w zO$yOG5K&64WBLrkSDJW!Ok_^<<@~*)qrN>E8LvSL7+xno7SQV~`)n1qa|N!RrLih`~*4?=vh`|`+& zbN$f($cE>%tS&AZsY`QmPA_fLlx}R#4MmE7T<@_Sl7>ugco;Hz3v-$hTv00te4qEz zz5Ef*&n%zp_@!CNtC@@g^aR~2yk+=qmswvQ`);mX9OU5d!XC_;`|TWK`pjZ3WV46( z7>ar<%%9Ba9)ZRNWh|ewTUXZ;S8U^ajlT#nT%5J1Y6GqX0)o5)Of&o8{3%9$WVgDZ zCr)SM@~ALA{1h(UTR9=k>)fRHf!QC;rrGt{`Rjjax3;cZQ)FX5T|V>_&Z9k*1FU~n zaBqrx7mz-(*Uao$l8JlZS+4UjTsry}M0yo)QIcL(M+e^@<(*M$m1(|xNU4(JS2)LD z{T>m2LY>S$Lz@nZTSe}X@znjL{mO>^_+neHYv77l)vzQEZ>P&gzE`NrJ5qb)e$yK^ zHfx|mS7I+%-~*Fe*bhv0@rmNPL(>Pvjjm)O<$4O)&HQ~(>&a?y5BfmnJ_Cnf2Y!bh zgb?HJjK5_*AntK-b=LK4akDEKUoZVXyUQL|arHW~N9-VHk8|eI%}yYbjrHRUb)pg6 zyDa7ixdrd26Vt1)KF@K!iNz6Nd2sP@K3ZKwcpgd;b8cb937*6Y)r~X5i{rsA>=j=W z%El~d?w|BIv!B9du;npkX13%3X)N(QUp@c5+VDO5JI4f+%CK;^Z<#SxmR3}IwQi9Cy#L!?CXq3Pke3RrD1P9gj;_xea)_(|61L}jdYQo%oSCU zC=`>b%|>y-s=?H@~jN#xs|*OQNfW(n>S&M^+7cFm3i_-;7uv48A5i zpxif8gHX69-d6Z#pnlm`zoox7UL2bpP=)A(>0L^iC#i?HiA*?>JJ@y9Y?6F#x(;A4!V%|psd!a)n37{dlb7f|kV<=PAcC z&L^C2t7IEp5+_x%btYBL;$x1an7oynw=sbl%h~!BkWITbJ^qaaZLe?Ig+6lFKYx+2 zy0FZqhP#bzZDUMQZ8E^3NZ_|s_pa=o)|2j@$?j04dG(HK%N~5RaI`8`DYuBK&v}Wv z`R%p8X}taw#Phg}k$buaFRx5JLBV8`pSGj~V2t2zEenpdPzkQJT{zJo<%gwZwYt_}y=TyuWF?Lp@Ys-9!7jHj+n@r&(? zZ`s?M<3QG<@U1IZMLmo6kAPRp-ewAlfZ(9Az;c8-UdEO2LglU5ZD>v=N z6q~&YY*jSoIRso|EHq%ayJ`3Zb^b;!jiZ)WkmVP%FLz&C!V*g-h8gfPC>l#(uZOi3!;<)rRFM?I>yVI zbK*-j+|%G_ZB4Ecds}e9>=}ZWA+ce3Qs}@-4;|2S$M;mm^Rzu|$=K$cQ2T@!R8xy7 zD1#3PbB7+vKNeoVPH+Q?9p^C95O0_EU!Nc*f}rxl1tl-iUv{T;`VSQ8T@z)+qs4wQ zb7gAhHoVpO%ceM`Z&E~LVXT+Tf;0C?4v%Do2}S-napL>eW}hQlzW*3GwV$Ty;JrkW zWb4MlF0ie@!J=*1P)OBKMDwd6HNd5prSMm#S`2~$_19?9gX=@M%_E$8PAFw8C5!T*8$w6@ibrZ+P zKK+N}2Vx@mK_!L-_uU4c`*L7s{n<_fcNycdFvhTaP07z3+hMSKKmdHH=INfI4c*0& z_HwzVa&Ys0UD2A>oDds9&^x9?t;>(=>1YXmEu^e4*IPp^G!biBWQS=PV)j+}yh zTZhZxqKqi%TeB@IM!c>8n#kTa!kr5vU>mgen4kgw{gv(xqr$mh3oj+3uedZ5q1rkG+e{6|FUZi;2J8N$KPHwTSpH_*FY~~ z_u=*%uX!46Jt1B5eX|3`Yg~-iK)=R6)T|WtR~)!_LRfr-xkRLj$TBF`^SR?jYsX~f zFq>Z5=d`!(cpQ(az^DMDJCIKgUl=^vsj*X7C@jKrTh|_H7(UY(XwF&I?!3NAx2`b} z+nq5ar+1enhq^1w0dZ{NM5@b+9O&=VA)eyzI+;so`L;{fpQuPFK6PlkJ)Uxnhi>$^ zE_r-s$w}~6Y|e8@pBO6OXmCN>(xKR_n9>9f$kTwiFd-l72k;Alg@}edZ+`Xe#ImAj>y{RMfB zX6uV4C+UyqPj*h~F=WK-3eMWULx;!N%yt>~mQ;Q@g)J*fNl5z zUHa_oXM4t<@PLT$;twHIxAG+G3x~1)NPd@OUlu@nGfG@Flc+2Z&5l(=bcktY%nUXR zyA*T|G#0LAhNr+SImkozKRsHutvk;?Y{`Zr zjf1B^TK(?{mK7YQ)5Nsa=u#uC!mllOv*!gL) zO2ezRG{!5b^U@!lZbLd(_qKw(?R}^#7g^rFc3YOJ|K(Gy$ZPH%FU;G%B%N|yC!g&I z326Z1D1@|MN_k^TSZL~w5gkW;P-v+u%2wS_SDp%P3Ak?>TEjwu8){2a7&+;hLj{;8 zcQGH%S~uq3M_i97u`qHaH{^ngK*GRte^&qmB-Tmv%AkZ zCmtk1+}+*XAg&}K0wDwvBne4ycef%bK^j_$)u2V{)C<(Ty>-9!-pcKz&3Vr6yZf9R z0_DE%``@qkbICb#=9y=9c6N4lc6K&ke0HiUTOX5bY3FL|7G&=e?(|qx8VPcYJ9EZs6&z%RyzX({G*n`H&^X1H&a1$f4vb(-_?EU{0}SPTNFm6wPMk z7aFMSI7@gskDES*eoAHi*LsD*LV@l==}z*q{0G*>qtFxg^HmS-j)yjYZZ};-7a%Ud zbN(glW%K>)m_Ij{ZvJF**=D+kJgH>hW?N$T+%TEgNS4w{HN_1IlINYkVptvK)R>v(vaE1{ipns*G3Xd%^<<@DC!s zDTV&ZgVfwP)YB_I&`D#>ESy8VypS5BVXwBNXgp(b0xGAIdg>n;nq+>pHKEJ*qMdB8 zd%|~4!qs!pB+Tw{cg_2DBs_YK`(OWb?{Wx2S!P|3kA{@l6I*+Ir#-Q;*LT?yYx|e% zh^?Kz(~j8K>AUQRwH>LewGRtGO>QKUj&2@$xht&8zALorKK#{5b3*6X&k37zAO4az zqbifVV5XAGBfIet%RE@D2(S&?W#bhe6q#gilO7bB#>3-9Zm~fK@;C-2c=Wi%1sXq+ zGG$#rM(DW88XAfUCy7BrS4hg0xpS{5&uTr0Ti?l(eah!2ht8iQ7WQ7_{QVg#>J$H6 zO`I$KV^0xcKGw_0!O2=CM0tH^`JY4fSC^}Q_?Xs6jrzBA@0j&M?}M_?C~7E*z49-oKrdIDF|iqiL76iq1h{9l z<+}tpS!Kq?mN+|w#AHV{oYEJ|7KdewBR9h@w3qon#}PHXehqOg1${VlNhh0ym-m)T zXic%#*qTL%kID9$0Y=A$1_UMh*=xo!Y8M(9oaASxA^G{sxQm(Cv@m;f-m)gt)J?+2 zG445ue1=KP_de;7n}h=rK1umLkQXtWRz9K|SQgJo5o=To7?V!NJblxYwf9-pe@T-> z+q~u1*lz7=to1EG-UoSxBt`?-vfcM>dh!)gut(Xxbl-XTwL^!9u8vS)tKN{mz&WeE z#%Ewy#8bF$&2`WB_icRQbyoN4zxHXqRsO_7XB547=3DtFN>eO??FQ%9t*}rv-zOjj zKc-Jvl$DOIqr0eGaH?NP*XZ`OC!f)r$(x>yT_^9H)@(p$JEK>>>(6uf7*rSBSz@Zi&T#pUT?^ z4(H9Qi7HEr7;O`mR~gc@y3&u(G0Hk*+l`M6&x>%R+sT-qoao35f1HFxn+Wc+{85gU z2gQB|_bG-~w~qXh`)lqk?p*tHOvCz9ExmV4^|i7Y)v)Wi#f`gXq{t6w<}9pR*PLW& zW2TF2saiegM;1@n+ZK)J{jE>8xAk1vhl_ucX57-yvsz|ZUAL6Z$l2Ue$TZ6q3z>4+ z$d-_eHQ)Oek`e3Yu~_X7SAB;lD(9b_7j31poqgi{<=TCFnh(w^v^F!h%j&H|tJ%ce z&-P?3e`#kaVZROCK@vOmHf5G=o0ZAXKI8|Z2FW&KTohKF-;RX1W|Ur^P3v8Tetm)I zT=e%QQ<>T*oBHK#`<45-T=;XJ;W<7_qo<8ec`0VK=U$+Hy67LtAXmw+iZy?L-4$6!sgU4{dmj~1~V|wP?tGigQoSmqD5d5F5r{gD`Bfls%@;1GmGX4xdpK}V&;0w=l z`sDnT^Z17Nu;B*=sqlENvBV6o0;Fz!(@!pJwJhwurK)1%lxX>!wxuPaEH%JP-Zu1X z)w)JpFdtsKs)n>o#ZGm6F%pu8d0PQ`2!xB1_Axv>$ZxrN>U1VJn|up-`Um}sWa*1k zyI0u({yy16`t?8S*BJZ62hVB{1LQp!^F2*)(c8apwx4q-+O0W_Pd1=EmM@iE2=TF` zi1oenA$9!e%GrXM`Y+dgR-AkG1@PF*_y|2f{u-Le?$*DrEE=XEWQTtDGDQQ}EB7dc z1Lt12hg=vq%ld}4;_)qP9{0Nn4L``a==cAVZI`2MChfkwY{BtqepY6-jk_-`S#Z47 z*YbXyMeOwI`i(8g7G`Ev_}H*e~?tAU$V z+gFyGw_{!jWBK#<^Nn51Gw|1ZMf-Uk&9#W1pXu^=KjL0|?gjEt#g3UtTHVBTC+ZbF z(Z#h@B$#QP6U!r%FL+S~Zb>5Q*VawlS|7ZhjEk*Ejwz0D;fZQg$}=R$S!gehs=y8t zoB~2_3QE)tdt-l}(d00@ZEMf3e&0RSWB#4fd@apv8h2k_vhc(-U#kbqEMjNW)Nh!= zTW%TKRy_$Vx1@fz{#9{w`m@MWnR4(_M_%u%hZ?vXuFRJ6ck~tU#`l-z=53#k#^?6! zL*qr;*$~=3Mr2BJoi`fUvGzVA%qophekg?mc2(@`NYZJ-3tN+(dqS!EB4%niuJqv| z_>H^DTmr$>tLignRHWJ~K324jIK`GH#1uxM5|hwl2g8r-OZl*Sl25mUZvPC7e_B%A8!5M(N7wNa(@-q|asCdrz* zbw^674lKyW&;EH$aUqT6i6k;QC)Cw)YJBHGBd=* z!Y--0udIG)sW&AN4I3LsQf2Hof;#Df_c_p$Y{&{L1=Y48nB=c4KYi}BvfPzD1S4w2 ze%lXJjHx`tWlMp}XI=Glq&Ru28i28KDOT9)@0v2{)|oLDYaUo@J+CiqW<|WkS`3ii zTW)QKKax0OPcyR``gPtata39Zr!i#RgD%X!ykFif?g7P_a2^>*Ag}8}$qSeDi%k#*WFi@fbxAR$A(E zNu2;i^adUe?to_bLl>OL``#7fV|7~luY&zV=RI#N4+_2d|>CcS<}xU!8- z+d}raIBlTwHXO&Ayo@Yvlh;73Q)e`yz%iki1%U_&@|j{cvCPRj@oHo_I* zsXSsKEOs@ux`7k4-%Zg@Zkwj&FHWR@}7hA!3&95xNxF=a6im)%icz3=Cf4f=O!d3In_du=jB zR&HZ#M0KV=mrXauo))r!-f~ZaJ7B-)3og?O`YA4Kn(X}7SKQn&DG)lub=L=b$3=J$ zs%p|1D6*)VjMx?%-W)czh1b~=VK;o|aW8g6_D?MhDXm7C+2x1ICTwm`(a0gW^-3aWJO;@ofOK>FFnw^rX$@ zl}ph_y5dE*HMVW3aV6h-W$8L4U2HV>knep-NgY*e(HoyWK_ z+DeTJq7&{h(J^j;5jL9pk}G4mWMa#cXlgP^Ng>ug*)bkY?ub^{j`J98=M7`$?CylK zLO!aEp9LKlV)jORr-QvCiw4?17)Per)0)H$bMdnQ#)r9LdZ0~rg=Eb)1UEa@ZWV}c^%-6IiyElMZpQ}a-y z#w}@LQe;h0rpqq=uD=Yw(fNq8!x)QuCxqTag+Ek&V>x`rmWCnr;u+|Zqn&{7!OKh`_U*)=}QLzc(-MLX9b z3_@&NLOq=Q9Ie74ld2M(iBnu6hL}AxrVAm|$9cQ=?xGQ_D$;G2e)~m@5BxLo;lig%UaUeeY7zAwk zZ*&Kq_cPiwUA)-FS8W;skqH=VJbBw&tIMBH-WaExPRYzptWR^NET*a}Bd&RT7~7*s zi}y~z#;P_e)i1-HtS39x-sS3>)tHbqV?6F*a8JRE5+6<+0u#Ja^NE8UY?(W9PbOop zpWjm`Y?+qZGLt#wo^A{?8Z%YO{xsg&Y}q|w{*CdNpAV?i}vxkr3p}bg9f^4V^X5H;4r0H^rikIuambs^?}UbR6wTRXRzCpEt@Kxj6>K zyC)SwmZC;9eL&SkqYa}+l$3kOvr4HWokY**%joXauwjWLYa+= zzx}vy-*L#Ob@6i;7v|?gi@X!U{A^ttl9751eQ}DfO!iNY3b1vqib<|ZLROh`T)BeF zDV?mLLT)aB`0E}@dL4boS=qP-I^nOit!p6HDcnc!2km5DBkdPA4%ZBrPe8(0qX8Rk z;IetQhxk@SCQeKeJ=2wu-U8%G z$ZLwvm{p1sb#e85nK3hO?@S^%V@m_Q(%q86-JHXc++Cym9JsFIUJ&eojk~r7M)mrA zE_5c}17pNe&R{Oux#%575of^+|6gxC_vcL0s!RV~alj=a-Pb!Q*wHyG&BrSx)TxrX z`i=3z&F8YWx4kC}+}!gY`KVW)d-+SJE5JD#Bc9-s`zN-9?b|c>(RmVo;l$W6p@AN_Ju5K8#?q%U9|uRr1;n~q z$X`74Ac4oVhH9*x9UaD5Qqn|iypzMdBE0MnL1cyjWrCcCeaj3~v%va_=o~~G3&Ow} znL7rUU&W~gk+12`#UqZ7imVn5&y+CY@kDGcxZ#}RYw06$$WAZheATQxROw&j=Mt=8 zwor)UdFy7RYUJd`z9oxd0-Kv^v-}wIO)d=f*J`U%vQjh@UiEF&{`r1n?$Gac0d|R% z=Gw3cwLTuje^y+te6AMrp`jzYqwr zF)K3F+uCf5dsvEp2qa19p|J6>Nc3|{D2>D+;COe~;KYh3zQ1)6ez2^$fW8`gn)lsH z@)xKt_XfU0nMG{bFD7Bw8Q^?llDAt#Xt;|{giV>oH6+Q$ zH6kp+#V5)}{^HP~-@fup3UP6CLjq@r+gOj3Fc(Kx2SS1oIw6LOO0ira7l?}f1Bs$_qgY*O)r;=fQkdYrGbW29r6jf-t^d7`gP zjk5JJ)lJcj^$hnO?K|4WF;dPa;YE|9lp#v>z6vg^3-w@>(nA_E97ZW`2`9PwCz%Ub z=#n0XtDhO!tHJV;`_|vc8=zb6{N%eI9}LFIbIcJNP$&VaI-+7LoR`0rbu8MeqIF?@ z{_L_Ce%i;(FR83!RatsRRqCkn(^p2F(0?Wl{X|yfCxv<<=SDNiJv=)U2ZG{p%l0oR zt@(aP+bC+AyEt|DVr}Y|)1307{%!rwTTJN}DyLCF& zs^B*VInrU+D_EswN0ww+pDVn%6bWkp3u&rp8)n%TJUB^wt?J480uRd{K2 zSmUhcb1nGCdf`LOeaJoK8GhG7Ny0ZiwTa7l=d zc64$|Ny~6s69?Ct;rLR<^un};G-OtTF`f^unF%@bSgNsLga~C&A5>$|KXOAQhSMVo zF%a%k$?jMX8J|V8G)9fXo?Tsgo>-pSkG!}qaCLaXCGxvssg;Jdle-lQJwgELdkgVi z#7?+$Oph*FgtyK&r%(Pl^e6Rthd!#u$yxnEx=|mkcgJ)5om%WCUwfyc`p#5s!+BzR z{x~It5uMb?vyJUcR9s>z~5dHc7WXHCJ;wr6P(ix1-_orzPN&N$UIL8O-5ijQlan(=pHs8KyV9 z-Uu*G4?YRv$`=sNgS*}q8$G2cd@IXJO|7xHIA&B-1g<#tiHfqavQJD&3gvEac!INq z=1fvWG%U)v=(0qbnm`g$#w;bwa-5@sy*a5O%wnv2sE22W%P2X6&!5sWkjbr(C68Ha zEs#OslQ2f&*B{9%7rb)M#)#kxLG`5R>d+r9>>1J^pw4q7jJ%Me()$)>-dT}8}FDr^Z0^1 zvj?rVZOQ9vE=u$>ceS+5S>85j{ghN2GvzT?@&_H$^Fseb%DOLnyX@hKM|Ur&M+hdp z?`ZqF0htCAOzB>f@>tbd5an%szCf zXX?Ru72%eaX4WYU3-_I#-g)2BTpUO6FYGKXSv|WZGsps0UO0po&7M%Tc3OcWd8PZ@ za%2RiPTzd^?un_54;m{2J+kPSW**Zg?opSCoSxMpncZe%L>gOvf01A zbnP6@nQTU!qAGey!kZhad{dQ&T&eVUT4j_Svae@sIdcCb*X9d%Zf(O6+O(cKXKvXo z)9~t^)thtN($}q+TN{g+bX<@J$v*)8s2JCyp%Wwb#I(3o#7EsKR6T-RJ=wqS!>x(7 z8oLdzDL)@#&%LzxgLyvZ7#{9K~RPVhqKVHC# zqqxib8%-Vh#!Xb`=4Yo()l7MO@w)!ObzBpyQW}@`-{01FFI?2k)v5opko- zR`Ioc%WZd6)8yrgJ8Q6q9ah=BVnbF~(uyT>YtdWbmEEg0!x9T#WlcSJ9ln2Sc+X)3 z$Khh$8_xU!!-Y249XlId-C}S}a%x7+>GlW3wmk# z6DPJrUz+<1%D$z~1mjh~lg=I8I)k^Pee2-eD6hPHNf&1voUYiE6?`M(M0y1N%xE?4 zG#oE2#$7e5J*k~HJF@xobI?U(rn3LYxBqYP()~k&PSo8yCoupCInf2dY17MME$%n3 zTYs`~!un|m*vZJN2~nD9(-v~ZB_+2cJTx}~6(s!fTaroB!0cqWJBYERv^Q1wC=Xx^ z7*;8_qyEJ<{$3G^7H8B&{U|u^!@)v+M%`M!!-ds5D7h6&DtvWju~psc_g8gXY)&6P zSTpg!qB2VhkK%=88MX+aEmyj2%jfMXtKPk|CC3{HA7NYhaxt!TTW!Un3IssA(4B}2 zyrGB&`G?B&_cY9Zc6%A_T8rPBgzWXyj;&>>-F2t~kY0g) z3qcza)V?*Y$7P?P=P$BweY^|XCOiFkNRx3ZbT>meCWpyKG55iD)9|44^#QkGk&B?4 zu}+7Gx{=I|!9^3@bN1J?_fPgSwI?zne)!N!c3=r&^Ac0A5e zLv1|b%i>GtRYvNxwo!FY(vmeN>f>Myt2UmQ((%OZ8p@^|yfWw4hWl^d)Cv`L_t@&_ zO7wDL&A!mai6zNClxEM~n3K4$HB0o7Gz~snH~6-{7LU8O!>8H@al+4Nzo*(x+Vk?- zWp}lCTT$DFeXp!ude<~>tFxNX-pSQTjoYTBT3{HB@=2*qZrV0A$&%(Q{NVT$#@gvU`yJQfxN`i^ zcNf_heYy)Qj|P$xKkF~*LJ&2>gzJdr+8Mdwd}rC*JRq%R*6NZ; z`=dh+!}*z$ad`5Cxs`El8tplqd1O;*WMx6BQ-w=+O%?JzE$FzMjmu`2p$bAl>1wT{ ze=2`GC6VPb7pz3wZo}LnN}R$n{gj}R2E@4gZW+&c&%s?NU&Dt7M}DTWd!|j(;k!^^ zz)%g7d=TAG7-xOAb?x#4%kADiJ~*VlrX&f2o!ip_$Y-694?G4_-2r$WTs1Yk zNQH6s!>W|8Cd$nMGbYYiQ&P1frsJIQ`vIHG!6^k@m5J_V+H>et4_v_)UY3{QJkhPQ zG_kofHOy5drmxKvOq&Wv#h?diBiJCDnW5Th0-A zz&88#sf8F7u3FtWon>@OY2CV*hO|RftDBIlU>XuB+4_H@JmB*2MJSR|K64?)L$|qhoa^AavYK0B0uC!f=cZ=# z*NvZBmEd8k?r;@sppyD(`=X?mEOj=JY>#vnysX65z%=}+aU$meKqe2{QRtIWq zV@V)foZT ztY*u@b7$_Ycefg=PuIER%qc3}ksaz&S>F_sKf5w%EFG;ew~eeCOKNvNIXkQ!$Ez8u z*l@aKao&olsW?FsyvifQ*^0fu;_7-*u;V(tG!neTVO$1+mmt2TH}%*5XAb2q8|%!0h5}xgMAn|yX@Y7?gf*#gn^RW3q$<*a zy60?MK8F`^8(*|?h|WH@8t1n{gSPnc!q2q}3sN()!8UBm(v+0-J;jWQQTea&WjGi= zZG+Ej=8z*6GdqoWE7XB?bY>9+c0 z%hp;SGmEk{=emmL*Cu=D%sg%4E4#Mc)m^_UejFlg&JhJMMLp$VW;*N0TFtX$jNN8< zVP&h2Pn^YQ<=W$Q?T_!m#iS9XGZ(MPezWd@quV=@^u98o7IkVPhCG|9< z@cv&4p2un~A^HWUhtC=#eFsqlTFT zM&|OR=*gOmuWmq<3x_3-{&CBg=N{@jzo~w-zxB9^ZS8!~Qg_=28~(lf)BR;)&4SzF zJO6CCy)PTlW-3iLSZH`3x)@iw>N?=s@HEZr*S4AEH>@LyJBwc3GUQj}zv1zoz)=Bq z(~o|-ebdFBfKd-yT4pS5Yd_qbYm2H~8B1Dc-qw|4OD9zy*wh#L{M?^)Izrn{eY|vN z?N=u!!$Udw>2kUD_GP7v6)ZbB*-&%)%5r31Ej!f$-Xaa(vP-b7;e0*i2ryFpV5t-rlz~<=)X6hsX(G!Bu%N z=I71oR}G9WTR%D6tQHY5s)S6uH8FHa!iugkGs_0g4A0yOR6H;3EzFx!ne01?^hM@` z*pab8$V7nK9Y9D>)zTXMcL|;Gqqma6%>R(lku^E>W#}`5f#~GRtVr`Njpq+^D$=|~V8;u<%*#l zsEe$*<@J>jqpa+gKA{)}&M80DJ+$EBw))Z5)}xEJcYj<>#?XO&x`MFYM}J>GaqnN} zr&AonAQju5oI7dC!?!dtqIhtw{(rukaI44u4W9|Bj`S6Eu>sWOq{MS3uUhnVkM|+8M0#@G~vWDbEe2)v8rwyU%Dm(k} z_D8nA>hemGlHw}oxhg41pRk0X%PgUv*f&ZV3U=TUKKe?6aTi$n;sXPE{31w=Y2gsrIVD?&S5@w zTDgA=i7KCwKuY=_-a)iD*84Em6~ledjV-!Z>d$op*=51AWs?o0G!*eGrCN`kwqi;PaxShf%lRpN5Hd9_yf}OBjDyHcsuy# zbS6NFodkW%=bXOb$6+{g9RcqJN5lA^={S8Af55PO7|twooW2TgH#{id;9s*q$SqRP zA0%;HZio+lqp=Wj=1vapm(3*cCh%TrHv*mr`YQeaaUKEpF~J9kH%T3)qcxb|?W9`Z z&%k?KMZfb!JAdyq-e1y<@Luxc2sqaV6@Nhb?HXM4y9#f|b{VI`$49iFkCuaeFL_MB zV_=J)(I}vkqrO*qU)VChWs4E;UeY!UXRl}_BfeG|n1#ncpW}OJzB9oGd*xv``$OoD zO1~W^lZ^Q68EvEKy@#cru^+F}vDG#Y!%wjUF0D6 zuMl*yrMJaci~ow$$ndqJNIp6emfS4?n@&*56B zy;;x^cI>S7N5EA(*-2!Qj`wnX^Vd8GIM*w!)H&Zw&{6HGtqK1i^gltxXWwbwGvezo zgAZcXpoaUDGI&=Rki+Vll^i7NvYewG<=iSb z4akx5NgN-Lt-t^I%gpgk;;Gk>j~6k!h{P=a3~a=hFA8yu%n1xH%Z_&-vy`>sia}?3 z94upwj#0|kGw_3QQ8D4B@Akiza%Oam#DYq!Y~a%h*NE>_sJ;NWJ0GY7t z!;QJ~Cx*+~mOW?dAG6Yo37-%dT$vYb^qDHxHHMf~37;u6yrwwIIbc)#;+aKe8vD?! zzcna=H)vdhQyStoVU<1kGq%?Fk%MlURSM{tIm{TXsYkW#5SxV z8|kUYfIy%0K{v1JYS1TskO$WV1E~d^$A7*MI+ACEWB0*?Uu(i2Aew9VLI*iMbT9>f zO!zJ){6pk}YxtUH09WZBBFL0B;o~Hsk)H#w<#ogSU^idI*GdP=>ORhyXQ!uy4bZ`9*N;5peDIJT-)CfEVYr%Y$7WkNuTIEHatGvcf?T5ZVNPT*!IBGki5;y zQO^=bvqn}vrbk(P{oG_aCa%3o)k&@cXM_%@eRM$jz|==S3!ULIht71XI<$HVPe3@wv{Z^be6Y zuhADeui_sf!76=3pky)c34F4P)G7UVugcF}&=L4J`x7nkv4Hl%Z{mIyp6C1%FQH?Y z$Jo2NEWis@xKz#kO8zv9)rA4B`d@>F^&}tg(NKcVG~WQO&Xa?NSXg5fKS_)c6~EK4 zNsJL^;D4<-Z^G|1BuH8npDH@uUKRhK;Q=9k%-i&Ctks6;A2hUpFJf4xlu-hmcY(#d znZBc<3F47AvGd%D{`tt?)EbsB!9jBfw5g#>DI=e2o&#;jGUn#gu^dW>$2~nfNyh*4 zF*kdYS6rUo!)JGq&8U#k$2L zk3;AO;UA;c7tenfmQyG&xPC=oK7JBB`|~Vr^k*^oUcfD|Pi~=$0~Q~zyq}MeILy=L zN&(#`Pq?Zs6A}nE;32E3b?0|Cp!zhE>YpqyUJG_A9`^{ z7Xf_q6zKFyZ6u2G1GtTD58$Oncn8@h=$kXxs$qQ4_ft-RpF0$D@}rNe_o}JalqGa>iVG< z6=1oa&HXtd<}U8f@j0zgrLUN476|$RAN;Que0nJ6>|MDWbOb)xCH*+eKjgikjP_^Hi4y#D5fmjp{ERlnw}c!||(i2`2m_DF4dWOPv0o@Pk$SBhqJrAMEVO z4+**9#v36Y!#dE>ite_+|nQI}UzSd`@4* zACNAX@b4FT$njynxw>kT9E(cT1Q zkmKwBJrW;!^1HCpDnH34`Uj*JMSpSrKNIa$`8hCEZSM)afyYUJk4k4^oVpA8IeG(+ ze*ivFg-fdi{De|85+AGWwSxZ~rD!BRYAXIyz)$cvjL=&_A6oLdkbe%&ygZ~`06U}7 zpHAL`ZVs<+dHf=QzgHTBkHhVlx_;p6Np)Q@*ru*q#Clk)2UPq{$spDP9Dkh9XBEG* zUDaoG{mj<`D*i!&qgE#R+=t@$eEvj5TN6J#KBD3uCX2*8rml1NdR4_g41MP7RZc%# z*hv-t2>AuEystQiV@@1fKjJgDB@l#)c4Xq#JoNhw-(k4 zJp%^khxQ6R_B7m~IjCEX_pUO+gUCwAC)uz_4ifxh-V^-8V&c6IsI>*CKe>&=$rXdA zVc~y=^So_-E*AJ$aZ6fqCG8VI=T6AybFC}j2L=6X=@Xn0f&77QI|ANIW)8!F?{36L zzjPbp0l@dyB5o(>Xr;l0Sf8tO*pTK+6a9AS)Cf9@P4L5zbCB`9cG@MwaKw|YN*0hq z0q)&EEeF643qBW+c7q;pH}L2}E*bi~91dMK2pJ6ucxRcAkx_TKj8yo+Mc43u67S`3{$3a4*`t;O zWXJ1<_(He;w>W~amPp3UL@442UtV8i#vz@I$0f$h25L#A}rd!{LwVltb!!G0u43+#%=;NV^2S zEym?1V*IJ&a?lVh#s_8z`lXPy3hy+;N&cV{4EQO*j|x9%m<$~xhB~Yzd5sawYX4;= z`HBC{Wayt#6!_fvzez2!A}8KKUI13rcVeB&+sfam#hOOQhSx8V+eMpTt+}lsvS^c= zqLERD1o+1|9KPo($}ywteT3c~7j$|ZRT;Y}*y9uU9M17yR8AQ2Q6B+xRQPn#scajj za}5rDKGAa@4f+Wg^SMN|WxZsNksrqEjts-mC%(#26F%2-75{*ApXgg*vxMwb+texT z7P432T+dbbLFq9Q{!>~v6CAbd)c0b%3<-Yj5%TFJ5k`J=yq*T|1sv_YY-;b2&`l1< zxGPk3Q`Ex{bnZ3MNfLBaIM*o-ht6iG@^ny&c>N3`obSOQIE419_`JO;{()+h{v3sj zn48u9x*hmp&KCTLIa?aWS8Xo0>8i~g>=ARVTF*krO@(*PQ|*Ili@DrXTYONuO~_59 z!{=ZXei*g$Fb4}dM}<69_z~$VVK?%WKAG3cK!o9c_Jyxi(6ETF=ty&k5BI#m6;2GT z-ZnMjZ)G(K7EZ~t8ygaxH}36bz_;UjB3kJroOZ4ct?+&AwHa7r1x(}P_oN|Pz~=(~zBUW+ zU?aR-#M)pEXqz?@@DL+>qVOHJU`^vL=tS8G`kMuP!;he|Pry@DeB~uUAFYLH$@pm4J((+i8`dxcLe21W}dp=Tp7cmd)&1rdz zMEzaj_+bkE52h*Yy2K9zJn9+_a^uW5#NO`En=QG+jACclfSPur16NA_-gqY z{=AUWN%*3F;XOfE!+)$z0{mek+{^GM;J!)=`&!^XYJ{f<{B?%k(Vu=sc|$LJzY_dn zjVfD+es~V}TIrOl8smd>1@x4y` z{tUkVCcaM+zt6z?Khiv4dVl*?^*wk$`&_`)_qQ)m;o^Ow9cql|BqA5Q-2z{b9Kc@@F%#Sg ziQW?hFo$b8h$`iLhXFQVIMvNqjtB{5tlKQ2dRA=Fp1vHdu4T`K#+KuYv*bt3wysa< zZb(PT=js{Z75%-LIwP}e|@p$QB6oiPfqf@DOqGec70mVXs7(P4UN_kDYQ|IAn$1hirRMFgz0Q-MAknQ^e7EoC1Ckao}-u z)z%1lHy^7)#^QI#c(^abcQJPP?yRO$(0#{9cb16HgOC3*Ce<;0|<#8-W~Y3Va)z*jAH+o@4W&a90FhLk%{jG;yWw_PR8)K-FGVA(w!m?;l?q7 zJYmfJoK7Y1)SOu4DR4{lKj*HyQ}TWkPhG#uN=;pF8qSHW*)%1VoOF)ksp~u?7N=>O zM`o_G#%r1DsU6#^qb6n}8B%1fXKt8V2sY4fVxL`%O`$)A8^`K@%XffQur-=*(QeFQ zTtB2&xXs4B@!yL0qn5`j@g4HvdmU(Zk@y}C8~otk^BW9yN&$IG;1v%)C)bL7pYK)r z81vr^^DE-Z;1@RPV7(fzd>Tw-i8zcJ|H-DsJgy?Gggz)Dj-keXvia>YfZvGUOW(dJ zelNAZhA(WgO23^tjKJsl2rB({WB!O5U*d6pXfWiHZOp5>F|Q$8+9T+nlD)_##GSOf znicrFB#)-Yv}X7&i|;vxUl}e5mHcJQMUqaAq$(aPu6zpTKmDcg;ytAlwjOfg`!COH z{(<-3D&PkU1%~%P*La5y#`$zXSBx(qH|`wpxX^Q=U6`x2lZD*MjPRp^?tRKko(BQC zJ_3F_>dJF|W0aX4W~0*Z9T(Q^7Zf z>!zFF0n&I52VbR{g~R;bG@lHk6ZRt$?@{eXHuj{1JI~z`r8!bCimac~F3-3b@cq(LVG%o?nZ(+gXhN z2gUar<_`m`wQioU%WsKx9i*Yc-ecvbwGnpj8x>AA3A=aW^Y=k6TXa0GuIkJGm}fIQ zkBD)m;v4f3c^=Qr^25}4r)bX#!M})e3OkD)LHp23=*#~-H$vQjt9>8+m?hfPPR!s{ z7^HN(|3%1Oi<%vrF8}_i<`UY4@96J#X$SX-jq>6?hAOXi8pZXH$CDs0?(?YfYA4%; zzWL$qh;2Ho8F=27pz|NG5ATIMvxmffJMVAgInBTyyjSSCh##wZ-bu2=zPGB+M?r_{ zGmm5ab`4+nJSu)W_8s`RQ1LlGs{SKBD)!zTw;A z{eK$q)&3R!h>*v70^TWo&*fpvAA1mV8UTkpBFqFos{g|KN5yX^E^7aXe6zphl^OjV zp0A+dA0bV{_;Ry|r*rx`R8k)l^k0U3ND}h?K)~Bcu8{W<%$L85{zt#?{_McKhW6&+ z4&8k^bJ&4TZ6)}nA@W}JIcg@JgU_Wosd)guUj;ls+RWE>LXI+Jst8SO+nVwAz_?EeWlNW~Z9{~_?9j^|?o~wPb(OnnecC&_W3Zr zW`^z+6aK5xPekw!xxA<4bT~g+@@k8iCse;y$M^pP|KtteYfbd|cvJD;Xn9Sg&*dZb zl{kI?_LY!-jrNU{)3v-UaV7jdE-tTcwFiyw(~%D()a_K| zB@gJ{FyRlNn#v>OzXE{D%7ay7MpFmvGmg9@|58L|ytPhY^c|-fJO6iz?%?t=+IQ}M2S9*ak6s~_fQxxw=$DFrOm5}+WyB9N z;SWl$2z>;;JX++xa(wI~waUZvHD`6FhVh|~4-tEnzGl48M}bfFmk50{(&zq;;0O2V zJV79L!Oz!1A65KYt3Nl3&{m1cPPwLeEQ|a?@Cg|g?ys^Yt#g`pK|Ec)5PFDMm<8RcxX2O4!pm?wm z|4q?>r zepLD=WL56jO27QOe7_N&w|KtD^9Mf9n*cmPwD*Lp`t1$SC*&;vUTcJ_F+K2u^Avo3 zQt^+;L&6@Yc^rIxQt^+;Z6^LVi*?36qdYCdJPmwJfmjdst8g+!_*1;SBk{Az%A4XN zZ+`?nA8#uCW14Ydyb1c+F2Gg#&~L*KzRH&K-1DH4(PmIM}J8-I=V@D0Ff1i8%&ao&$P%x`B##t2bN~!2rSyHt#CUVF{ z?|RPp{9nIoh@}gT7#mOCca>Hzu8uO7U;it-FE0=0VJl}XSe9&$LIvXFY(@^z;aJ(w zk$}4D(iGeZ;TW9igVXn@Z!x}a7dNMnhornD`1P0IZ{hZ|E95FIfV{G#6^3c}Jy*F^ z#NGUP+>NjIWLOWtBb5Cj=ISqr_y>8334aate7`Y2FxZISCf>vG<3)e`q{0~t0q+ms zkIdtGi6U|X_!MP7?o;C90d|DHmx%Qr{K@^-`I9fPr#U|S$^F;)lP^*53py_YKS}6^ z@OQz#@E@fm!2exN0sY^M{HXB1;nS}LoxkCeuLL{??YdLY$4Zp*$>U9UZy4yW5&Yx3 zfWz|!pLZ+!b*R*X_r9gVwPKt@|MqKb1pYTFTn1mDvstOpT;%ImBJ`EKL_aq?3OH5j zzJ3TrT@O>hq=Y=oC_zv#=@6T<4tLoFbS1LTF;gfoYw`x)X_9 z-hcVB{yqJNB%p9sURrau5B>l4ULuWxKac*9tkGJWc;U@d@A06Em7)2MEkI@M*{sb~ zUspji^lp7My}O^zIm`=c69amb_t{OJEmyv(I$t&5vcHTDxGHY3Sd@LNc#)6$$us*E zbR^;TW@(n=y>|G5t8mmBXS_h0dPFpaKL4NaO|>W#zK9j`-&uqBJq6FJxxZp;I z1pbdITt33#hAV)NSnGj)zJNaqz6u1sSnGj)li@MQNZ4k`+(yV;h#Hp!AdnfumcG~U z$fUPi_9|b!_!If*6a8B|sk#0SYTnOA>HXsY#73@#k@Uk$9e|&(r5W&Oev` zw##E@&TJwFpHM6ww^U}4z5VRop%0kv5D$?1LRzoA`>S7JqZju>3=CzAbfnHDNylBlC6 zA4gh8a-?H`>!{QS{x3No+y8kg0{4L0x*~}`g`$FV0B@BG@=p)}7yrRF89x)un8*$h zP>Rof#?K6QJ%kuP%NU1g#?KnquVFe`z^54DI>{5+04g1G(BU`2@c%4PXKJ_cvlUu# z$oSbB`KqUlpKY+~`jPST7|EKLp}j;l$J6PEk*c4GWQ80B^)toi$;Qu2@+Gs3pJmCJ z>@a@TNTJBtQ1P{Zzh(TalQPLq#?R)G6^$@{wv_B>it)3RLD>R!~-F{8cDv!JVM#_TrFXk49G*)_GRuWLeI%j}L;6`ZVslCS;h zss22%t*5u6tJ5<&JTfveDKRo-1c5LWMSaw>qt~;=v#+ORTHBnKo>`t<(~WNoSKpxi z8{XPAC#Suqqqnc4rPC8nw)OP&c6Anaw6=BjwoUV#*Ey}N$Fr}!%`>aJr4@gSzl3^@ zV5GgTuRA#+V!?t1;Vl9yysKwM1lq!B^hV%HioDXQyfCnAWKHE0E=!lxiIBXfG)-#3 z-xhpo1*{ua!1qWU(hP(>`L6|lb>Z7=sSV$vanvCS2DTEgsrY{%{y#xHJsZ!oUWc80 z9ai#9pY^=%>4|tp54M{+K($l6EgbLT|4Wh*@o&n1;UMffDkFLG1g%~?#aq`0+AU~p z8`Qo9pJxHqCE?P^>$ncT?%T-LhYR`4K~Sh&NT?SSJ3xtZs=kwR--q{c?u&&y+VBa- zTJTm+X&yfFxA)+4A82rSW`(*E0kxd?J($kOU2{bampd$$C;WPEcv8NwSUe&Uh!ax5 zuvnpBAslRR#fp|e{mym!CPeKDzP`y75x0GZ^nGjYs7|#XM`RJtaXhtD+9*dyY8K4<{AYBg(b~*6k#+ zNH-HEt%241Mfw$XuwUAUY_E^tJs(D9@$c|*|BVdVoj9GoOZq|Dgs9fH(u0T!|41~_ zJ4B0U_UA+g8+ckeL(HXP#DZ8N5@C&Ximmjn^eIl$e;|D*eS#?S$A}1wCSwqHup{=^ zU3bKa&Izl27eoTxuv+#Yp2UlIOSfVA^2I3~e-c0faatjmgpg1YCLKV;ErLXnD4YO{ zA+e}e5RdyO5=j!l1q~#Xq+zznAeq=V$VO%IT#`rfNdXy8CXhl>M2blXDaBcya#BGm zNfoLN)R2j!mei4YGKn;hM#R6H$z(DGar~*I71amY$aFG;w4*M?O!zyq$sE#2y0FVI zm-LWc(nscz`D6iEi1QJP$r7@ZEJG!U6<7tYLgk1xWGz{T2*U01-q0SzH69`#k&nqIhzNd4J|mx# zFUXhVEAln@C;5haOTHuDlOIsE;V1Gl`4{;G^*nwfzmtEHKgfS@E#9BxFIN0CX4IToP)lk>ttkp=(NT0X9Ye=bJ8DlIs3RRmov1T)p{~@8x>FD8 zNxi5y^`XAhkNVR98c2g^Fb$!hG>nGR2pUPFXf%zXu{4gx(*&AGlV~zcp{X>D;uty2 zq**kZ=FnW4$1k&?KoFl(rd`QoPoWsH?dx8$6nM-n4(!QzO$uH$_?gR7%Xn?=fRlGhY4GV zTdo#KOQdDE$##XbTv~~93*So*(<)kxi=-yfT3RRJiYQu-3mh6~BToHDw23y;$#e>B zp;Kuq&K2wBdryX=AvfHoHS#&m?Lpx~~?ZzDqJ+znh(Rp+}T|gJ&2H?eX30+E; z(dBdnT}fBb)pQMAOV`o$bOYT;H_^>>3*Ab$(d~2x-HCfLZ=t*C9=ezAqy6+&x}Ofv z1N0z0L=Q`UNkjBDIw*Z1eMyhd+vy$jD7}*&qsQq9dXk=^chS4)J@j6BA3aUa(EI5F z^ejC`&r6Tc3-m$y5PcZ=kYCeB=%e&8`Z&EvpP*0Dr|8r48Tu@Jjy_K>(aZD-eF4{q zzeHcAuh3WNYxH&c27QyhMc=0H(0A#3^dIzn`T_lrendZ}pWrU!&*4A-BaAY}WTs(S zrekKzoLMkSX2q;=WXYC|Vx!p@HkR2jd*;9#ahHP=b7n5gmANr@=D|EsGr^nrFkj}! z{8<1CWI-&Lg|JW-hJx@BERsdBXw>D2WpON?C9p)6#FAMGOJ!*+on^30mc_DJ4$EbE zET0vy@oWMsWJRo)m9SD)#>!a*t7KKIn$@t0td`ZWdNzqQutwIzn%QJFg|)D$td&h; zZEQN5!P;2|o5^Oe*=!E$WL>PA&1F5Tm-VrEY(87S7P3WbF?QUxdxgEqUSqGbH`tr(E%r8hhrP?* zWB*|9vk%yZ>?8Iu`-FYUK4YJ=FW8stEA}<}C;Ntd%f4gZvme-x>?ig!ZlM2#{mOo0 zzq5a{KiGfRRrV+Qiw!Y7Q*i6IBokcU%TSD6gS((~vYBiyTj1tVE7@8`g>2MC94(JQ z)YVS5M=ak_9w$2?*T6+~mEB}_*+ce}y<~6MNA^YbpuZd-2g*TmupAFAmUH@2^>r)`=%erijP)vOsk zZEc;iTRNw8w4$8a4A#~;Lo>Upb4Ks~Ywt|ptEkTYe`d~2$eut#*cU+okz#g0ae*xC zi!3T?t6`6aVw$xYO*E^rzoHH|Ld!F+=&pGFrxie8?X3kqMH)@{VPt^M|wQo^2w*>^RA65 zoi}&h!o;a1G-n}mc6Ah6Ja=B{wAs^2ilc@U&zVykRWNOKX>rtqnbS&(qem9cnLM@F zy|ly~TM{+CWX7CgId*1=9J{b2s(AMNnZ>@zq>7rM^G#LxT1=b2umoy+i@6}xMdtpc z#lDhxls4Oxwx~odm^m+cp(-vjN(ZvExU5B)$tvel1JS5?bEeHO$b^}uoSaOXKGT+y+0S0@Z$q0eE884r+4Na9eU?q1Wz%Qb zdb4c3Sq=H~ZT6s+tQJ3>&v$FW!w6)ZGG9czHD1hwyh`I){|}P$+qR^ z*m84hc{#Sc99v$FEicEmKgX7vW6RC4<>uIOb8P!_Z27si{9Idpt}Q3mmXmAC$+hY8 zG7SBBmhL=DZ=TJcmus)vcJl5rCHy&gww-yl{5)HJo-IGmwlmMRGtag&&(_<|wv)HD z>GJy7`uf@W`q}dO+4B0?^7`5G`q}dO+4A~ZI{I5W`rGpR+w%L{^84HJ`&)YYTRQq% zI{Mr4``hyS+wuq4@(0-R2iWok*zyM0_6@N42if$4Z2Cbq{UDoukgb1^<>w&VjzP8^ zgKhf3HvM3GeQ?8d%b&rv-odusd`oY>&7W_}&$sytY*=X9S7_T;WXmfu{LalV*K@5t z=Vq94bFE(IW|(&6W*9nhGfX|X8K(T)4Aais3{x&2T+{uWn_=3Un_=3Un_>8zn_>8z zo2l!~!WE*@6YBO6>i#6u?I6_j5$bjj>UI$7b`a`z5bAai>UIzgPShTdg;VA+08E~p z_`@=c?Sg67;Dwns)zq0~%j}mEJ9lB39x@jAW|u4|j-Eelp|YKYWeeu%q?xw*%uLg) z%*?#lX?R}d6qin$8ar?9v}wvQG&7-eCPR#gFN~jFa!o@#VIdXIwHM;1%)?Iiojtc~ zPONSf&07@DcrvHBc#0abRFy@AMVeDZMMavEgat8+r!AP*mzE~YE?zK$5l+>~Xp=gn zWWkiOIn!rPTXbY-YI5$#AeA&((SIaK%O+JWV3a7G7Cor%!Z}msM-MhZz6lCUP-uc8 z6AUrIP!kL@!Eh6dFu_O@j55J!6O1vzSQA`if^jAoZ-NOXm}r8FO>l_`E;Yd<6I`Z) zSi=??9z##)Q!%C2!YIzf=^io3rq3%|U}N-*Nw=_Mkx8dJ$V7EFnS^soY=MS#M+W&8 zx}viAEp$C)^J8r_W%FZ9Eh?fbA&stsG`0$2wgwWJ3WzXkS-6l{O6-D?xifT+#ZE0= zSW-N1QAu(96daGU@yeB!Oi5{otB#*NZF*@!(-W;4B|%+RbCjqVeT!$8YR)K$Ya$no z)J&OKq7udGnT3w&DTRtfjnn%PdOu6;qjfwhS|4N?#vBo`L@iBWV()sub}UgxxS0ku9#h7Lw{&a zC{@NL6+{=%!NsM%nRKylg4&g`iyL&Lx8sVBL|Y6plh_u;CX61Wi;6BbB@UW51L>R9 zqS%D-`Hg)ZKcz9QYtFQ0IWuE0EhuJY96ePBEedTNxR}+1Il9o)F--??h0I%xEsC3V zB-*0T);!IG(S@eOX*!4>(pY!=jK;WWN0u38GP5!hhBPrd2{W1;#1C!E6+g2v9z9G; zYIKPXS`4!-$N1`&4>K( zQeDD=CI`{uOx+7iFy7=^sDt?Nja-Uf*cjIxo0Vzi0a=-59*~u3<^frmW*(54XXa;_ zdD+nuOyQ*_m}ok+%yjBROJSL%aH65GOb1aDm2O0pseR(art~G2H9cxE(RO~B3F9wm zY;F9tP2zkBzG1+O|50N+`Z7cJVjaX?c0_dI79WYW7*wdQwkV!vxHD$q?BazpO?+OH zxKVgB$`qE)G~xA)q=#V}*SU2(Wl&>t>_yEW9Zwq6uzu8s#(L;za-$*9$BFq< zrcGtYDAq^ug-t3m&DZBs3XiEQsqm-@;)gZKH>^n`haH=5*wOh$H?}!`Op`LkG$~`u zF=fP$Y0Q)~=IHV!HYsCblQJeAQ%2Inqw`H_Oq*bhs$qz+s5+it?Wwtt-)La~*wZP=kZOF>d2Q8bL zQhg?+i3v4%jqNmft>v^AniOh{roNEeXfgG1N)v;rPqb`mDNR|%LYk{h?W4WgNL#G3 zisr1biY8A}n`o~#=1H*D&s;F3PsdvwW%$fxWAAjlWm9WsuQrw%Z)}`CpVGv_=@W_L zk5ZrUjoDgGXks-@p~kG4xG`!vo?uOyz0k<*IBm`J=~hP>Gn=i6Sfn&DVESrG6U(Jf zBuzS6;*AB{0#q;ME zyQ9k7(Pa#Hx(+#R<~%t82bHZx=FcoiP>CCgPPP{sj^p$U)-=uf!}LK6HR(vKYM73t zS*KS+R(&#RmTE+cd8T?j!etN6cjuN#rpO6RiAp{udxFiQi%GB-^+BBWrs=3IFvl!) zGji-wJI5}ubL=HZ24yieINu6Vt(m7@coxvyAO}S=m%CU7N*daM5)4C2a zt?MAux;!$i%frsiao@4XpSl2|3O`mJe z=i2kR4d<5@JA+? zQ!-ag+!o@OojWyl+M+4AK@oYyt)ju!;gMNnTAyVcESZIdDniYj%tGU!Ake z`873!)&XN3DLK~Rk&|n=l54r%&mQ-)+~{Yi?`Ns+XSv$Xa$!J2XwMI_j+;T&Q8vhO ze~|6Pd|Q6LEkED(V!pjzV6R(;ZjN>6<`mdoDX?@D*xo6y?JKbDE3ow!*!C3Ib`;p& zDzJ1G*mf1zdJAnk3T-`www^*;Pob@+(AHCE=`OVO6xwo2nP7uouYY<)$xKI3l5$SE@A=UQ#ewOW>Iv@EmGIQ|HYToew{^>D1~ zA=LE{>Usz@orIcBLR~MRu9r~LNvP>0)N~T+b`WYh2{oOWg@bi}659F)+xiFF`i*0e z>$d*Ew*JAke&cB5x~+e(t$(nszd;|2!;y5h{=v3>BX607M&1Z*{l+oLv86xX)}L?d zH;ziKTl({D{rR^3d|Q9Mr9a=&pKt3o@|;;{got}bs0IP8wsttn&zNZ_WA&uet4+I9`lY~k4E>u>4kZ|N}NMLXj5qW=&f#mvbha!!`Bnl}{v%j+xND zbf<8xze1&Ve#@QhE4Yh2lRLXr@^kL3X7L`fANZE|e(c-GN61f)DvFvN^^2$nqi>16 zBYH*j#uj-k-fyulCMKp^OrMx@VhUnL$6Ok7OU%PDPsY3-^KnclHaa#T_T#t<2DDE%uZR2~ykBz@9et!Ia#NQMDWPEx23-O`&+W5aE^iCL?a81I439lqn zCdMVsPP`@YvBY>zerixvPa9YEw5>LU&|G(=C@kh>iyL8)UK&LQv0N4rS?xfKXq#A+|)&> z52QYx`bz3Yshd(GX>MAtw9#p$X%Dr&t@Y>WGt;-W8QEr4+l;o$+OBN7rtQwQpSMeB z*SFo+b_?3w*Y1UOmF?a3z1oj%U)p|g`z7sv-2Sc(ojVNda9M{%9Ukbgvcvigkq&?9 z=GE-xsxAk+rgUxJbzs*YbY0SQS=V>Et~sskX+@`%p0@0?wWrmd z_P1`GyY=ceyxW9sKj?N_w-wzscB}7xdiT-Yujqbt_eG~qK4WB$ydDF44DKQ&xreXm1jwm)-u@6Nq@^*+D%RlRTN{aEkXv(nDW zJL`(GZs{|-PyP3<`ra*l)B1MqJGAfgzW4O~?b$QW{*SYlpZy%qMvl&SFf%SQEpt<5 zC@U!|BkSU<>$C38UX;Bx`%gJ;PM@5joT)ii=alB$nDcPXTRFkpq}-*st8(ATU6Z>u zw>I~0d2{pb%6l&F{k-*gf9jXsuUEfU`fcv_m;P7upWOep{+|y>8}Q=+j}3Tbz&isz z9bIvR0Y&^H~xdYGr@wtzkdvIXFz_|lU2l~(Rop;T7_njYo{^{pG zaQ?~*dR$O&!3!5`ys+rPsTXd#@X(;?gKiu2`QWs{KOX#8etLdR{_y+>`B&$c=Kn|j zefdx3ugqVQzcGJb{-J`ng0zC(1vv#57c44xq~QI6gN1Di&o7)=cz5ATh1-i_iux8^ zT6AO4<3;O>HWzIlGJnY3L%R+=f9Tqw2Zs$D_JiR=hd(*Ie8hqg*N@mfqH4s!k!d40 zjXHf)(Wsed-Xxw@Y}mK-y7FY=Y2Mr7VlONvc{{`dyxZz|Z?9PCt>YQ6mSVN{K2I*C zie27nQRA&~&h{SVEzcM6u9EAVb2%R9ZR6i?wazfF%o)M)cyEj|!Mn>@<{fsP1kZTy zIptoB^Q>3lJV)AZ!@8+TJu)k&mqC}}^GPx9V`Bdg)WO0n1bBV2gd@p;cVZM^kP2k(72vXmND!-XpT zm;aG75=`(ubS6U4BVG_r_~AsrSd|5u`th;Mv38yUr%K4o66J4zJ4G45xn& zE$@k0^)HFVUN7>F;tT0_i=TMEf?F%ZE8dM_l{Z7Y>HUQArop{O#Ctqd`@XkOeBk|n z@_)lKp~-NxO8C8{)Kx0>c}w8#bK+0l4ZLw=iTIoMBmQZ61Khp|Za)aOw>mw&o1HU> ze~+HqW9benC$>?TkfE$BSfopqxS^#exT?@0%Ga4G@iU|3C+8Cf;N@2D=A|OWo)60EtIiE zr%EPO0;%?sDv4AdlB$|ifg}Cj7T#1 z_OSO9EvSIL525cvxbPudtb>bna4`%QgS6-%QalOzp4Yjnkf20z9U#|!a)rnh;wkDH zwAcstJCOHm!r_D?;oSsp15a76re#4&s`1LX8scn7m5#pGU}2_v>VGDtk6LL8)%iE{ z`QydnYMn}=eQ{fZ5Iq>l=G3)QIi^cUfh@1FW-)-Jm^xg<~TTIU-i&gbO zdaR3ht9~yu7K!)j4~X~c|IRx&x1ew1(6=b$>ksJLFcGY;N8eH@eJ1*rgubPsZ+yDa zOM)jYY5hR>vK)PDjlK;;-;&_b)#%$WL@)_GWsd0R-*xl=t6?l1@r(L@jBXm5N!{k?FW>$ zV{MrgU>~2w608K9phlIjS?lwY)VPascG2=0?*n9UFLJnt`rctI-^CcdQS0dl?BRGu z;0f62SW>@D>Q6}ZF{uJb=MGY?W3&&EYALDKon)#Q%KCt^c2M&HYTi$oJ1DQ(T8Et{ zH7f6-Pinliwmm`G5}+*yXp5h=tcAXfSZHQ7%u!M`T?3fi41_+u0#523q~1>I9m>x0 zACiCfs1YUFQO_|E9_b~EP;(yAJI=4{X(IUB%; zHH;n_0ZdN?PEu-4P6AzcVP>BywhL}lp;cyNJBYj;vLjI#83{8tuHlRiZ8=+yONY^q zAR5sI4J8-yQ-kJwL5XK0Sp&cXrAcbs!Tz>EavuT9;N+8p%k^AVjZ<%VPl>k~^WQ^f zgWi**-0gHgSBEnv9|=xQXUmVW2S<;~4XulazftbljIaZ=+(#IHg3KRlv_9|V>>k>@ zhn}tRUV+k2p#L+{kL3z)9Vg#NByoZ_@+4B6Xao(y%~MfF^JRSfqsht7W=?J%d*ZR@ ztGWE`pP@8r*Qs6eo!ZhGTiLLNZ@QjujK`w=wP=4W+OJlawam@mV1*fCh4~(H^v$d= zUuPx$ETi*t%rM;}R-y&5FgYURc-7{3ku;x@Vi^CP`0KZ4 z-_`i<@VI@))qe+9zihFN@0a}7&o)2L{-&fjm3H>)FUxrRzP$hDdDTwrGy67PZS>|f zA2Z&)lb`#3TT-5Q_I={3U%!n%v6Ow+o)h!u%cI9Xcjn}*Xm9HJ{?-Mv-q`Pk;S= z(D)45SM^47Pn|U18_lOUwKKcs>uWy6$w|=3J@55@XMFtTY1F^}o`3VQ^v&Z+P zXXYpNnw)$&$G0=z{`;QI%R%!g{vGSwQ)^pK-E%1alVjbtU)qkZMa@fC^C?c{$oFMW z-2a`i@ZUf3oY*g_Y`l4@_vCH!S3j3>V(V|7mTIiA@#%^a=R3I-#~YYfp0$ z-zfWyv9GIlPflk~evCQ!lwUm>ow`}*iLLMdwtBuUnfa#a*LUqX@wogQf4<|-iT`W- z9e=*#&%g3t^>3H_G&djn-+sOM8GZ99PW8O;yYi0r28WZMO@Gt*ck+}peFov%wrc;b zz5nWa5Kg>eJGFN^nzwS_`Lj>mJ2#9s>DzyArqTQTb*;A>J-#RR59)6}kH2m`Z{8Ao z^DMiQ`G9)!8}Gqr%eO8clxz4-`E$NQyz3&5w?tHcb^L#|FW}g{4?F-K^ft>O-ezAM z*IV=5%rw57*@`b`raNhTBe#o4cYiBdxsMY*Dbi(2&=qtClSC_dIru)flH*d5Ca))~ z7wI%3-RFXye9iMCk>sU|6wuwfSoEp?6JO{|<6FnuMIryLF9JirFmMqV4=&;Vv6u3u zn#;kx9N!QAi*rwt{~7QC$1id1ZNhiJyIiZF%ypoa<9hy88{=KFK>co>x6kbd`hx-B953je3kFjDd6aWL;RS>j5)LBFCl9=G zX|oHT+!0_D7z5y$3(wq%;1VziTn@euX4U`6y@~Ku`S{t`S2eg%FF zegmHHf-=FoSf+u~z5TM6w@*Tg?8Eu9iDwYcBw_OhB{75hwj3F)U zlJudx3Y3uUYSPT-Tp7pL5MBpvAbtziZspo-gtrsk$@!mxyTAkBLGTdZonUe)SO%Wp zcsc2xCjAP+X9&v)pCx>b@Oi?Oguf?zf$&Abmk3`be1-5;!q*7@K)8yKw|B`m2;U@p zi|}p2)ztAG_yBweD!?aT9oPW2fX~1-umkJ@d%#{00M%eWH~_+cw4y5WNnf*FkhLh)xF4$sjrzL??sjWDuPU zqLV>%GKfwF(a9h>8AK<8=wuL`3Zg4P^hD`MP!@|6IT=tV`k{0qh;9VYgCKekL=S@K zfRgzjG8sfBgUDnMnG7P6L1Z$BOa_t3Aaci-8o_=LhEC@!Ga~d9m-6l2<<7f&5%xw| z>bp9sAZmNeqPX+pQxc*RKT51m%1By~a$n21mX)dXX)Dv)r*CX?S(}&IE^ZrX=eFz9 z{>F~4b=={keT z5yD=CuoofhMF@Kl!d`^17kpKd(xVwAZ)23ajnU{fMx)ypjc#K!;v8BMLQ6tuNeC?o zp(P=-B!rfP(2@{Z5<*KtXh{ey385t+v?PRM|pa={F7Xw=DUIwlJH-aVL7VtbRO#z)iJ|K^r1+E2)!TsRBz<-0y zU@NEu+X3y7y8&&Heh>uvKnNU!CPlR$s{K&yhiX4m`=Qzo)qbesv4MG774x(z@hR`Bit(zLPgOCWs$xD>#eAxY`BWA2 zsVe4ERg5JYnD=lMT#6su)u?$kV*_j4KS7+k{=+gk9Z)UEPFT-NamZ8*}At%$2t> zSKfwo+J$x6#VAq9C{f8MQOPJ#$tY3DC{f8MQOPJ#$tY3DC{f8MQOPJ#$tY3DC{gJy zq8@bIy&hn_u-luk+ncc4o0t=CV@|w{Iq^2;#M_t?Z(~lp4NJI-(WO%MK*xJAYwGQ7 z!ZPk+KD-S(zlr(qHb$OGIfCmWIUYqgn&UB~p)HcWke2}Z0V}#o&Llpc^FJgk|-%0pWa2NOm*Rhq1A)6SrDj7#MVQqKGrC=HOE!Upl{A%zX_yBweD!?aT9oPW2 zknc0F4eS8Bz#gy{1h`%e_Jac)hY4$-rw$wjUw}V@zk z^jHl&wwfMWO;6R(ORMRf8hT|l++Pa!m%{y}aDOS>Ukayd;B*a~u7T4vaC$YIUJb`; z;8+bDtAS%RaI6N7)xfdUaH|Gxt%h4QaH|F`t%gIZ;m~S0v=k04g+oi>&T6=_8ZNAc z3#;M6YAC9Kq8ccwfub5Hs)3>!D5`;?)ljq=idO4+YXEr+Addm$F@QV13m|s^Ye+TIA0R0`HzXSAlfc_59-vRnNKz|36Hu7%KSa9qb=_33lYMpc` z|LnXRG+i&f#PP9frc~bi+nRSBe)ZZZfwfZtYo`R(P6@1?65!OA*G~8ku=D${^ZT&# z`>^x)Kt#NIF8C+cRoL-;*ztYXaeNpe9POZJ5TV4f< zMFMNE1lC{)a6c%^IM=WayMcJqwb%ocq1Iy$5kA7TrC=F2nf2Kg@_YuifgNBM*aP;0 zrfatY9J79to{0B3K)t6qL0ra){0dO*9dMU}6`-8e^;ob3+zlT04)_v5YtpG4wdANJ zM=d#O$x%y=T5{Bqqm~@C4#KqH2n}-dBe&#Rh@KLPCN3ovy<{_~K$}5@I1UO$! zy8VP9a1ew+1k{1U;B)Y2@K@e>D?l1=$!*PyyD#(BOpa*>^OtqZU)Evg)?nw>VCU9g z=hk57*66uwhPMvR_~DG-T||5_xE|a9?(^2;BUz7+WWAo(K0z8aw^j36Gp9YI=d?Y% zb#T!y&!q>4Fn1jamqu`I6d1$#u~=qkXAZFro9Neb->V3Vy*1dyHQ2>9%qi9}pIC># zWh318<8#?S5BQlIt6m5*FFr(nhnZ8XV@|P7{*t;L;rgS5O9_8P$UFDtul2lQ9dl^a zQ(-kPrnmfhZtM`M`7x^(#{PAT{p;}MtY^NgdNJ%vVos0(QaPW-xz?QPO1v959jN(q zCwg}ky{LLHOb>?Xy;bzyDmWj8^Q++cDmWU3qhUC>3J$JkRh7)0A zEey3`C=EkR7)ruWp~kT=@)f3~VOqF~u`CZ+;T^}wR4pnDVOzZ(4}m+y~7>I_4C1nU@+$j0G>V8w?X$}a4EP9Tmfzb zOTaDQK5r+zw3A-iNiXf7mv*q`#hZ<14errnJ7gMhyngiD4ti~eq%PLNLDs@SdT%Ga zwnO6eV_h7i_ja;24ze~5(u+IfEu6<2!#X+0IyuNXIjFVeG15KB`KQ2gumY5W=fFzv z0(c3$0$u~Fz#HH#u$eNp0wj-hc93;;kac#Db#{<-c93;;kac#Db#{<-b`S~KfrRWp zLUte_JGI6o6DqB1NqB}x@$~>b>HqH`4K+x^A!|n?^n8u@gtwNiBUH9>Gx05~&CpeP zw1(cSaYlKE>4gZ~tbv;~aI*$(M&M=y4o2Wy1esTMD}v0|!L=G~udd{{l=IgUDx0J1 z%`dtBDEJjn_Jl8+KtTiwB2W;4f*Nf*l&v_!J4~x1d>NoSZ<#RK>gTP;NyxGv`AtT4 zleNZv!a1$Agqy(@M#oCtpL&4nhmdQJH>1XYG;PVX79*oc$YV0{n2bCoBag|*V>0rX zj65bou^+ihM(&c4yX0duURiBFa+C}Q{K!x;T=2`&L=s%UYBTzi*JwZIuH;+^$EAeV zgPS;a3&*#CpAr8h=^q8Z0>Ae5%E#!}-*Ns)@Dyp5gB740JO@^S7r;y474RBZ1>OK} zfqHG7m1XuDt09t*i@m;NZ8i2H7g!F?odJ4?WVq}Xec|vP4FC0;K8>*0ty~xF0Y5t=>(mt7vtVZS{Uy&D}oU&`nxety;XB7VoCTyJ=xV z>vq#R)hgvRsye1sRkW&#R_&)HyJ<-kEvcd3|PaV8bI;XoAQD7{ZOMT2T!ptVZ%qGH&S`kL92(yMTvxYDphcF{mgwa3D z=pSZuiZI%T8I>Z8^kGK&Fe82VD39}DM*72y^oJSY4>ONCp2ztxqy1q<_`{6whZ)@u z%S*vk;AoHYVMhAHjP!>Y=?^o~A7-RK%t(Kjk^V62oI}iF9%KHS3|cZ1jAKrDm^r1Y zSN%KkF!Q&=%-;?(e^X^2X8v@T`O{%Bfz{E`z6$POYJbJOoL4>y<)3KqO*Hr=)E(xp z@Jk%m2a$@oe-lm^+>k@pJkkk#%RHfI_%i&dR%-m3KKS?{e*<98cJ|_AH0X<#4%N zsI})iga^E5Sc#X5df@Q|BJE?;>(6pl<>gK;pgdOP<*drfxp$Yy`ZJOBXCmv*MAn~) z+^>&tzdpkK`Uv;yBiyf#aKApn{rU(!RL&~CoK<`|tN3zO@#XIEe2@)m)APu40T=}G zNefM^_RCrAm$TY0XSH9>YQNmQ2tb=V5nKW$fy=@7K~sODS*Mn>PQ{t(wSMHIcPyBKOoItXIqJdbJ#nLAg}x)mu4#JGhhMpMtx9@gbHQ zA0lZQ*RADPxo70lq<;oH3!VqR2QPw`!K>g8;C1jOcpI#y%=f?t;6uQDV!ROLcp=L1 zLXxi1;h(fjmQ3Qs7 zVPHJC7u*kC0B?hLzyY3!sU)ayD_~_EkVzgpkGVmc#a<+d1sG#EsuV3rdsmkjBw+-!F!STdFzXr{dM9Ax0c?=d>gBk$Bf6j!#m`?>fOW$p5Q&< zE#oUh|Im+_Ez`M}yi@SZT$5`@5)ol#eaz3+xsPXh z)b;(|J`dg*MuQSIm#+5A~1d6~5wkyer;j@7I*6d2IQ598M~3cyAod zWA8dujrY2@roNo;hxG^WI129~&-7#JS2RK(DaoYUVy=H#X1r^>UG=YdJR8tZ0KFgr?v#b<(6E($d?7hZAp=KD+^ID_<74jqW3*@#jEx{q8}pOi{85`?a@EoH%Uz; zP077?JD}H)EPi+^?9cY0mR@vUT~pHA@JloibEV;=3h^2X+VQICV=aTam0U8d{SDGL zhcrm1cc=Fd`+FOBgg3K*g*?yxym>lDFJy)W;lJEKH_SpuhUn|atfV7G25BO+-#0BlUdn3=V89Xy1;qVc~mTPe(U^BlsZp3 zPl{`Jvhrzht@8}uXZ(?~kuNhXc6K^D#dXeZXOFnv%>J6JsJ7PtlC1-Hm85-++#-J#+ocep!TyzGu-UGa+h1NSQNjyu_%EZ%dc zx>Lpb?sRv$_`sd%&J=6hS?(>@9mcF|v>B9AY?&prXz2zSag(LCgBx#^^8rTZ#}uz8$B}G*$V9}6z$N?Ayzv(Y3=N+wX>Vn&hBXE z73iqZ&gFRCd!dUji9TrJYus0Oi>)vEw^p1j*0W`bPua4>AJNEct&w?X(lSFK0U7W z=?Se*PilR7O6${dtxr#DeOjUQ=^3q0(lF6pWe{=^rqIQx3oUJt@Y_0 ztxv19KE12;={>Da?`wVfKQ^r>8YsC8(g)}gIRhXnt=ki7-}zraJpQ^hhv98fwW z4k{f&=g=YX7o|hu@95AtM{4bf)7q1uwI@+)PmrF4M zH@&sq^woNkq4g$H>rH>HH|J=*nWFV(s@9tYT5lF=y(!gtQ>OLiI;}U?YrVNa>&=Z? zZ5KKqffKU*U5Ie@ayF?XDh z&}8IuAmdv;TPovOfoQEgPH9?m()GC32F)3(o(pGd%a}8cG-`}%ueGQhT6CG{z{qns z`gR3dN3Bt<8R?c|6;`lGtyk@|UbWGB)mrOS7p+&W)~h7+N`2*b3tKC#U9Q$HS8G=n ztzBKTcExDz>Y%l&wbrh#XxE=bS2XM|v`vkDUA2yNMY~e*f~7fW_(@wc0=7fbdWzOg zFQ=Di;hgE5DPpwN#cHjK)mj&$N5f9e3}=SutjEMo&MfqhXJFC8&RP$BS`VexL&iK; zifA{%O%Oge(M=IiZcDedaNTsby^wAPw=xeiJAwE_#^Q8r z#}8=#mF|_a?JCA)SKAR++YwjW5m(z0SKE;UZAW6Y9f{L+Bu?9rIBiGbup`$}!XkGO zrTxhL5%I3nJA)Ul1vt^0E6i+lZF3t!zh{_OiW*l^tY9;+qiteaZ4=vRo7fhcm`(XPSjHAu#(t#lFZ<&k9U#x4mUHE~{7dmXc^)k}U!G5z z3$UJ1SkJ+v%*TdGY-l017s(>wlSAYX+AvfO<(}*?IZUL=;aJ#oEbK`9v!moF(OQm{ zqxtXK7(Ddtu<3tQr_)^YKl9TXWGm~M@OosiH{8utrUL~*MYO$Ow zI$@Wmv!5Yn(2|*Qrf4ItmRD2bEIEr-G25Y?%yuZbRF>lPFOy~DWzIu8ufvzjzb^UT zWwN{h-+w!Kqr8!FZqj$1m&hfw>SlQ}XKt0ZQs(XQcJ_D3J1Fx`c_(H5RNlq@XZp_c z-STeI-!Jc{-Us9ZP|Dni{loHM==~*ku3O1RcjXlif-#lgo(z zPO3ZEkITm?=V|#gbv+}WVgIarmi_bcdG^1Tzi0oVe3AXj@@4j~%2(O{LH>dL>+*H> zZ^}2>zb)Tp|Bifz)~?1Yo-W^&?-G9x?|8a=U%pTL1H9zva*bR={6oCu>GC7_5%CJV z=IQcd`7!ZN@Sdm3wQ?=-b$HR!<$AfE_y)Y`>2jlF2Bk(d_M7EqXx}2YK=oF+mH21! zGvbx9lK3{cjrexCo%jy9gZNIlllU&Vi}-H2oA@5Nhj^8&BEDDdCC=QEJ#$N>k+~)N zdj2DuEIsadwDU29aZldiIlp#3m;cNr`y|i%wNoRgh*cw~aMcJZq8ULGxPzbQOB5X# zM_Y*&zEoeTi1DTAyZfzutvSz(RJ37aZ7;g`I`}$}hIuLFFfXMX=B4bJmomCJ!sqKP zTCkQgzs6W9BidJbzZ#P3P=_ewJaSzfE3{+$jb?m}W$a4gzl}|Q?KxLbYH0+M2-b z743?;roTAyGfcxZ^D|y7hq;OR;dwmHPnDVu6yJP$ug0T`FG#B~8Ub%JxQM5B?)mDZVxQlnI(3GUTvq`$A z6knAMivh;Y#S=f;s+pcivE`9a|4dm?aJUt6q3o5h`n)+pA1T|fer+jNak&AC+e+Wf zPlau@R5kKjm8E{lei_SUEQ-ph?g%Jr*&vH5U4zWEw%61dBQHi;R2hmsfgM(!6@z5# zt4gQJV~&emZ7B0(!-jglI@FaOk=LfO+Zb=up@!Br$f@ZW)fbI0vZ~~@>8R9J%ekUN zQPq?((}JV-hBu0KMRn7ANp0-tl_TC2PC?Pg3GhvMjCuS(kKPWoO3p-~OD(t-OTF^!xb#N|hnA?lk|Rg=GXJ@tt?flO?KeAzx2X(g zZGV}VEUp#{NTbqSWlC_<&9U3nhTV=i?re`c+OXlcA$^`bUtq%`)_uc8CBEigI*;IM zUh4eHS?2uOdCd8Z@;N(?J5S(seoFbAofY_;%bjPP=bY!AmCo<~nLIMyeZl=bc#-WT z_ht7L_f_{b_YdwW_jUIT_f7XL_igtbceVSj`=0y0`+>X0{m}i$t#ChfKXKQ(>)iGK zTrSzd-N3ey?Nhc*Y=30i!nT#|Gqy^$ZEV}wcChVa+r_qrt%_|go1ZPf7G$e-_p$9~ z3$YzwJIEGhi?G$O)w0#G9b!Ao_Bq=ZY=2_=GuvO-{>t_@_ir9Qx1P;&J&DLjhfTRN z)K5*(qu8R^TF4l-ShhGB=l-5v+zw)Z&-n#1I0CH4o3-9Kz`3=~9eUqI?|;p;wOrfm zY$5h8v8~Q$#CT>2U&?N0m$S#Iat=CSC*ssNwN9OLh^uemnF%?29lsNBf=;!w&)Lt} zxwa0MJ15fl-1)-!g0qSEe+MG3`FNk&i(A=p#O-Xk491SggP=mu9}meSah-bwcN2bw z*W!Bd5I%>Wi{HAaXzWv+Zu6s9|Fu(JJC~@8U_3d&k^+h}(?k(_uXJX&zW+x}p zU_$6tyk*3w@guXQADFR|5by4U*tHuqH9N45KRZiE&@5b!Ny{2DKKfqI1BCdm#4~5c zjGUZB?1%^2yMpUZV=|_vJ#<}gmykvkgic#JHg)9a-_jfMd+XzR^RYPLu-EQK)cc{{ zVC?wp9JlmYuc7`YA%=DtnWILIdYfHFdk4{e@c5BASxOuB4A*mTf8d0X<5PEq-8K=r zD+&GImX$dfO-ju=*6;OL+}Z`t#1f7hlwlF`J{s=Y`ZrS74krk? z_{6OV-(U0mu+eiT^QZQab}6XZ6UNWthiB|k%%5Ug^xR1uY8NNoWVt4`vVot$b_?+) z!-=l?x(mT8XeE(Qm*fRB5?6?ByAC~~0hYb=2}$G4XiX9FEn!u?NZ??c4CF8GoS8WW zJLf8Mbsth#<3K`pB=Qzp>5RB5kTCj`-;4KR&kO5L=E%R3*X2x-t^0{gkROo2bO_02 zbID4!lDJE$#7|yGy3wViFY8L0(jQ5&6h-{y{bUKAIfIgpG76<5%085>C_PX{qa;%k z*-p!Gj}OkxB%9<=GD|8XJ@q}w7`ciB%D<6wx*)Pp*N&W%^HB0ppH9~6O2|1DLB5d3 zkRH1FIG;eyDUWgOFiHxUCI5>3C^Ade0e$$G442;~QMzHISbj_b^%10{e4o4`-y%Ws z6*8RuOm<7*BnEpT^&>r`Y(m)^WT@N&eaI&H=+j8-Gvxp>gzX~ju z>5@X$$Zbh~>2)#{a7=@pR!V0{ zhW-uWCdZJW9B=Yja$Gi&Ey_iVOEJc8CFugV2g`HFF5N;>mtG+y@<383M-m_AM(XLd zlX4ETemdSWnhXOzidjL`CEX^nLY_ee>m~#DCo$GHs#bD5N?By5)PXFOMv@iu2a*ri z4}f+DOS1rrjx1(t$O%HspnUUALMo47KOTGV81tJZBokdkA4o8lYzrZ@&=9z2k<)XS{^tl`GMd-f3{Ni;K z=^GNG`w;zKje2`BK}jZilyPK-&Vhs|4EJ?G=}fYedDtg`)~8f`kNO1VGtxl0i)W@( zJ>l=s*CPj&&7kGZRsYq8k(;_-f%A_*%PmM6 zLC@#OROKlN(Y-?abUn!-IgM<^zC>{#jpP$me~NdsAceZ!;1{3?-8S-;{0dnr=aNaH ztRnTKu9zR2NO$E`l-ndz=}lsFVWbIYB1L9oqW%nNuVj%}{RiMhd1SNv3t1-D0X>$G zAe}Gfau>2*_5}BD#HFNV5B@-y192FHb9z@MPtr&~;n$^vp6^EHxYfcNq; z5@kH;%0`pH>`j#3!0{OH==r1{+f3F=y8wR>IitS@el?P0prlHhNn7yM9?~%I4Dc0Y z1vx1bp>rpjls#lNcw~mYKN+uFB4g#9WR$KwIShQiDz7Db z@p$$L&QBq8q%<-S{a!1LAa8-U86`qy%d1E)v~>piV(C}Nwgl2z zK1b%GK32eWfMg1O$mK3%DdbfLUI1$lmtU-ecnX=w<>EgSE+>VI@NeCuS33hV}C_iN4}7bfuBGR;j)eEB3vK9*p}iRzCVZke7=__%O<{cR6j2K=HxXW37$-Y*jR4RnnEb#I}euxeVe>?=qZA9Fq)|JOa& zpSTXgX+(@$wH}4zL0q4*-gBLT>ku06m)BQ46ot=0KA-=s@Hx)sw^ae|FM+wr+>N+q!7H#HuaPF6S%OMevxam1uiobzj_gf2?@UHqLjn!g-HY zZ2HIfkXAT9vMwAi8h^5eq54?xD-MswuQ<;_vAc-(VBY9R)icG3xUtocIaA3ix^`8Y zbiGLuORF-9c?Er1%nyu{rbBa@eOY(rG$MEa^kmLA#4*>Qpf`!RVbPazg$`($+l3hS zNVIbb*K;}j^1Z_KBt9RZr*ZnkocTh$uUc>CZF60yrf>W{+|TEQ=o99m;8R?u<2pU( zalCI_f9E`c&vUNxSlSc1I;TmLX8fAamoPUl2M=M)_Hlik>r4C|jgDX5YjiE_9N0fn z9(2S>q&=VCT>kQY30=RMPw7&sdMgh}d%Xv2gX+F({Sx{o^u=l&NM|>U47Tr%`3+r= z>u(xQt8O!r{tT)*STFY`ieJ_(!xK21;2o~d~+=P$sE;4gfy@f5DxLnqU8GaYnH zt_Sil;5hl)9=fT_^+)KW3fCKfcY#~jHah6BTTUG@RD;5l`uTD2>7&Z4ebqX|PWeez-0k6nD}ll!j7IH&Ka*2oBeai>{W7 zeqz^*Hn8X2z;ofz!L%uLapGu&<3@)r(U6f(UFw$9yH*^-twq;E8yohGuj{qZxqVcJQdDg;cWTwYqTzY)R+Il@e`-4 zH+%>!KR)*S?;n2+fIa>fRTq?jzhE&y9yBZ%e-xC$$s#JsSN#3s8|sHg)&7a6qd`;A z6oZI?iSn}iY919}TWYvcbD9R@XQ=@>_yq=9-6^QC=H3{v9xw zLg$o%pFOqr6>V6m*rLBaK$gI@1>?5cnj5PRIJPZ#)wWGBX)J#nqfRwH?MXliQUnNr zVv^%@RHH`XB6?%F$%ocK?_mbQ{1K%-;WeW46244A>JwRs!-;RmT%wR+#F+$<*<>d< zNDh&6Piizb0By-yBONY}jbT*ws*VA3pNT1Lu=F1XTGCRZGWAC%C*{>3n zB*|WKl|rQD(n<;Tuw;}@O6R2arEAi4=`%T0j+Q&hiE@gZDNmOd%h%-3{KBP-1}%zMoj%}30;&4uQC^H%dBylqTX8o$G= zL!nijDxX*W0q;;b%He8HQ9hpEh_V*-&V+p5?R&?&r|&+zn|Sx;@i`1PraRaJLC3< z+Z}F4-H!O`vcoml;u{gi;BGMzgHz*2i>M^&RtZ z-*)W^%|i{54hF9mYl6}i$2>boS_mENa6(x2$h z^Z|WH=Fq$JPx=>qPG8VUYR3GWM^(%W<%IeHjE8tBgks9hK*z?Y!n;KQsJdtOV+U|Y$}_^a@b5Zi{7I@&_~RkZDgC+ zX10Y*X4z~yn?d%G{p>M(%1_uY>?!9b>@W75yKB{P#FOl4KVD^n^_Vv?97!KWyb zGIC7PNs6SG?7%@BBuB{!_PmSa3Xik1)JyUr*CcQ9vE(Dwk?KnIFnd2C*QNSWZ^@7R zNAf2(qyQ<9d@2Qz&&cQGrW7ps!aooqHIPE3FezMWC^aHqlCPu)sWCX)59B`iQHmr# zk)O!}L`@!&N8ol(q$cDSDO!plPo<{hSE-rQM~Wq?6i2G0c&WLRAhnhPY7#oX@E3PN|ur!^FqN5sPr7XB^=zP5si>4B{S5CNa;7}cWIC` zSo%S_4?)pHQl%;guo&q_=_hcZW;B+@(RkWi8X^sqewH3c!=&M|oop{XlpfIp+Cq9P zJ)tdWEBcD`7i~@3NPkFwN+YC^QVMNLUzHVEPutPgWF||}FVa(4mUXl}eO=0s#!C~V zOess6NITGu(y!7pX|c3~cA}l7rP4ClL3X5Fq~)@cv_e`*N7Gc#6@h1V`*FoUeA*2BbC1E6-G$f5k1ZhknNfc>9qT%IiN}7>a5=Y`mbCN(> zkd~wsd4;qlZAe@4DrrYvBkjrSqyy*hC&_=CnLZQFdyk-`U~cx8M9Bu%+q1kDa?*JFem27oS6$VFjwZr z+%XHiFb};UGkh@r>hc*#Cy-2%LPn7>;6_u(0y3VwN#~Hsu!>iaIhfbWNfupA*N{|_ zO&8H6bTN5{t{~}TIyr`!y@bpr@FLS?WCL9ZxiyZ=pp)o#;1)k4CW-mTM~RN38Ia3k z$zr;e`Lk7YD#k0DPT^xlGvU8|la8m8!Cjt$$NUPZ_8a}3{z0E{{sIX9;+%!5WI5Rm z={SMpk$l(^(;z2zkX$2)>}Is@l~hXU>f{r&YLRiFU#Yz`d{~r`Mg|6Ue6xd*j)*d{ zNF$91iZV)(ft`#}Xs13&A<2Qu1DC%sdU;@{z_BAo8|6^3$A#48$W|(>LR-Z8l|vaNxhSdb36DN+jU6x z4GIeEXguF5$#}klZ%}e_lu@baBl`N*n{_O`)khkYh$y3-F_TrYXjO zPBvxn&0M~z;F~}Pnr(X32}i^EW)9y(JKR58ooKgH&uKS;6$hJC#LWxrtl}G zm|R`>vwZWIZvtF!-*CQJ!#5xEO%>m~>Vlgy`R1H~H)O!M9ejgow#n6i3pj^2yW?sV z-+b(j3yFLa&8yL#*u2U&bFd-cFKOTeV<8RqLwo)VJkCoULA>Nv#1nCPFL@O)K*BgG zb^gZxA`z92peG0$+^O%nM;AoRaeC| z&UK~h4TEfGZAdZ9FccWB81A~+xh;2l;@-}Ej|cO}@Ob3e+%wJdu;-s%o?eT+D!l7^ z&-cFP6Xvtk=TV)wI-~2HsLSehtvkQ&#k#lZ`PUm!Z)v@!z9W1u)NfF~L;WXy{(fct z&7h|a2~Yy+2Mh_=9&j+=Y`~qs=7A#urv{n=F9tb4?~V!T8ZsC($j(5GSj!m`57hdYIL4d2s{HC);#uu)p0dl9`N${Ra1&T3p3DMvPs92>bh zvLy0OlzUW%sO+c{Q58}5qnrnjtU)uh#) zSCm&~z4D;-kk*G=KWWph&E~dB+qrGeyh>i}@~Y|8N9|(TWwa}Q&F-}kukC5?(0*(C z2d^i+e&Y3SJH&M;>FC|DPsfsu4>~pPw6IfIr*AvwbS~@sdzU6%a=Ki7BlwN9H?DSV z(RFnpdEHqj|@P~!ex-n|z0de(bb@1Oci>RZ3>t$w}w znfg8J->QGf0Pg|!1|Cdmo%C69!{n*S2a_)+KOf{WD0p!F!7B$p8q#6Ni6Qrg))|^H z^!%`T!)6ToY5?&g7IbJ zuaAE+!EQqR32_s;Pna~plxfI}%xsa_CCeo%EURr+pRBxzY~t!k^(Sqg+3l1)n7p5<~v4|{cy(oRr*~Kjuk6pZT@lQ*)znpISKV3NX?4!(vuhfxS-a-)+SzNLuN%Ft zWW8a19sC8ZU%dXohJG8iZnWE2Z)4=fwi|nGOxrkXzo}%?sZAel`exI!&C2FFntgZ96 zZrob5^~BbzTW@WBw2f?Y-_~$jt8Lx44cnHrZT_~6+jed{xb5t=ifwncJ=?Bqud_X3 zd+Y68wh!8#v3>6L_1pJsFW-J;`&TW$0F1Jtau-x?AS-Goox91k+ zp2@wQdnfm4o}A~M7o685uU%fBys>#R@>b>*41>Y1r+d+0X z?eO0bv!nfveml~4%-XSf$Icz59T#_ew&VVe=R2Kt`tNM9v(L`4J7?@%xwBxWap%RI zU+#RmQ{83Q6}&5MSC?Ibc4h3Ey=&vHqFpC;UEOtS*P}vK=vf$6*rKp!;fTUXg$oPU z78Vwk6<#j9S@=_70ZPsN@)d!Fr8_PXzFus3FJ`@Q}4rtQtyyL#`Qy~e#4 z_TJcgfA8}mry~ENh@$32?TdOA4Jt}2np8BqXme3PQBl$1qVl4%MVE`N6@6CpP0_ug zM@7FEsl`fh{o-cD9f}7Ok1d{2yuNsQabfZPVpH*z;#B}FBNOD>jt zSaPG}Udf;P$UeJ$hJAJRMeJ*~uhqWx`?~Jyvv1J8lzr*@CheQCZ{@y?`||cZ*!OH- z<$lBd;QbN%o9*wizt{eh{n`5$@87zA|Nb-kukXLV|M>x@1O5k^A83D|=YbIiCLLIK zVDo{(1BVZsKk(s!TL&H;BnRCOHaHl0Fz#U2gCh=R9Lzbm@Zj2mc?U}l8V{a0c>dt^ zgLe-;IH(>n911(s>QMVbT@MX8G~v*~Lt76WK6LTWmxmr5CWqY*H$2?>aG%3zhbJ7K zdU)mGorlX0Up;*5@S`L0kvd139O-am(2)s8mL4fQa`?!pBNvWbJM!g`dqWOiHG2J-VxY4-Zc-DBs_){q<^(>7jZCl!}bZqJD()Fb!rDsd8mVQ=xzx27u$>eW} zGj%nMFlC#Tn+i;2rYojzOwW!gN9!DIa5Uy<>!V$c4mz4~bpFw;M-Lypc=XGoPs)_C z`en_^x|9tn%P5;&wzjOWtgP&E+0C-MWlzc~kJ%locP#Q)+he_sr5wvXw)oiAWBZSt zId3b{LXjfs>8H^4U zF-<+Bkc9YHA1TBmKK6c47b)#=P!~B>*G_#=_03K71!Z61wRrFA@cHk6Ug8UDDa-O+ zXS~Z@L++toC>eJDLSg6>pB8KHI_igSNZr02jq zA=yVR@D%LF}UW5hL*R47)l%0-U1}Vg@uQO#m6-8aVVIjeam#4Rn zx3`z4qW21k4+~33i1qZ2ZPr{`w6?tB%9Vp@N6s@TYv7j|(1>|Rhni)dr3XaT+i@Ffi~VW@<0TsVYD9Bzl`Qa8pyvrq!yu2Wkz1z2th zh&F~9N~3Bo7y}HYakW*DXPKlviG{mTjv};Jg3L(Lx*N3&6<_eBWd>Rq{QK`?- z6QR@xdQ5Tk6}}@8aeU_-7r}QfmTPX7YjrI@TKT|^daGjz#b^bqgnF=+!n4^IQ>WTrGm!Yj(> z9pagH1kb8x!JiB)$(&;e65t$5FeqDI1TxM>lwUj8e4G zIU2VbNP>@#!rZ(J?f^TCxUHn#2b6m2Zr)s1PdTJMVBP6B)-HvXKw7VyLgL$QON->{TH;H%pvA3kI;GZt=6A2m-FoH%*&aN^aMdxS}lb!hyi#9nq zGaQ-VAm%6Z6()NpeuDE%N6rsJ6LeCn6zZe%&`VM{eN!z9q}}DQcCt`qMjE^g4f6UllPMat0j2K#X#9t$c}T8Y%<|bxrTnahkjO zfcg~U{-&%IJXkw0YupK-gr}#5F>oFqAH)o55WUS>r2=KRA9JmSFyd zRP(l1EF2f|;9}!9BK_yIZ)0Gr0*?9507F z`{L#w&%XHL_Z(w!@!`^%eo@pa`LBhjYegbp=DV`FqRlB^NJBQcal)SfhXMF@a=4aUFl#BZ5uc}cEp%;1N}O{YyE}=S{p4yuni6^m4&WBqf1#WEJj6WPL35OJLbrd z0ae7A&u6GhVm`y)ALJIUm&V+^JI&mm?O0&WV17z0{WMiwOS3vim6f4VTZSZjj`w|- z8+PbR02yuR2?eUDhIbcKT=>kO2835?X0pl7h4Pl|qM_26bOCm}0xi#j>w2Z$wKp2= z45jsJt6=6rui@EJyI39`L+7z`;;^C^lZ&Sy4wvXs-`c(!Jq@M7wN>D^nYWKVOsHdC%|YxI05BQih(|CqGYcPx z3u8;Vt#297GOK6dr>##-ym+>yPZ$T?!6N3G}c0XkO1@>eDYi zSMSqEs-u~ew5@sj>`~)BdHVg{BXAW`#1)7b8z)331T>BSz)^!nqY|T|?JOmn78sNC zAqfbFfaA(`51vOj<~T-ByDux>kxuKns`t(3)MYc^{bvKI9)Vejj0WzUfjb{q6w%~O zOM6~u&r54hkSM3hD0?qH-cgu?QG5B1!k4=r7ESZ+DBv|*!jb1(kq`lWg28Z|UdJyY>X<*Ma}4lQ3(xLfKxyLjiKdAYfu znPl*t@2hF1rv+*on@6LWQc~M%lipJZalI|UIKMHd>j_Ro*H#TJ| zbfPI*!SLVao8e-k$5Eyp7jE;TXuh%M8>;9zCBW{}RT$-pvJg2|W)qEi1GiD_E6O76 zTidgVpas2`4}zZYD8U&SEUogA^a^WVU#YJ?n@wkqq%&r7p2f%}S|oig9RStp5uL;9 zrN(6j8c5kt6Oytfa%N@4FHHvCS8RrIE!xUtMT1=VL6JVMJS(;5MS3mW{30DN&muFB zWl{|@qY{Ui;XT6{2aRuT^Nl?=+=7MmO8^ME!*Gv;E143<5I?$&4Ri@W4*1JLbg??z zqnEg{2ZqR@ji(9m;j^S3l}A}lMuyaXrn-2fx@Z=4_f`A=Z%<6nE`mn=5ls-IX(PpJ zq+>l_E}D(?q9MTR@uPnh;Pu2^kcEDlN&!@Go?I;jp#;}Ra~Kb>%46wt8Zk6u)Y92g zAwrn+S<%rC7R_kuYgn;@Zd@>?f7X`lxht1VQTCp_dT_}nlj4VrP&0TY1S4bASCsp@ zm58gpj)Ny}TwH>O;P}et z4xe4?`KDWZUfP1C9zG9BhE3|oq-GAi5?1eZbXSe)X7z1#h?@sOqrH>L+6J_{He6k( zj_`1&pVDcF!!CPq!q9KTfK_ocIfc+L%KDJL4egrOPHeing7T=F<=txD;DTe?~!F51VTRChV0fu)9+-V3(evX zDAoKmwew#n6-?M7P%7-KuqInvMcfMm{UL+~(Gck)bL!?Og~y2;M94kuU0 zWkc;*K92)xt1(Su-GVFzuSGSZs0xY=t=0=>5S*jXB7q3xw`P(>+Gz#c*mLrC8;ZxEMEaQC|L;kcMx;T50QNV!@tQ|?$Cn7 z^{DNbQMPsT0F{1R2Ky)wY6Qk4iESox8x^_(gL?xc*gQer&pgye_kLABqY=N}rv?v} zRpuRx1-h;;d})&(&fcZSX#(DOUy{)mN8~)z(wU|+XgZ3?LFPUXc#2HX4j6kYtB_;Q zid%CYZAF)yN4r5~v=r%A^XpPbWtz09@(z2Oy<^^!sxzjUzpn1b2!WGoJ@y}G0#s%} z{C3b??C8+40J~^AFyll!IqqR)aZKOlBVdhnJ`C1oMoiNnAQ?6dCcay&{NuFBi_@k_t*5a9bBfMr?q^APqvQ(^ zVsG?M!t50dYt8^s(Yhqw7E62Qt1DZlr;+I!D=>{94Vh@AW&`##=6DQSmgEUL#TRX+O+pr znOrxz!SKS z{r{gIimNSLu<%`Y9QR6DGvsd^)@ASlKakJ{xM@tuy|3{=)sV<11F46u64i zxd2xl$l9y!hXIqspiz;gJDMbW1LuwgL#a>g4CPj*4VR>z4Bqijq2m1;;>M>w@2md# z%7QNcg1tTJUwt2R`^(Soe?%ereg-(K&>ex#Eku)w|A<3Dd+vbB-4>x%UI>!|5mq$t zYU_-s!7I0(d3?wV`h|#=)Z#gI8h!ZF^TjikObZO15$b;^R~<{oTq-|yTwTuAn$-}xcKES@uakJM z8*)eg&hu>eyCxQ25-DyL9|)MX#gpVFpH#p8=?C>r&aKk2J33=!=%Y&WL+Pu^&{H2= zJuQitErotTZ{mZNn#pn?#$NB8tiz;!ItmZ=;jJsE6kg9smP$9^li*hxfoI z!P1ZL5Iy*LEPXptNuY5PX1l&wI&3 zw{3d?&Vivte_sJEjHoyw7gw}xqZQlqR~rLyn;z7x=hSSk7n&9vsv=}!lsHWr72a9& z4Bg}ZVp%rLU8mNk&(^5@)dB11Gu3yU)SgW+H#7UQ`R3W|4!b7$6NLVpLVxU#S^W3@ zh*mX}Y5g$~nfppC4RX;I%QEP@E6fk4nSWWqmPm~%N1GooUkL#x%u&359NurQS${UK z)YJ%Td2PbVK+Y}oHjWUJz0T5T0)%-ycZzsDlHPjpOd14t;U}r7L*z$k1JT}Y^$LBc z%*EUZCq{iV4+r5zR*o^Q%UijL0R`kDSCZ+&>(|wC+EuCdmuH&(1l|=>wLsFL?;?i7 zEdBsZ{eo8nCTPqQHe!m-_!ri9;C_O(yNR|N0GH7S1D49Qd<3%C+M^rO6bfTdJhTMb zO+EIX|0r|+?2@Kn(FJ^}>BMG_YVw^QLVvQSwXt<|oQso+HVk!@QQGBcA6n$5B z5t+FS0TKtxG=~Q?Y9c*lJLDrW8(Quv2VkL-G?XJ$N{FTJPWgpx$HQ3TD|{@_W3R|P z!3!Fbd6pj31xeS12TycI(||=q;{qm0;gMyNb6sJXAv78743#p_ImQ{jxw~LmofTt}GJyif+>qw^)FAq zGCh>pxFd587Z>$fI$ha(l}0~`ctB&WA5iA!{`Gdm`9B4&Gts~QRO5PtrH2Be8mO~QyIHvg~t`2&W~pkFWEA3KCr4x0ju3pj=Vjtbz}8#L3;3J$I7 z+PpD265+sh1e>z;P=Wnft2por*${~?SU6QgR!fj2K*ZgQ63E0S2s4AleW3nI9nZdZ z*DPNs$SP|)BKMA-nLbrcHJcN2itW1tIl#7X%C`5 ziU79{zO=;SaGb_%@a_Q);PEmfMh}CvwFoQ5G=lp(p72c;%x~`b7+Mx>_bNBgWB7@k z{Djf&Jol3jJ35Jn^sHQWoKqsF%NxuRBNUJM&f~x}fii9#{&w`}?hQd5LR{;_2B(ar zOjV_uDFwSt4)&uI{j98llu9fwIp(r20zF^CRR&cweVeM=OWzNSBG;fxk)t? z`1Pg9B?&I6KV0i+Y#-2Wb?<^*2_;$Yex0)uv=|Y-WqLuOg%(qX9C~r%lc!-psewV| zg-iP+)8MD?{+K?L{yr>6t+eP21rQ@&Vs3dL`X?|T^rwHESvFiu7)KlfL=yH80CKVh z2>yLehEOR)FwJ7IdN(i2IdD8@#f+JI!(p_}8<}zAwmFsM8@J6HXXf0LVU-Y}4RBRv1=&k_)aJK_IljH2maNw0Q}}ylR!&jW)*nT>){I ze}GuLQhUG9k}&2rCa1f>=vLd78*htRyffOUxrqoy18q9;J>u?hX-(l*+&qZWm`*j zp0*@NCC9i!IkSozG(9%|(3zZ7vsY|&r_^E5X7;=Xy~&2|W00yliVd;u71=F7jss0mI1i3p(a`9ft84TI)t>*0I3=Uf@L zbBrsUZak5*V(#o6AvtoZw?~iv{H}RCTYqZ%q6uba-XqS(c)nmA^ojdhII*K zqwUg{tYw>IBab+Q4G2to#Ec1K9*-cyz8Ah8s6jWspo;q9=9lX8oU{9j&z&zRIm@CR z^CY9kK~LcPY5L?$70`1g=p<*jJoyzmk~%`xpqx*{ ztiY!G%Q}+o);p69G|x$OZGHecQqG=&>081Y^UgnQ=UzQ9?;X2YaDo-9_ z{xdo4!Mg&MOm&2Gtr`|<9YpKC4Z?*EqQRn3_y4;N0%;K9##P&Y&_Obbn>&r2mQXZ7 z=pb3!A{%X)tmz;_2kdwr#+oGd<2uOCsRNmN@7=Jw%2>1DSMw;ka25fWDl zdu#WFlb;+s{+W(tZkfAa!Nh&ty1H4Ms7OMqzaFtS(&w5 z!L|xfL3c1B@yU}jJy^RT7Wa(^C&LEfI*}V4^ypEKc76#B-2DeMo;2t5X~_wBk{o6V!^0vG$0}6wZ7JPR%&#=TKR7){JGzg_odpk z1V^=7h%_qBm~-Gl&XQS63j=e~ONWoS|BOvGuef}0#yE++xD32Sg15elzS#PfwB~JO zp=MPI-x96yEz#>C3O@HTOHCc2j-Ewb=gg5BzqoASlN9TziS8mQw*DpU{Wc;=_?NUR z|5yJ~Y=TFu2l~Rj3EYMkq3tD&l-PS??!_rlmu9J#(w;;sF%QP5muJ!8@4UmlGKXHi z%)WYYncY2o+FW0Blwwslk;-uFsQJNc=*Om?njfcj=){;faQnfe2=@{UZ|;LJ*^}x> zjg@N&i>gCctLy0OmFkD;hpXuvb=@j9m!2{|G=D)qQe#;-^RUd@5a`NR1@5ZzMr|0L z4Z6fYf%}=LohKT$*50|CMl^*A`lwcygg@?+FokwrtVTpEp6Aut#leNozoX{wU7&1#Z~$ajVfWtEikPrfL2 zuJRCDXtg`4+C3i6 z)p#VD!489P70GAZea_xGo;z{s)QP#r>&=-mc<9i<)8?uf2@m(*nXzo_;+c03JWfb# zbal<$35B8IyT{*Ib14FSFsVi;d&R9(^8e)o1@`lefR< zvv;($9cj}0c#A%JAS0(bDGt^mA0O`OkM+We5Z-nBIXS~djT$y(PQCKHtZCD-a*wNL zA}+1DlU3Ltq;TThweL4dOn7|Y?u;d4m(94d|6u~}!x~yF|0sFj+X&5w$=)05c)V?y z8=`DZ(VVdxYRw0}Os6iA?vbp=ogS7X$Z(6LSMBcjv2c3Qx}7!j2ly~jkGInkX^pJJxavA_y;WkACxSYj$6)XeT>Bi4dcGV8C8zbJ$%161li7F;@Pltk;uWdEo(=mqk;QN zutf$Mwlzz6j9y}`61JW-+#i*CSh!>;^{d55tye`X$zd2K_m|e}aNkOoY31XXd}CA2 z*^jQhom23EB-MIXmR)fF?_D1n{#C>mG`!BOuiQS&uko@_u@)-^@t0stcenAdYwXs> z2WnSg3R3tCHwM9(7X%qS9GkK^L2H5#B(@448J#PPL1JZ=r&xi7OjjGX1@!@OaaV9G z=r0@sOcFy~Bd3wWOPA?mn@F^>uS2I!`j0DfJNBP

d7@`p2QLizj&|rCuF{#nA?9x>vkR6mGm#}d0|}og~a^> z4z%siuGQ`VFaD&yS1wau_4~_L)bAH{O-y{FV8E{47bj$W*yq5&{ja~#?e#-RNBX>< znQ^h#o`G!U=jwIZa$PPZ;;b*r(pNV?Vtbp)0FfZ`96FS7S? za+x|Hduj&`;y< z^3ZnniOO&#Q<7T^O(;j{psBl}Xlsiv@g%I1Pk4^KPzdBG-S;)LRPIScn@ zWG_;GROirn`0kw-^sIU6&lD@{)L!Z(^&(#fg>hKI%GjTvZys04v0zHXRXA}gk(P)^ zv?-8h79(B=4Wv4x;v^y~5ToT8PP3d=I!QxK-JOt^{Blsm>7Rlsa9xJgk~)wjXp^h& zz}Ei~PGQUJ9a-qizSHIxY%cGUI3#rx)9qO@bAywMn%8N8=dlrQCbA246Y9rzoRR)! zcANe~yLGl#Qs%E&q+X6mj_ln%dP9#E?eXn3aw{En_R}$$5zR_jG*We46b)C8*T>?3#fjq}F*6OL? zSdn8|*I;ZcmH@p{dyV^hNf2^r#Mb(_Hh<-Bc^2W^Aqpe>eN|Tx=^_e}R!zll{ z>D^j1Z0}|8>K)O%U)RCCyY%nM^|^FiqQuwlNW?&lG}?l9D=f7(4{+_s17*WqkYD5#HWbqPNgAZIktpC17oznD8w-&R!5? zu&jC#31Bs14+=J5WFzTPHD`jFLJKC)-IZ@kuS;!G)i>zzR9gO`4bRU2Jx^u1?1=6? zjLQc=MJ~q{=X_coeN0o_GnuVnmvonL&xg2YyLL}QFvNzSPpq8a>sZgwFLakh%ohLE z1!sYCWX=FI{FUt>M+lGEBB&HiM9h{iy{E5lkp9ZhT~^deF^>x2zxt1`->Q8QHhxPR z+ge0&H1Cz>I~2XwycO1JpvlRV8$2d=J8oHke^mP;xXo`#f)9r{r*&6PU$(h^&KSp- zyzxoPqu>rVFZsA|TBanwxSZR6aO?KwKXhLL-afGF0zqF6_->kLQ*=$6t(x!IM2W@9 zf<6LoC0v)WZmcBzN7YQFAMY?bDt+=X)jjV8(DBY9mPKEa8dzu+v40!Bfwcy&<>s=i zGRwUwY7fd+61d_EY@&Uw$=aukb{g(W^;WbC!g8stB0ObL6hp$rv<*-A-6?To!3O=H znSIClL45WdJicd}S6W8d%@Oo6kZq$$x=Wyit5sEOn??)T>P*mrkPi~iQR9AI&~uF& zhRX+s`hrIx;TfN>8d~~4dwNA^#xkp3TKB%>$i|JvBO5juGsb6($;=u%HdCIu@$~79 z*_%$D+%#_CqV(*six-at?al|k?jiW~6hF?dr_dw;$4>ZIPJ!o!Q~cjGY%BIt@uf>U zs;3{ZBfx9*Jg9{W@8ZwAFP@nSo!U-&7SDWuFD2GIBUrVV7kFkRVht;F?}_(+E}r>F znv22KV=mRLoo}r%ms(rq5+fPvR4G+{1$lD*Jlf@Eu>-|w7H$U;H^IxfT>W2{qhd{` z&1x1!(F=tRJUYP=`xakSfNsaXD#2Q_#zV%ZESWQ9Ez4r;v%O_k7tU-`AFEkd(Sou4 zCT^KjvzlemCzIobj-Z?PS}`{uHUM+M72g;vvW&Md#9p2af)X@OkVKTFZ3$5;|n z9)J%*zA8x*Vcc4K5s~O;lOb;vyyHP#?)X4>Fe!#g#5n zXYwre+iB)Px=!kh|D+6ab|`r)UB)-U9bxg9WCs{B)S)^A#B-(~8YsRc$v+~jr*tSy zQ}-p(0d!!Zx{szMs@v6Ed`ogX9o9=N6dQFzBF*5Rdj)$zUhF~S#eN5$L?|+)sw43> z*`7j0;5um&E5MQRX=T)!{F?-Gz84VOgzq9OyT;-qxF96ENY~)@BTt+~j5)j9vPAmr9pcS}1ICtK8ug_obPQ z!xi&}*abbb{MzWK+#CJ=*ep_P+qcd8rr+)P52wDW#a2ic%{2m-uKPo3Gp{}|XFdW(lx#s9tBdYFVgqjo z`-3yM8unWwJ-LI^-i?PKtXIpM{B$C&hRpc}wPPk?l$s8K(3XYgX>nS7c{8qh37Qvm z&H3oS$`dnb)~&n&$HIdfZRqsYI(6;roF3EH$*n%Tvt!NpPkRnf@2=anJ31&eplQzV zQPg+I&@cK7nS7uCG=v@7gbzUIVceg|6RX^U#OGqDmSQ6Rviw@>reE*afAY?!RGB?%N&W<; zyM1a_X~Q<>CSAF0b~#!;Ccj;D>(a`uY3CZKmAOUprIpJMIx{vg*DEt^;Ou?t3XUZ$ zUcWfiNm+g@W6Y?mKW~oqJNM|d<^vOYjvm*R2CjZ{!X z?&B}~TVVF^$RP}7?J|NN*~Vo=z1_9wDfAIO-(gAV!nv&vN2*V#50)6?V>%qA7EM-a zotdpZ`nW>A?3Db=;|hJC0*_p$eko4&2O%=ugwazkz+ug4Kz zv6q1F6jLH|*O#%z%W2eWx(sN>=vY&!QE@PM-QPaR!V07=#u6 z&Qp2Zx^+fO;?UH=sR&*tjEd?xbkykaIh|fp=)4B~qY=Zt)~= z>*Fpzt>rOoFVCGdH>r8^=;pKy%c3N4>%BODlzfF;F&*^R#;@kE}ez1yf3-+mH zO8h+sP}8b4`C=OrHvZpo0J(SUpK}21E%EJ~=KCi7b9h^S!aR52@PCSL*M$x?7IMJ@ zw%R{^5ksiqob?)nx^FaKb(kT*0GA?M5ic!7ZYN|4|~1BIX8I&bA=mMdgJEDg*-LIod3N(vzpeNl12H_H z#3Dm|JVLhk)OSnuJ-*H=FE2-m9zA}vd3P$yYdXFu!$)*D-k_V)zd-+v_yUkXhz<4E zD5O-b)+GL=Ulm4poxy$VK{mV>30^#_z|x1#CeyU?@@dkLPUAb7-Pk*w$9HBw@wUs= zZt@SnNgaIeTC^=Bs)iGr;Du(jirZ|0*rJP=lQ#KXh*4n4EeMn67`~L*6<@RTO8#Nj znt(Vz7uU9415+w5@-U`riCt@g zTLropI@V1Zv10C9c?~cbPK+Ff>>^JNz!;swTiNXAQ`@JHseF!^0o$qSXMG@SPao*a zt1Z2^S+OjTtf5~U`dT2tIe1{f%8oF3Si+|s{~v2#0w2@a{XfrLW)dWsB(hi{8;L!L zBt>f}s@7Oa?SdwDL1`w0pq5f9wxVilRqZAtlu}DeH%b((mbQvoT18*9Mdr!>d!9RY za<8TD^8542&D>cs&vKr#e$P3G9R=gG7%SO9eKEpZF-HSb3Gp*?ns#(F1#3_kg;G*O z!^m4BepFIVG@*d>R9jThivDw3-{hxRwVQ3IlYwM`yk`lR~tP&wZ(z+7fY39 z?a+dx4)bB{%lIPGH^aTQtj$NcW%J>G|H6-5;&&nI`eH32v5!=rtpO}yF-?=KGl5!! z7Dx*~Dy+}~iH}-kp?3I{6COps1XAq`K^a%YNMX>&6_QiTplCSj3QZ*0sJD3}qXxM& zYG@Qa6^ru_pv$YS^@W67aJEsSZ*o1D;1y5Re`e2=*UvU;_I&4^K%^9BLu0Wk}ek^H@nfjA?9 z>du;ZmFh+M2Rt46V*i2y4eVU59>C6b2Hs)2mj099Xh#i_-HazPUTR#oFGF z2Th8+K5L>i86LjQW*b=F9YL)6jaLI<{=!B_kqu)32I!LpK8n2wp=cxdr)-bO{@YlfE`ncls$;;Wq=22t8UVHMVU&|S<=~{*UeBq zOehECP3cuGTPcElQk?<=&X@KcvluJOYACo>{;{N1Es zmnQ9sqAII!gsue@A%O39h9R+ z;-aviH8dtY=0kclCvDg@vDnsqN<>wk5O zT5Ch#&p*SVO5gFivQ_#Lx?=#YcZgI%T@zAB*j%pOso=@q}FWNA5Zk|-73C* zV%4fi$zsmExPz?$e+;HLYA~Qq`u7<5AWS2#7aRT^EeM>#dOhDRE-|WZczC7Ob=wWd z=<{^iQ<2F*{#}C0_2}5@wIuQPGnAWBvHAo4ek|%LSfJhrkPRvIKvluggS`P6iDIL{ zq*e~(~iTtG+Ucg`&spi?qf$jmmJh>+{ovFC6g>OluL4` zdIPcG(w2B6;>$Hec~);I%o_u9B6x@I6Tv&wqlk@{DI^vzy*gjwXGTkr)8)GvvU&rt zF)LGW6?qSmWfy;&ohe=`_5~=%aAbYztK{_6A2kiL_}YD=eCzl&_3h}J<~z!FvTvU6 zYTwep&xmgg!TiE>pCgvg7`NQj?dgUubZPWV*XL_QR;pI5Qe=$_4cfPFkkYnoO1UbP z%STkM44QKLEBkn;S_GO35q#A<3ReJ1dtvoZrkaQL+b~Jl#~S1PtCjtHt?Jg^4;Y(w zL0kby@5K8PtR zJN@GtGXG_(TUk5t5Ad#c)o?k%x*U(lw}u>ie4mzU?p?X2rE_ibY^!YBZ2N60sz@2Egc3w1|`DP1q{x+$P68(@g|Mgibb;@zdQ;hEf8jq-X<#tZTk9uTit}@Lrd(_MXak0w&FkR6Dh2^BZtJC zD5@DN3KYajZ(4c1iBjkoDKtk#`6pUe(1Hv!l|?Dz*|XBf&KG~*6ff85z(@oxRT3Fv zDhzLA%DMXCQjn|8QvupE)SSYZH0qLd>Qb^k1@&b7jFXoX4M~%Zx$AXBhWQ)m>9RdT zw(7N;sD^_Lma!PmzmHf#Ko~1>3ICi%roUzteUhcrD4|n^sJum~jlb`Q9%+xxS2tZu zw4f4yG0p}4CY%HcQYJB$gkLr$?dPF#kD@?HaTm$EimprSN9l??H=~dAmejjXhU)$l z>)iuqq#wRJ1o7i|bXpVNZ*nzx)!Lx4LahxV?Zs8Pl!zkW+{4ioWb$6X$wdAPLx~b+ z7!58l3b86nbS&!c$3_vrAvzI$(Lj=u1Od`w2#JAm81;5-$@lPL$-w|e`-n9M5XhmN z{_F2k6TkiI&ofN9!;fG2l^;KNkR|+z{NBC%$D*aTKRNKP+XoNbk_Quw=3rjFm{&Qy zdW^}&2!}x&t{+l8ZZD?p1)7GI2_khplx9o#Zlh@>9E)Ujz^hvpDr{_EoJCXJ!{B6; z?pwG2=-@wG&%VYlInHdeX0s!b@AZ$RI_|aCls#+s=tf!7^d7tN)WteY%`|9CTtKj2^2 z8JpgdJ@@rEwDs-F*YL~ZPVn75)1k*8pB=qbJ3teoeqCbFCW}L?xNd&vaB}fBJ&TZN z#^B6#`3Dl#%vC}BqLS0$rdSmS%9JG}d_puik?Nkpw1}R^S0;a*RHsZ>Kwwy%3LSg< zC2bu0@!7M7#;i~Bcjv5FIc{l<>PyG2T%|NDIy1P7qV(}A)n{wG`|3g z@NmO0GFs~}fy^EVW6?&qQb2O`$pG@iGd%?p=olqQop=2_r0?uSe}9>_yRqZ$`X%$0 zygq4Dt?eV%xVF7LPd)tYhV=Jp#eXsT^PihF<*K@K>n-<~yjMrP=bBOUS?jKw7tPs0 zJg+A2FY=a3>vdO5yD1o;zMFzUkt^3%_GIHEGK>%SYUB;ct#bHi2OpKgsw0gFM&vL2 zS+-B9P;@#MAR$klr#Pq8(c`UzZuG+`s6+oIofVN8Y0TbJL|oq$ss;7KMKM4_q5%$t zG0F+b0ee)ud7+ec;0bLe$$E}xoXF6SLgWJX4H>7Pt>*iL>zbI`%Ia%6_ zO|I3d;7wJ@trK2VxKYCs3NpiU!==#${lYWDNk1S|roln(lEVcE_Hih1XH|QCR0+}H z)=7*37(^`zzzpL~M99h;%7se>#iQbejmaD^{Nmvqf2-1n9n+R9o&VPE-K$n@T)JQv zg5dnGornKq)%w3$DJHkWf>j%4SbL2d)4g}bOX)+?#=Y9#`t~}~LtFDv@(S#6G*ARo zz1Hh1)i+t-{%Ojr5}gzyriZrLRKOHSW6hq!&_e)Gf+Ii^9{?u>rLg$uBzXlNJ8?+f z+~=mwVvBm!YCOE%3mrc?oHd(uk=-p+XKOAm|8@Mh`6CAnSRVUgxxp=-diwaXu`F@} zTcZ-t5&5K`eTr%Pr}@z2Or<&Lob12Nhu)Tzj{*XdbCy>@#NvarVP9W+a7?ND;oI36 zMSp4WJlQe>{M9aSa#U$!rbai9cX9e_E>3^wn#eCL*yg|ApL9)sXqd2O1P2C(&oJWIKs2)H?l48Gk`qaN}ojUzT z(GBUXP4B+5QF_arvH2bReoSMBmuFIEhu$P#0jmi0v>OF zgQLr_wms9?if5v_wk%cMuKGV!Hfv%W8&au#qF@nO_NMW5^qrhmi-b`k0>I>5Wnvbv9 z?;2&UW)xRSFeher)*{_b=Nn!I^6=>_DNLUdn(y7k`2FX7iEk_v$8<#J z9`MtBz4`5NQ#!QaK+nA~dZc4ezH`C0vBUcU<2`Q#wTww1tA$lxP{rSRa=Os-^M9qPNGtN9-I#KYF!BPUO* zorEzZ#@DC12A;YAA$sj3`TK*THa_KG?CwX$FF97OSowDKw_aYcMpOmp*w+2M{Fm>q zOo1`@0I1?StNHHk>AxM)Xeg7X%O^xE(6go{*)I|U^-=46n!u*v+8}0a%<8Ua0-|G0 z4M{`r+agn_goDSEW?DZ;dd7JP^^@M2vd($vqa}0M;$F3y4DXTtd+|M`!x5Kt+A_YY zy6e~Az>LBD7R9_6-oI(1My0}8_{HkiSfZ{^3cQbQ&C?HAwcvSU3@)`p#~+zN%1Hrpfwx` z3}nIYyuR*Dsd3WOx(!bJ@a1_x-`9S15GH3H3w&*2@ut6d;az5tdSVQcWi*db{V|4c zaM|vn>YY~u(7)TXM_#7^z0I45PbztsK*10m$j47)!6I?kQziit1ilrSzyU%ldTZo_ zy7R59)C;F0+oeh*+pmfvv-C?Os(^ng{L=%tSvTpM`j^i#X z?SVN|MYg?=7p8qP zB|Vq$HjtqRq2mM^g+K7-1eZo^0Ot~;2X2}qCuq?s*@!=A4gvv%HXa|3sY>eV(&xKK zZ_J;(G<(UEym?ZW=chJLJ#u)8t7^6U$)A4Np@q`$HGVViV6o-kSFAEWhZANwIFAL+ z!U?;>k4~97bqcG0XA@%+#5tP|SvUncVtM5Ack&_uOpq4u>RW^(Su`7TDM6wK5~4 zg+C-)-2;D!r@pk1kGjDiwno44Vxb@-jgjIIQk=j4E8n zWfI4CtCSoXRw|}!ozyD)ii2N@?~o7@RVpkrsZ!VR_4ie_R#v{v8SG!CuUe{MSN9_K z2C0WMv}?msYTq*cgL8PdQKQ5@JO$iz70_5H{Mhgf5EnBMmhKf6uZZ$A#M+UrZInP2 zNGoxb@*@NwH-!tYqj|(clE}BJ^bZ&tK;dIku6S>GB{Pe)y0r`}=4rkWQORX^C~1-aq#bUWRZOV4h@#b~j^8*VykaE?clB!5D;3wY`Dju)=Scf64Lxz}i2 zFFt=<*NbP;+v|NV>RT*63D_^PB1aiCW_`zWPotnsUG}<|FD2YlEEu}80jUJUYrfGX z352FGkdI^vgY}3BmLyX|%aR0V6%^OtV0u~@@yZ1@;+F?Smv{yDvEaZ1e^slpZBbyD zT#1b+*s*gvYVEK5^`nn|#b%!5ZTZr4WGLrJ3sHMN=fm04J-B(mn0+XA9R#$=WNm&X z&#%rbT$TXg-$iB=b-^phwai1tp=gHZO0^*54tWHr1jr=X^(k6cNs8N>(nDw;4dh9{ z1;Y`>d{NflFlAEKy>mqX^O-C*;_`iX#3~{rkR=z;Gn(f8-l6jrDkhKIV{@{LcDh1CFjB$I z$+ZpDQd#Cc-h0QOn|B@CclY0oLW`}$k@~S*g_GC$K(=D{>I&uDjlJh-FJC2atlnBb zLdNP8W(w+=R6Tvb#>j~iDBn^Dd+VWU_^t$!8pVk*w7pqaM1+BPGzI0oRZQgR zZioD!CKZ$u1X)NcWjfV5X%oXS*a0rdSI9!ijHP-cD+q8*;gOBS1Mik9k?t~V_?7z) zF7t}=aC*FB`}Q3m*Xuv-+50ngGRnO;f7Yv8Nhf}uuTo#b`23$RKHVI2mZUWx6blJw zz*B0W7bk!Sn1sQi1>s?BP@XC=8K;X{OGt3_2S%&8nGd!N^&8OT9ea5>_U)oo0W?57rJJbgc!3UZfB>s9WKW0a4Lns2#I2xsPcgbGZ6Nou`6}vAaxf?FhT1{8AjW- zm)2%&-~mge2=1H5j^t-;VMp?~k5p-?^ntsz__-w=K&`=r;-{(GuFVfMY?Xn~o4o#5 z;eyp?p;HP{=BpADESIn|wOqe)ndM}#`*Ij`0xm{A_dob!jUD{FC>`O=_e96wl|@4_ zD)6tgn>}Gp9zS>OD}EC7+`iki|C=vA+qUiF-3RwAKb0w2S^1;an4eO2#I_pot{I>F zaOQ}0&aU!(?r=e~yA-jDNf6MO3I-(fnVLVed4;0fC(41VanVn2{c z6Np|S*orX4f$EvmWkv+c2{0Z5z<6b73#2bp!}pSZDnPGPYWiN2=gn)XgXtPe$C(44 zBvnA|263WXaJb(H_TTh3E3Ge&V(Wb(qOD4XCaiMitRBX6;c7Ip=a4q;c6kB7uD##s^icqkTIiS&vm zMqViji^wZk&d4^GQz`%?-Vv?X{;rT+9{Txq)`9t!&yM(kF<$(G^Cw=+Ea%Is75VOa z_xT5>PqS9{@3Gc}{7BLB%;)q;=EMIyd79sscWHaQldn-nVvYUC?@t`qRMJORd`;XQ z{zTxMP^tiDotikC*}h1l0q`d<8tD^_q^!BVBOW07a({=Uw!Z%XZ^-%y8ruRITY~Qm zws`76nmE5O$MucYY1PTq(SumJUmQRzrsi-#nOJ(K#m8!rwz*a zLO&H42W!ZBNo7&L{fpJ$r~h?>UqsQVZ}#oG>V8{#>FU0H-^kajr%}gu760{j6o^^# z_c?3+Ar^P7e@4}7tm?s?(8<1q-TpcBfDm{c-hPbEXfh;pq7{ry*VbHqn)-;m+N7KUft3elP-a>5@v9pXjArzj^c$HH>g=!?PyGIheR1z)NbM+1KfTd65nbo{*&7 znzIqCpX)#`{s)rO1OB0vRf-!~lJ54Mp48Eb^i?R;N)wQtA1p^tmqL@0AP%%1Y0;S& z#Fc<$l}Ru*w023Nd>gskP1XkjWLjx4q1rPo2|F?R!W7nX9-8Z3VS63CCtJt&ez3n_ zHOr8)57wND36?rc3evA`xy^=Lh;7~l#3!#(h`KyL=A#&?s|ACDAxXKG8 zy0JVVIbBR?_YCc-JxLN+@f3KKMb-gg(C{#aK|}N8KqCk$bv)tb_s@Js!GNEaOzbNu z+wzy6M%my`2Cn~T--h-3_RIg`w@yW06S62<>W+r@EI_-vLuXTDaZQFVs{K$kQqm*19RQuG^}f zA}?OMrb@IHV~^gz=6-oTz1Pqw-|pt`v0gJ4E}n+p3A6K-FXg`~4d>@|nN+dtygmz; zv48O~g9r2+`jXVYPyar|C*H**8e{xsY^OeUT@2IFH&|oDD}{2`*!_b;S}va~s)aux z_Bn}vth5#D;kEAs=h6S7&UsAs65vuW>!D!4mE#p@B;xS3Ci@ASn?i;YsT#1O$e#-l z^J=$@(m_)0DBqDqCx`g5IlgIarEYv!`taZHvYACScpui7f6U&MI-KGcdduk;Cj%W? z)FO;CjH>&Q4kXToK1x$KP_P&M74M4BXH2$}?o)FGN&-_F2o8#h{RRC3GXnv4G%O!k zPiV_dMhg-^F-?HO%8)+jv7X{h<`dw$-{v{y@lo?-c7TtZ&j!wSEMNl{^5N{DyZ{}V z%FvH0)s%dB6?T?>+<&@HtF#{sz0YsR?+8pwe{G&s3C5z&MrW4!24|70T%gCEdb08K zc=U>HEfJXiAFL$`vdeD_=s9S}#ShotgRQi2%ABQh7ryu28@V%HA4hF+eqFb_P%fW3 zDW=lY0gK*$f4Mbn+SvZX1`Hn9r{}0wdRnJ%Tq)+Z7PNa7duXKUd!g@NvH^RRa#=s=sp7qV6dGn@;QvvY}e__ z^1s`4fk2qVrlizM4h)pfIe7A7XAP;!$bn+HPV!m&V}4;6`vI+21)pTZC)Fe|4o}}q zu_O98Oy|w(*rg*TmR6TvUZemp{NNcdM__Hy-c=!YgRpe9q-p7vm2Fz&u=0$qystHD z#d>)Gws9ycS}f9so zAk!z8TFOwn-GX^Ot9-DX21D5kIu>SweAeOK?I5ecvwam9;ZF6jnX%3K*d99^3PMXI zm@@CzL~CCmr4IIFLW|}B4S7N8^J;Kc%%s;;tl!1t~La}sJLwPk{MIFa;)9?6bPcE zvl2y^f(TR#rbO^evKpnNDulj8exC@`CPkY-shLMVOzIh%72CVP?qgr=YS5>0R+S#f zyN)VZOBSYdC|5BxY2o4`mbb88hlmR8>Mxovm8DLk0Uvaly>CTM>o_J1Y5*K3QLq@0io`XF>B;Zm6}qaOB7M{A23 z=Sh-;h=zb(>1es2#fhU?uP=XoQ4tE}guF>MQ*vat>Zv;$WnT|i`(QEid2eOLnX9xSiasPXL!t&{on*6KyerqdypVWChx(TVIa_pVdi6cET7R zwZZjKn!sJUDlfM5|CbFOr4Kht8>{pHJTsq0i%|z^qjl3lVof1y27@w2CYenm|R7`q;9`Pc3%gAFP+d$$7aFwO2F>dFI2oq*oM8ZR8 zPt6NWj1IOAF*;rQLLP2XG!Vs-I(F-DNxl8fsr&a%ZM~{W!{5(Yy+xLJC3Znlx5!st zb66K2;m3Zh{u@7bVzYJHTi3U#>FUNy*ng}i?C)UAgZdSFu;3ZBf zvKG2D1s{n)!CFB~gpBCqL`s0bk&Lm*`3~~vPGj~_0e_ zPa@X7{KgKxr*|&A5783X+lY+88}WtltO=01J*PbjDN1W1$QP2uH|6DeB%RB|^zb zXp<_n=3j}1Y^(F48=;y+%W^OF*IKjf-tAzC%1OReG-xYB6=4RbrKXIN{?t0PDJL_2 z`ib}uvy8-f`d*wT4@Ss@PSZ6-wu;Rbt4)W> zy}$;So_@5enD{ne2t@mW`2I#5Qw=o}z>!)k;G4TeI zny=4COiowk4N-i=QXY!jBZm541@9}89-aK*i4&NNP^ns3D>Q^v`YbWYatRUW(8V{4f>nn};m zIhvS{J~^Z9=>*sU2`t7MeI9*_TriB*o3C~76`FSQ;8TiOgB-+p-3+-g1ir~A6Q)m( zs0gh}zY(gxexuu0VoZ~}4f5!sg!HoxIh+4Ve$CoDvbLRe zEOO+ooUnA_gk=bQ{&w<*VMB%t`{AS#^5C~sn>Vj2`K^r~eRtK1n2dS+y3S*=S;hGE zSN{KwU%hx_?a+6s)m%I5ox@qvhL3r}F)MTAERb-E!^isd?c49zVQH_s#rzd3=9m1Y z@k_-QLDxT9%Zal&R-(*SvG^$xV2%>6`a@BOI5u~i&#Nm}VUH(Pkh7u}F{;Z&IAq$Z;3$CNu;YPsKgmHtj z-zWy7>`q|+0C%V?jw@Wvi28@wVhQRdg#ZesgTWGYxR|E1bVSwQ>bI{ld$2Sr{EJ=t zuSh}e8v+zIN(YVcdk84iieaIw|DQiucO2knu2jxQ7tk;dY%JZ~fZ|K2FAkcV1{oNy zuYs7UiSqOtp&jUJpw|L3$_E!f0VMAOAy!0f70u&n2#V4E8#Ekeq$o}bU#*b+fU!Ix z9<_3#T3Ko-o*bHqtkQ#0x4!nYUw#k$E!c5hM}B{kM~a^LL%k1OzQ+$NT=Zf-zY)^1 z;5V&DbIcW91}9Jga@L|8#1c?_eNRO@Au9C^_j)WI@ymJ{h{Y(+OxlPpu*JxAHQ#0R z@zkTt4=I5z6FphQnZngyc!Zx|?(leZVG3CvHsh(gmWcw1zD# zZ7xU#UV#_|ypFhP^Aaia(T|-Mc8N7(otZCf(L%9Z^Z6N=D21NgIw)mB*Z1t1wr}p4 z+OE<3;N?~?W8WfRcX_hL1S#oTCB(XZz;)P$n38}s;}w^$pQyZ!vOl1CuxI081}FuR zy%Oz|IgFWz9Ogu948!RT!5$Idi4ceJl!Qw8!_g}*ewWTWD#Lkd+IJTnZ*5#t%3)i# zahX&(m<@DSWjSB(lh(R>e{_;hV>$0lx4VZ*%S+E#3uj>&sj-kvVs6ytwj!jfac=tF zndWBNA+JZlr>vM8s=8oqFrtl$a2P$~j1Y4($I{3Kqq$MuP^`#M^-e8>B?d>Y{QiWM ze<;7rKRo`uW5Md?rLt^o-pOM-%ieR}|K#hB*i|0RK05KqCu^tMd1ZE?)bzEVNSzt% zGsLNZaRs;vxhK^u^R;s(PLsZ0f+6cS`q3BrWpZ}vnT_I=7|5;|+DTim;MKqu;cVIL zq?aKOYBzX4QQiSCyeRQ%oY15Vb-BUYq94Df$daNxPEOH|BdtxU92)Y-{_b3}AUml( zuZmi>WyCgPGauPxWyWgS^Yle^-8~Vz?v3r1s8+7^2==-%vO7HMVoFMh#T;YxjW_Y1 z$8Nk>7k!b?b1ar*7_c3_hP6O>B+#}V9zWS3-(ihg{Wno8!3(}c_^%#d- z&||hf$U;c6e5lb$O)No8oiqf6>wa+kTpMk0S8Vy3H0js`V>JSoHAXB&O}nvan6swc zS+CGpFQKX5xX= z*rI~{wU5`9sQOv$$l3|Do77hNIFm>w)g!pS2udrlT7Ehe#uNukGb{;5E&${xev+bB zNjrCj$#W*Yv4CIrzIm@s!<*FVy=cL_rrS;&IXrFJ!Cl*(d_P<1DWvB7a>vLm)#J9$ z{OC-xCe8YXy%@c?@9=T&&U$OnpanB>mSr%-Q)x}I^u?MEx0V%adR1FfA-r_55(KBO zsc=^k;{?~R8K?$;Y(sRxRWnuy<(dh`^>hW)5Ni+iqAhEfaS64>Jzwuuz0!S}MqBFH z>qXUjc$rJyV;|i#_|f9%j>W$9MuiC3h?q?-=@0!(nR7u(=+4ervC!M$Wb&INQy(TZc zwq8}&UnAMepifwoNzh)CWnNTiY{BXQv^So#;1uc z%~GdHnf`u#)KX2m7g6V93H8E8E0?W=1xe6zlTC}D#|uc$fP_UuY^2v1v+E?AY`TS?|A;CH3c*w=NBym=m~st02>DZwF>M$}Zi;uSnPP zvV$GjfjN2CZ{En87&u{kaCY8JtTWYdnSfpid&S&}Gpl)PcMEe8k6QAC^-)T+F2$ss_0b}-)wah)JiCLW!vdf z8?BB-a2csh=^VeD+ z^8IC1>ixkw_rdpfZeGQ{r-uE}sZVDw|F}Of0#5bc?vHB~?Nnx6;5unjwC!0%k232+qWlMY;%XK`9!Jxr z;8g$H{lIE#UJx>zp12>wt#2Rxbj^tOYSdUe{GG#xR#=BmBj;Y$8!r!=Hf`9Om8S4J z4O_Rzexx#cCXasVnb(zPB=y^){N}N5`{CcW$5`OeZ?PZmFXK1gTDM~Uojdbatb2~*RtBLQ>Up@`PqNt zU`Eb9U!ZIPF1wuGlS8P&V zP~;M&n~n?oCY-6ivj}u4{`RB&SFY^ufEJ{^?5rm%^*i}b@1M0g55s?Y6W&wObf?!F~*r$AOCdk^p-0qma=}rI_I|atuesffvm=lR0>6SI8iEP zZxP0ZgnH!CH-`Tz*y8kuVGrS~o4;T*s;vr~WK~jB@slXyUTTK0IRD|pnLqQNl30~< z{Kpg)dt}-ltV%=ZsLsv(Hu8M-#-_fT*z8Sdo7iC9b5q}qq;D0ys~ji}Q2zvdqYgEU zWx3>p;;V4b&=Ebv9XyKhk!qs}Uk=}c&*Z9M#oeqS&=YG~TxIN#poqm8K1j-t$osPU5SBdm{hcUB(rzSoYcGh^9}j!$&u>I?~Ko=6x6KKimn)&d#qZUKW*&~ z46={K)0vxLG+{RP*x8L6sOP57$*xWBdmr!1)ZZtgq%TGupAwI8pKs8Zy{^_4yw2x- z8GeYpt8Rm*nA(&!L5-h&mP|`7{ySetaK4n_91AgPSZ+|Pu`ajs1reBg!Jgl{WLl)- zy+po$T=Rz;p08Qx9BX&hr)z$W;rXWvoh|J7?Mj}Z!N!rMs>hQ<9==B=#Xr9O@caMW z{lkB+s8~`)^-CMANQ3Lvt5=)-BB`U((#9y#kUEL=YIhQM^djyO_}8XecX!iA-CZSR zbXxz>D!sXG9ex?N{lslT{knCY5qD!$X$bBTl-t(SL4#7QH5xXk$$ztU7>vg?8#JuJ zeM=s@@0C2}m#iH#GCJZt4Qi_8_0K-}{UC3P&;4r1cOHz`kYe!#E|)yQm4L0PN@d*< zt%^x-R!nflCpZ!AL1|PvXeOISuzCc)pw*&ycd#5EoQMjOYDg8Fxg?dPR0*@H%!USQ za=e@p%))|gGOtm3e7}|r%4DZKCsp!8bEtI>#`z&Lucy3RV$E7q;l)MZu?JeRxEg_r zntdww3tar{;ivui7Q{#2@dwmnH4iM4GoV!?y0ESGWi7(;i{1!a*79@dlEj{C$xjzu zl=z-jtOn+%$MOb>Sl&=gJ_*l|&TUNzzE2L{3DCJWd{^ebjo{%_{s$2}WOZg!1P_Vl z+qV~O@x<>W%H>k>AY<*=8xJl^SkC$!bZ(6P-M(4UUs-Bvc7LbpWCQT`SHVzwMqT*O z-+x5@{`21_&opIyJmdb}A;o8DIA+#^#=nPOQCfqhLM<DA*wk zK%50^g|T!7^btdp1hd08qw-!^NiS?d;j3sWYkrFPvE*OBv$A!Y+3jyni7MyrKlso5 z(nbEIBK3H%|LQe274@KX;J4*X@HT`P#%ZD5_DA`#h1c!&hFrIF0{RrBBQr$F}Y6dl(x2 zG0P6nLm`G-)`U*dPpGg3^cyd65IfbqUasI$qHeCI)t0Lt_1iL*4`xa*8CB355K5<* ztFMHD0T?R%7c~PA6I2$VHTKOV{JGv4^Ru$%XAESM5KU<6woBXj1y;%39(RLTdB~lm z81p+Aa}!LUtX{X(gm)2ReuUs2Kjwmd!I{Cp@n;6-1`~iEgD;pDyeb#~{(nCQC{dm{ zfK6f!etaF9vyyLboAFw9_G=mKSTsNzf4U3Vts6JA)_Z^a!Omm+oe&=xiZ!=eJSYuQ zl+WZuHLbZG(scPqo=BLhA5spqyn|eydB{jGL3t48GtR<~k$W42L!$;xlrmkZ$8oGY z{_`vzD)s+NdS<5NUMEeL-jKGqyMUd$2S_Vb6n2Rgxh08+Pu9V@+o4?vnJUJuFSQuA ze)I3fEm9@4B#QrO$kK&%*?g4b`%pFv%I)b54k;Z5YmGWIwgXseKg$$t%wl9ZNt@`~ z6t?%$x225mSnKs^wxMDJtl6I)TdM{~)Ue>#V6y`ioCT;6T6`jX6rOon?&OZ69+X+K zB5lsNzmr-|Vz3xD_^3*GD}FleLyTKrUK5Q!Vcgoev>@jQ+eNu5G;-vsKrJRxrwPo% z*GOZ?{r6uCJ4|XNRpu{fSu9=IFN2C|X_+iyy|?q5HtK&9PIag#cnMx%0(%L?g&dId ziZ^a;2^6juU^UEMXIevJ%rnds7yvClhE>x7D?e^9G3yOlwST$!L)<#vSpOe9+X|o+ zbO6-f_l(`-6wnW#7`x!+6sfh?MNuX(cH(mwa)7~iiXf9&zQE3Xb3Ha z9c9l?GK?01ROnr`OP+C+lWUV&6JJ~CXrXpz^+IQLlsoe@bcUz|Y&KFNOcdGhC}=Gu z1rm@p2o6gL;S4~agQ%FGR>~+uT|8u8=jT>-<5&3h2ZycF(p}8|d}6;E^H-g5xqf)n z(QsNDcjsjb$4^@_C3j)@*x0CO_Bu;A##v`oO5?vAEkr8vhqcn2xt>a5h@VmbRUr8(wwfq=YBy6| z*2LswWpbA#&!$Xn`3?GNEwc8V{K@;3TSkt|dT-Xu4PD#UN>5pp(fP%+%yjE>sbwlw zh>Bt@|7`yiE3HcXPOeBj!v8K^rv0^fLl55J4-OB`{jQzAKRYmN(U-dxjGX#eN`r&o zGqHS)bvVvzpk5Ke#2-zv$a`|ZFN`@lNX-Fk%vg*Wb_SrxqKqWu4E4+`sTcyNd#1dD zcPXhG(k4CqL4}gaA&6HYN9qR7VSwHT!^HbcVP4&#Ogzk>?NPcAJo?5l0q=)MfS>Md zC;dqq8Yv-^U(8zbQ_>-RUQeNtPp79B<&`8+F^gW$B!YU#6Z;ZDW?hz;LP%o7#2i8- zQ8g*VT*MiGA_ONitTwW#ym2Gp=R|}EV}eSjl{o2_^i;;Lj%-Jd7q@35*B_`CItlPm z{<_Ns57Ek}d!#~FwddF(AW<-9SPW5`qgUgo%5X}NSWEEaJ z1GdviuqR6Vdg4$M<Fh(xdetFqxewR>MJ9jtj{l~v*A zWt%@`g^9k($^y`zH!n?$Mqg9!88oSHR*OicN1sIlpG9GBS~YU0crZ)|QUCxl1}5`bAB799Fh%4a`U;@M{XDg|gB>lx^hS z4_)>XzxHfOj|T1JPSt;e(tP%N_!IsHAM5}=7y)FZXO1R7vv-a`77>1d;{?%9c%2OZ z2|@s4j!zDo5u*c(15cx_>Dpe<1Vc$IV1hEXB#esFORgjQcIL|&&6<@j-uT%ixAO7I zQ7fNHd}dFc=ma}{T?ngrxnAg7IUR=te|pc*4OVu0I=>Q)@8Cz3^+MMeqMb)!Q|Yv0 zig1`3&4{@Mc~lS~#`POrz;B0!jc)dstiJ)|C>WYzG!2C!C-i7(IC}dgUek?3{%KZL zz7#)8lA|Q39G49SVjI{pqoh1iPcesgU?*M{ItO@)M|=z7(@&>Rk@OoA>|D>T*j`rl z!(hwW2`OfwLZm=AnH3Bi4e0t(oiBdhc_4b}3`zR&!+q2od{dqzbqoIC$W+cN_lemt zcFTHik8q4_ucr@on5CVzzGC6@^)4wuM*11KNukzd5ih9rUeHNnuyqGBw{OsGHLdh)z&cy+sjB5G|Dup#Za0J zrxHT~s|i7U9^yEjsyw7`2G=57T^yy=NGP$Vh z-|At$gnz%DpW)Nl3oL$Iue+>%^W+{+b-4dJd-``Z={&zeeDgK*9W7E)#hCxczN1=4 z9`o=i>R^B)U^aSM;1l|eN|mYa=-qvvU6P7SjKn=-osvp@N3Zf@1}0J@>r8}M#(*!D z1`nyIueyn>g`EX4z8&TKuN$n&;%A#Y7UK&YwC(&zRu;i{Gr%U|V zi#K@jS9|y^RT{l_$(o(p^Rv~KYDORTAJWBBAOGm76S!l&)>mN+A1AQp6)k9JNK#NI z?d@ez1ii*%2Zj~<$C31v+(|T&*5BXa{OE`Lre`Dvw-1$%se}5sZ~9z1df=z;zOc^T zwSI2FhC%2RSRTB9{BCiU%`p~B96Pn5g~i5}qu(L^;q^eA#|%(%oaJg&@%lS6#Ou@O zbJmnO()MjFm^kQ1Vnv#WZhc$)OHu~wnj18FzbnK8`5~JlwawLzq0zI#pWIl8xZA8T3sCZ4XD4=dbXf|FSqf}EHU{=of=?aUg^m0_J zq7J3(I%XDMv$jX>T8t%8uNy2_gP!A~lZT*{ zf9eiT4a*Gc=?aPzb?`l{;j#7x-32F7v==F6Hh~CeM;?oap=caF)Bf7rz77-+-b0hoHOyi|sy~yN`z)x;nULP;?;VRATW} z^;7I;O}$>6&}?)$C6b0fSw^1XQY#8A2c->+o)4G|#w7_+C}qeMQ;psWf+Jjf3Bt7m zgBe1r5#-%#u^Q63g|qjs-{IQ1pD$yBZn|gZzWfp!{9@iZg~dj_5>r`H?tGZH%El(n zT%ED_%~uy>eDY!L?rN2{PDyD3<1S; zd8g|w#UZW7wUV&PSCHw5ytET?LGvcViQ=u^?M)tN_i&>&V{t zl6gy?v&N~DXDd?W$`fK@nDXP=$+_xe$4Tkf5d&A z@LyPkYxif2pP6MH5Xi5yFuy9VwwylW?etZzd@E^s>e8|&8k_2cqv04j|=iV z&_ZR)%Z7E*X+cL6lt>E@KdFYOpCNW!Te>QqrF(dahWcAB&lK^&*e6ZVOBX3#x`>bx z<$0K3{jf5xI*Qp(Z_a#eF+VD?dY^oqmX_YLTPd2MEqp*?TA!imXi+vIef8oVlcOt4 zO&d@~%!kyGjKL)eZu~Fd1k0hqa18jn?ZM znHW?#Ds)8k&;tXNV;a|riF}2a)}Q+pziV@UcIZMFg;sP=Y6y_6z*UN?KmDrLVSMCiktEu1UIk^Z21#nEV-L;CdxfEXWmBiDEF|P}=CV zGELE*`FWVMc9!MVJbmfL2CU}j3~3fi?>>D#cyiP@;z#GV&Rc0k-uH5JI{s=Hy9@v6 zQFkQfc*NCXe>%(A-0k|`m?7q~ANv!B{fV$l)#hW`A5+6jaf1JY&2m);6TR~)Bou6` zu)hL4?ER2gU65O09z9N=EbE`Vsn&*5NNT|2w~>NN(SgcZHjD%h$(_oQdUxOAwN`g2 zq;dRd+Q6JWy-CDidaQ+eAgqoq5}ZA>cW+|v%3<#!^ty54cQX{{qJW2+X8lf@BRzi>~1Eo&b(!c9M?aW!EH!JzLz_ zy%!T~k>%OmSTS{Nd)aS11U5(r`%T~3j|P?OEX{Wo^x^riL!$MFy$Ls=YewXyH{i0# zP&OPjR|QeTQFsFa(VxVN)|TKA4)Q1tLcS;xOb}Ef_-p98rd6Bgb^YS{^)J@%R9J=Z ztP17O73+@>)(3P5LBjgRSLqua%fCCz|NfDGC+&Er^Y)h}FY9>bvbIm-P%GjS_&1_~ z{}CHt3bqO_FX;e=Gv%`SiAbwCP!ACZ#Rfb9<3m%dlBy6I-drHlqz*I2$$q8B`uQtI z-#h2NeWLekHDYRyZ@G5;&W_U9K@BE6)#Bx(m1|kUi`6f%hEb9IDn#)6&g%L6o;KEK z=qnL8Kjm~ySWu3xuL!>d9hpa6ng}Hr5c#fvP)fz5V=p|Jk2wcYWw%?I>@JeDLjc8t zlrJ0t8-jZoMFAQI`(l``V`=BRdGS?c8ED=-KAqLD8J4}gU^B!;gH5c zjre)XqP0HceRWU6_&!?Kd3zr=ZdK|}ztQN3Mi+oaFMvj?qZ+E%YZDH!DuFd=uZ{Xm zc$5HTgeMs5xw_?!{F*2jNV@Id;kSDye8lIDZ98uVc`oqxsZ?4-TwRa^_lSH}0+wLbPG ziUgq@@d@iot?FkrgHBNDDCXG)ipmP#1H#qO5bw8TP z+WZfK=tze$FfMY;su(DwJ;D|g$49&~ns;>YHf*PZIpq^Y3G#^{>=iy6Q^fbb0BloT ze19;yx{LKOg}qI2dy`LCETax{^0IzfU|q*FMOa`x8JiBGouk$648lO8^?`Z@O93IJ zE^nF5Ut}BTC!6izE%B4aR;SA&2hqp}6)g~BUm#VKRQVv{;J}K?r3eFxBPsBv!h@K! zApM1|>GUJ}cSuj~&@6SpfK==^;{MW4s8$nav4;QxV6iha_|u+O26>;4*Pf@>hF z_r(W4*HOmQ0o@L_yu*s*P1qG5OF4M9!?E{BJ4<4TS6SI1{5uvuM2h1%Y(g+KUSpPY zy#KEE{Z{e*MD!_+W$8m$JpXP8D=Tl}(}UsFgj zyhd}#7J~pyNS5|e9l1Sdq7-;5D(s*;77>CjbX=2F=x(>@(v&WCx>!{qZxEs?Q?g}b zgyBfYg)W~mTAIFwh++^XgvgGkRQteqoAmC+jU#vkg`J&%l=Dn$xZJ+i#~-(oX1ZTv zze#n(xtJimF8!{4h%-IQA_{t7L?$&{98u^Lt|$~Gc5S0eWFYL|{dB>jF|JHp3VsT_ z87PgR*T=Y;(B&q*K94SVghUUz;7^Qp-J(ZK5fLy%ceUCf2K5x13>a@JfmwI;?UT&1SWk$;mZ?519yO}kl%k%D|at!u?_+uR*&)?GclPOxG2jyKs z0Z2g!2*4;Z>CyxjDwt=|Lur9cojH;E6%a)4rb{L+6w@-6c?lO~1JKjnpe|@tUnl_s zd0?o_N9k`Y47tyUWhX&@O^SzwD1O8d^y&pvFbqFz9!sn(v!X7go_mg+K4Cq4(00nT zXRj=en&p@{AMiocsAX%|&4^(iH%(6uxa^3?Seuc5^xE;Q)kD2((DF3JfjMswZlNRe{iC3n8hRxVQ@=aiZ||xRk1U27X7LHr+St1lRRSQY zz;}ZRcLu~q#wWzfeNgT$-FlzrUs+x`zDWTbdKNLfPXCDT!YM}zR9DX+Wff`>;3^nP(p$~y&f1iIKa+g?gnS9 z&!}>T#o7ag+Jmot7N3FA3JPIb)M=P|1ZLmB@{DD=#n~{y`LxECM7F1HOX#{VWqW${ zJi4)q6whD-ZvrB>yy=#zX+Q~%_L5Ikdwzo99ntpuNoJ9R z@GudD2kN4N=Ss6BW!~8Al`9Je zpTfFTfX3{Jftx@Z;yl4}01!feHqd$7ctFCa5UnY34Qatft^qru3OI#ov%>!e11E{P z)ac5JWTTY`_DmVwRgnk~BB=zRWxZt4C zWy?w||I5vJFdldG?!M|HrBuzq!{*H3t)%DOLZ8`%WQe-z$A|~ifpr;c$yQ^F-O#rK z)K`l`5#cCd2SgK<3tdswDa%ywmo#~a(j5FH08vy=KNyq8)vKmL;j}=L2^TKIVA1o4 z+QEsME5JR#KM42}+@tmqdT^E{o*9plN+bmmgYlmlh2b#-oqXTAI`KX0^L;m2w{~ys zzPz-}N;X*yWqdMNCm$n~L%rPh-B;KtUXz__DaN`O{Y~;<-&0>E&sc>3*4dvoe&jC; z$&2(VXjVan0Ri?MYPf~AYM^)We1m$a50fZD8m(1|PGKa)q66dNl;9Wl_WPb6W6i%f z&Z69wl)3HuefT2JYcsc@R5AJWzA24Z>#G-7D*y6I0^gO?;OWM4^=1wDZ>&=NXGrgy zRD9RkNOf7_*_W0$X$F43f(SHOE+^zv%+P4#V5fwQGaR2epdP?`j~3sP7KzW~dp>ij zz^5c&s>KOJ)RvazAn8XK66R?jDnBo-=oLg#PwerJI!n%_8H$nW0%cHAdP3gh49to$tQP~L_OAFIE2=QH@3 zb9ea{Ea=M{%-*-N;%2e!?tfMMX}5uMFK%Cao@UQ1TZ{dag`jyGq70<-kx&&H1{Tm% zXd7Zdp~DOl3q%{OEOfX_JLF$(Tc5f2iS=Fax0>+V%5wazGE_xC*8Y}$W?%=1Vj|G@ zp!IIIYcn;2^>o0h{%r`=w5lSNLQs?0}~w8`RoWXlBD zQorKNmIJ>{vW(Ywk>I%csTKBvkyoLr28D=9uVBrgAi89&E__f5x|9>m*?zr$ zbmyJtpTARZ?B3sB?YR4V>$^LT+{@awa_0{b<$v0-%6V_{)-~JDMaFzzuxcy2dyaqY z-nh}tYM<+HjwKYY-@y5abKCypyGB+Y!FSxr&%eW-8&iEOdls$cS@G+2O^|CJ4Z!Kj>wCEE{09?hM(vrt`JrKO??1h8P_SH3TJh@GZDKU3;-J1 zNDG9K-kUux&IXPyKk=2!gq&tAo2K_{)~soEU7tERO`mnq}7s(q8HNOtU8A z>)NzeMmB8GbbKATTZ;}Xyk6~c9iAK4vVFOl^}|_eOa7yHvQBua_GEGx>(~-!Z?R>W z{H<~bc3TIFE1(Qk&mIsJfYq}HAXOYHx!o`ka1K}>uovxRu&TI>b|MlFX$%$C2#p{& z7mUbg89YOdr>4`vIQ79{(v55U+(vfH{nz3~6ECyq4Ln&=-+o%&G?X77%5T@WFqG9D z%F5M%d|HDXyi4*OWC4+Uozc|N;4Sd~*NThWFX$day@HvRr`{0}3(_O-+4=bFkK(gY zkk2Kb{qu33RWOr|xOj9BcwK-wal+3Q0Q99e`X)2BgeeG<6U5>tCW|(sC|pJr_XI=w zI*q-}Gt&4#xdQ(N{lWS7tXixUwFBMp?rPGvQdHNj?(^=SyLBV}H@7&Q#pAmk=aaO> zqIw34@6xJ%M)HZ1D5nUThs7^70$B&+ERzrgoMD-5dBd{6 z@+PZbAwxt?$Z@`s5H8lK4gB$KAYEPaJHvjTn}^HdIk>c3gi8|{oFdQed{wBE*j>~M zC?(X%NrfnF=eiXIng?#XP9c?4=?XKf&{d2w=5#J<6gpelosA2fPurbMbk;&QV+x%k z3!Os?ozE6Jo7kN%7dkTwox=*9%?q7v?9R6OTV1Jb2?)>@f336K*}l-(*6z$GbPgzV z_APXF5bqsS=p0z+>{sYa#ZX?MJ$MD=TZoJE6}$5VJoy3}z0>l7{e`F(gs_29KvB#1)ks7Bo?As*YR*clj5NL2<^f1I9Pi_EVOUUHYMVyVt6bk zPfi~^d2&X^l;(TWGiz3@lRTt1pVqc%(>86MZPG^mu=mhTy@pt&7n18$O}Tey^dYtC zXPJMGU`dD6>nu65sQ09LNr?$+Aq#c)f`Q%}!nRb&^q2gwHIhY)-LPRSzqp}j=Y|?p<7!KCo3Y~Gy{EKqkq=d^8Xv_^7EQWe6moBp z_6tWDC%(7)wC!7;0nn8y!DfmBU58m*QI$Z7QZz0WKU_j8kek_8R#6jB>$n#4|A>1J z_^gVhfBfw3d7g(9NPrNkB=k-?RRt14uOcGd0D(k80!e_#MX;bKh}gXXp(A`kfi_XJl+9o^n>ZR|p&T7%=@-dg(df8>cjLZR9>7!fqo^t-wyJ|++(d%HN3uMT$>`wMNtQWxB zNX8jk>u#=Q_Sd@)t|OkoJnP#E(Vn&HU^ItxsUX?n)ln9iM36#QZ&04}{|uQXrd$iR z`<`o^+nf#8A!qu`^@t69zvhXWYH`YGD96YF#5aLcf-N-?G{w>md!mU)gWr*Xyiq=D z5vDK73(AJ@ZpJt2O_u1$!}nG^b9c=mrR>gMIk!6}AAC@B5LX<{hn`)DIYkua=k=jy z%?U9P8&JHl05+*_D=b;p5f+a?2uE9qm1o+7g!EfHgE0AH?5I<(o%sIS6R&+&archx zcippn`&}{%(e}qh8jfAe#eeC}i_T{W?|=8*`_9ep{`iAAiy*o7-{P0Ren^lxr?Z+4pwArxDxTKCQdajmuc)j1=8)b~xq9aOXZOKxA|J>*gfKE*nRbV6K+hX8oNKh&rVUY z@nq?>-grWTM!k}HP3uc?c&$^3bn{C9Spg+w!^KVbrso^${)IB|>KHlxiHs)Qwi|;#@KY){l!zic5(b z5H~h%W?XQ36+5-7ydwz@#>FPZro^h!>c<JhFE$GwjBA|KIHj?gevmc~uf$Dt zE%pspZvja4CG_VwJwBd@yDj*0FfK7EF(r}U6H5|T;%5Jr#JyxN*OIM#oc>$_IC458 zfhksv&T#2Fc>Ij_&-nHX#lIzo-zLAG{B1Jcl4VRiOnctEv7#|EmZmVBkUFeaV(-LW zS@N(9Zd`Tc#*mygW!8*ov!@R}`|=*0du30}?Y*W)r#^wI;MDT+slfqb$DJ+Yh*{J7 z^^6-fTZoxLoCWiTc>1AyEEEJ!ldWrrr}4~FT>g@y2Uo_ekJ}Q5Bid`pU0;X4$aBdI z9uRAnRnahEy=I-6^E8i)rS1VytZV&Bpe6A{WB9v5|A@4-mMX2k}E$T zo_G<2om{thJ5dHk`HT#1x^i_T5^znMHDgBcT(uJ+bHT}_rIUkaj~RQ`(*b15MjguR zkL6FnLs&s;Wj#zzia6aDXzD>NCy&$LkXL$CTqr3-iM^2YRUO}dDz-Kj?J+a9Bz9#i z+G8&!B5tohz!GL8)hqF5|EaiIOkxhsj4O#-8Aotv?Sr~=;pr6SHq|R>f`jQxBc9YG zx+NYwp7?&^w~3Hu{N}am!Q;)}Z~kp_yhVTDV;@58I^q8vGJ3OchdQ!wLyNF*|0I__ zb8M*;^$TB`cxJD%&TV@RoY+5gS*Nxs_Lso}2ZCR}l|A)*DbMawf6zQ3CP|suMe{}- z5AFkRnpvZWH&MEM|C%SnuPB%LaJyACbl;)HG_k!inqt!hd3=p5Hj#!<=gJ?%=rgAe z4U}JXP7X+X=%L`(p>pTZ`~#~&%sux6zn=CP_%qA?SUrRM zOH}?4TK0?uf3Qahr{1$$3usNoB?t@NkefK3oLgu~k3#^8N{UK}8W6>0X9P5FL`JBc zxUgJ=SI;Z-O4T*XWe~1&| z{ut%za~q14gzj4sy1H5?rYiRF*yFM9$9@|dSX4ceRLoeYnCeqT&m_1liN2VSl#r4z zAYp96%!EJei|sn~&cOUKaL2XlcLwE**+m8OE?@kJM0{xQ!Yfx728W$LWk~d^Iv2sM z_Ce7r*c3LzU&Y|`&Oj2;TPF?cyfiT2PU6-_+(f>SXtaZw)xEFn8VI&j`?g-^OWY; ze6_y$7QE7zQvY_b>Uwb$7)o=xzEzCU+*(Pghc=sYH} zuef2|#r2)XPT#ue?;B6s>o#nhy5@`~8}ln~mq|`;SyA3nd**_|`4_;ZSXp}tdu%GP zo;Fn1?ayr6s(8I@=5x`|vRT9v{;)R#6`KIKq z&9^=J$cD{#ibcT(j)Jz|Pd8TMebQGQE!im^jbquPsqv#zq9b#bkYsX_49sJZ z5}}~x0lDS$7piGZo*X8-JALNZ>++pKv>DOz81rMnU-Sr^*h(RiaM|cgDM{oB-P{UR_af zrFdkGbdqI5dA)32^BI`;FIhiO^J2|jv)7pV%q-9sa6PSmIEw6xSU&1NvYsK5vFBXd;t+{!L@Pg>52e18FPTVpY)9zq5&@^+yqr{USbW5V=A##8RF0h zgA*?uON7O{XFJafR#e`pKK`vt-78OzhnMB_0MOyeD29a_%IDSO0 zKO3KgJ6;TQetzSm^RuY;#v3AL>63TvKJ@sVcRns&c*{90?6>}PQUsjePKy195AXls z;Nd6l*K}QP{~dJE8J;Hh9Y!U+AcJ%2vl~aJb?m|QcyH9-5dz?^-$?mf&pmtG$1T-kARr&U|RBo5pk z4{eLS;!7)B9c{HF-4A8z%hP~NE_x<0#rE^89eOPM(z4iM|tTY7)cY`a9|@ zsc^1P7u%hGJ85^$*E(|(`p~y*G_{b6JvERy26M>aIEATk(nz;Vk2t6AyUh*y#w^UChl74h$ zoF-Gyj97`MnGV~QI07M~F&%_J%kWqN*4>Wh}CCD5BU4IO&A2((d~Vtw9j0)J~)%h>cBHt6~^!zb>v9d@slcUyVH5_Z?}+y5CS5rY1gBmmbM%}qoe0{_nC|dYwbQw9-Sv>) z?VlHSuf2WOmW}J~TPOqne(b5QFI&2HO|A9JA?F*&@RPS~seb6*wW|5%6<2M)V|DPZ z4_|+5-hu9&9$fL{yKg=bTwAs6mfLRB?cM|J-U9WnXQk#{6td0ukLVIHX&f*zmWmgr~=5W=yY2{mUEGinnTG!1#k<10kBeDK~|0vVYiH zWDK7aPV+vj0qXHC-2YTj{^YqAzPoSxm*`d-mS29;+N-v0yL|a&moB_%p$xvgt?C6e z`MkC5lCLeStiESkaNg>bg^Nq(EXtp?eA%qvHG5%ULMCaf_z8W0;^j@|n1~V3>sZp} z5m2W1ZCo-1gA{6sbVJqkVz_T`Wl3LP5gUVv8z`@uzV}{5&D~Oty`<)GaV*$U6y!UI zejK3&o_<@dmT;UziiIDm=VaCkfi$U0tsM=cB+3GLS@* z*XqXl1>y&N`%q!UMh3JsZj645IFsJJ%sR&asbgMwH7c}zu)M0~gKlYmo4)(Gr(fLt z9=Lt;@*CE!K~9L)(vs_noYD?Gl{&Vs`ju^!!O((>ZdkkG#t{?>3I47|eGYOz=wzM$ z2cxE&nUHj`@3^b#1_`W-v0Xl<0d0NsTT4~g1{rB4`NEgol~1i9+SB<&#xzALr<`Hy z`#0~qXw2G&(r%x>|L{lqt3F5ailS{Tw1ox4-bq5z*&~ zf7cwJIg`5BoCJ+c$sy%dU;6x(e~mss$U? z?!2c&27Y?wkq>UY(kYShn`!clTaHazea8bEf(K8ZJXrDb-<^Imky6$|@V^TDZwgyA z#XZfCvkd*NfA@%LLjAi3`gaeS(e+5_QO8PEEqjnu#r0rg6=tA6&j@miMV?*f>&dYD za72{0{uE1b-|J)kh__v_jN|@ zCTh9kjkRvAUAc=G-9ia`gm5UO+78iOgwP=jG(zY)&|)J^GEBX&U)WtEY>Z%PQd-be z2nPM|ihI+yO+Rq_qy5#N|M+0`x}3!Ri^nglOy2&t6R`@rJQ2UZ29{<|`OWr?pz_3xfuDIylfXttJ?v(uL)0Ztff8vz$N6wxt zgWD=rZIC1T&1jyOH*~?W#l^t^<3ztEJzad_EIXsk`2&{Ua`VO& zy8?3d+=+8$&YU=5N`jan4$u5H@eHZfFJE@ug89Kv&M<7=n9;K<__`K#`I`Geo8V8zDJaH>aY~%*RoFGL%eh$>T-JW^$V;!g z>&jL4K5@~Ql7=PcO`bnpb#K&gQheOv8FRa5TwPJR{;t(;th(D-bY^rG(B-^LJhy1EUY<;usjYe%(d$uV3JtDSOMOwtRGS<;tf-;(Tm& zrmyO^pa&Tskk{&C2&;evUk}$p;T-jrNk1ajW4SkHOb_W_B zZ^+-!Cd|ev8fe0g;Oc)l(8v>`2acSw=dv~TO&yyv=Ju5p+s-W?Ke?h}%7jHNW)B-T zuW;b{JGn%)YJE(Zsvf}Lgmd$6JHLtYP=`iS=a|UIP86)oNH#GOmGl#)=q&~R_ ze0bH!&NSax<8r~3oqblA>}qeU*-xw3h_G;noG=XSJZKw!#Du=?kP{9|i5zlnn7X9h zf&o`;yleI4dmgwty)Z4I>%;-0FH9(zFzLb>V=tUIw`=!n7ME_^edVc(D;qXEzfl9x zu}{}d)0bR0Y}5>0r|W8egr4bc)%6v+b@IF@6yFr4kvv#FeaekPBcvYs5#zywqA|!+ z%%1h@_wKp&y1fe)<>eJG%)4NrXnA#I<<(!U-m+!2m{C+T z$SsGh%kN?6sg9#RV--#G=`IC-{Np)Fhc8EdP_s$S(HjaBVr%BhQNfManHG;I1FXkj z^NpP{FzO}yJ^PehYhy7sj@D~enm?u0TWs2CN{=(~Xa87xrj6E0LRfHBc)KFPK3lje zu~qfFJG}N5Xh97HLxl9Km2HLIJ~LY!yHp*WSuu6sfXR~w44gVRqkX&d^mgqtf*XTR zy*Oy{#W zX`InS(P}VOZ^hr{-tp3zHJ461XRUpW=-b43V%<~EU(Iqo4z})jh4d z(2_*C+R5h>QQL^I#y2nWCPX+V(#(k{Lbvg8{QVE7M2(Q16cX$OEa^GX@$vFV&5qu^ zuUPodC-1(yANdjI?^?TK+xF|%-qc3ksLm*<`FC1xrE0B{?>N6ab2ND4rXvsSI68R> z^K}>M(v#;9kzWmcv?9hDdCSNf`X=>VIA;56XFjy($j3h(dB*uo zw7&DA18p9^<%Yd?1&+2&o|WAC^b41cnc;l@<{QrEqPqx)lGEbsnhh&v&wu&*Pwv?J zI_f3h)wa}qXrst6$E}qsEj;Fg+XxFP5J)K%qS+fYqP+m>zPCQ>6tgtC^S_=w{kgg^ zFv9t~<}qi@vSp%7P7*;Z^I_~c(;1<@$9^3;Lu<5kla`5Y@LP0qgV{NLoiajni?2#K zUX>ED*N9%`xZQMrTuxFBhHn4rZ^L?=Zlz(0f44?;>r~oOUfsT44oNdMV)yk`1Y37U zgdb6T(Q`?5;-CoG$M$2m)YZ@`A%LY4- zWZhT%)DN|fyy`eVyfwOVSYpl<1()sZaA4!Q`|la|?n?)!&k^-sJt2~ue>%T96Kb3< zl3M4tX(dBf&RX))+n?XD^=&jI>IBc1`jvfNjotOOKU}}6w%q)t{qpbtT7*W2UE0sDG2ctwb zQR{jhzV6Al-#)VLP->4Qc?C;qx>RmndB+(oHeJ1Wi|BP*HS&2jp_HH18%5um4{JUa zwMV}C?EbO$)H=Vt#Cwa@+Iu9<6Oln{6F;ZPe#mXK1a;4B!a{P{Z>e8MjwU1ig5P|9p`N)iS_G$)bHC5`b`6EmoUo8x-sy z?YTr}(k2FOXyXeu(#R{Ey}kBV+O*lZ^6IooV5D|v0% zeeg~~gSi^Es_S^UgN@y@6nvgy+Mec1gjSYD!ncYY z=vFrJ_sqm<+I_JqU}IMf?KjjgNghm@com1k0VZDAkuVt^%m(XSF`Zx<;F!M%Jn0_H zR_j$UkznHL!UR2-0_#3;9;D#D`T^jyj#rVD!4BLX%dXcgetERfntDIc>p1@Jy?f|_PvX+Vuai&8p&UCWu$;_`# znqSuUF28Vsf&Ny*5Wh4`nW%F4RR@OnrC~N$4{LtK+jU@w7aFF(x=!;VK0v1>#OuA8 zAg{Kz_GeHto#`UC7TU3PgQg3?k1kyZp^+&eqD#Y+S?6iG>V;vjTrYcuh%ODYp?0>W zD`+c&r}iztOb-!V8m6GOkEW|$0A<15RYmF2m@ekmsSvd}wl#pRt)iLR=3YIQV+{Q? z)CVy5h-k;&pmLInRw~-1UBhI0FlFMDC?=TXx-i2$m<`siqLg4-+jZ~^^ zlT;U`r3X`By(H$7TqOs9rz)8;7`gSMdC-H*_uhu~Gd15Esd_H$8ix3;Vamj>n(v8q zVTkV9@xXp4)C{ownXWQ%uQ-S5Szm=* zy5_+yJQny6Fgcobob=b4V7lAQBVpe4V9LY=h)M=bYF(J`4NTD5FuxT+^bBY$Y)9y_ zzVl$VUXVaADZhuIK1cKft%89~i0i2#;HgU0DbYzEF|J@IkEYGmGsqeT$Sk6%Dl5LK zzsCm+>(x=bX1#`}WAyueieUTkyb6B@(igy;=j5sv>@mPii+|Mbr*OYVo;r1$c{SAV z>VW1|vhDFx!w|1DOqnRtylP(;hImCV;MEG|Roj5Z!o1RWhz}a3U;^`@eF!jB?U5o# z(^~r!Fmw+*4>%+q+^S_&v%Di=$2Jb8v=j8^LnA*_4&=PMcxd23s`txsLxxMBQ6g3ng+b_ zVk-Jgv%m*{8Lw$a8=gTht-`cxn0GvwGO-$SH^3yW;~t$i<&E{hUjYXI;3~G>5F?28SQ>vdjPA=10!H`K z;yFfm|Kqo-12 zx-wjco)I3Njl$MrWZSy*{L7`YM+5V$cTw)SgzsZTbFmKUwhNM5u)D_+X- z(kAHBdD>8CxX)-j^*ub5;tD;E{*E5fn;K80 z7zRH&@Fe^2I2HC}mOIcx@+F|l&?l!k`_*xlJABLUf3nWRdtEN^74V>KqxFL3Ys0WT zr}^-MS1z6A!sD%ve#*7{Vu<9f3**^f{ifxmUD!S;L4SWeKyo+Sz+9^3rDs^5X*?4= zJewddJE)Ew>f$-=;n{?7WR&iKuHNU|&o72Zel1%((b%7Uv zW#wY$1j^mw^j9BpT}GStZJgKfejnr`6nq~zdos>4>nzcNa7Kscr(3{7J2VY2h!#e< zWvK5h%){{9=aAFi4sp4_!{z>s@n7cj7wx%Rd`s_Zf8_ThmmWOnNkKb5jGlD;6=)vj z8Ok5dJmc~K+cvCIIs7?Nr~2?(mEv&CZnP=(^KkySdx4A2By#IgDVobl(w7>~ zCTMxqm&sv0r}13i;n{|WjZ(6-u&E4|R+3Ix3ARCQ8DB8U!?(@)33`)Y$-a$*MSgAj zIJYUbDwF(*J9L|NMrIGAhrwHUKkF?-*szShtJ}1RjROm{o_GXpdOWZfWdaYk-2!gA zi<|*+E4L}WWf}k4c?&e^a%o)Cxn zxonqp4QMQy9{6`Ecsv3g=&+^YPM+r#IKxyW^8w%T`@yxpfe$mCPJVdw-zCnIcwgXj z^~2+RL+2>LbA8EP({ygMp40Z4uP&NS;+v*(<6P!jcR!syoGkK#0;ZQ~uL9>d@OO05 zygyIBw@x^e&%cK=-Vcv@Ax?ndN6T$tc)SlWAE06F^`TUaAMZ9=kBBLx7wd=Z zmX7d&t`4?kQ~-syHM{3d3^27ZMYRa820fsF|`6MdVWN@N6&q> zBBL&kuT9C1q2-kE@c63n6kCoSUmMrOL*uK)Q;gG8czkVQEK8K7>7nsef%ma?KaGRl%lZ5s$zFnAvW-P)Uob9bWS*ef3;)!hR1qjb71G7o{oQ8(|bIWV*!5BFmFqaw_C2plQ>80Y`ww+pA4j&1% z$!f!&QOHO~FrJ>T{U`X0J@K-mxQk%KiQ0v=i=d&a4>d((Q4->0t5fK%mLq1lZT>gk zxO?AF&Vwi?C{B$080)LmRtyRlM}Ly>hZ-OK2in!18i4I5b}`-A*3)_}7aO+yGz{uy zV8|cCb@Q!XXqaz381l!k4cQ>P4x(XBc`&568WE3t>lYg4uz?|;O=FVUc(STIkG)HG zu!Dz-bi@RL{DZX%#!2?ArXN1cU*T~`u&P_wNGb#84bmjwFE3pXPgXj^D8B;W@8rI} zR9wVk7_FHfVqV>Cc(v8#l_yUchIpl6%ESzpS9M^BR|JFcwU9X#Z={mjMdKkpXqbYt z4IhBT$A{XZz|f6p+N)`*EzmUi)-7nJ!2U@(Qv~IewddAzS1qW#+L!UmY4Y(g49zRj zbo&K8`=}N)$!-CnNtabn8-yPaJm-4LE(EE5Wo5uWe{N(1!-kR%f*K zZlPgbH87C9`R%B7Y{B|{n7jv+e6QjmL-()R2KTL5Xc&yq2Bu6rplvbVnuUgeon>G) zScmnz|93F(s~VUB%=_50%Hwb3ng!V+Edp-<7PEBLR_pUnfv~dotfJgC!dSnM|2)?IPv8XD|kMG|VPzEvy8zU57d_0phKOsT89$ zo;KmR+DfOVjhrAFhUYocoM)gLiJyJA&+aiaY|?d%_iTmQYoI4OaNpN@Vry+j-SD1iUD;utBiDxAKJXr3s&rl0IsmU48|k3>I=v}J24MElSb+ISl=BMS z--fYZ7R`S|HNK^Fp<3dy>oL)7>hz`j6&i-VwZ33K40srR&+~!y>K%7J;BL1z<8vKY z$W&HMebm$SWl(!eCA-7uS*%n3e!PJ{2)QOS4A)_?O9#FsnbSIYqxGyFJ6x%wu@F2O z7$M*9`3D$=WlqCvvbJcM`<;%4AI;#|hB3G+X;+rZst)mp&UNiks#625 z)BW5oWgKINt&5s0R%G1zJb> z=F$wqeT`s()`kl1XoOB(-1_%B&6`S1^eY#=`Y zU|^$ho5V8x!yp?+1K;TPME?c6T3p|+2lTi>W3?WCw&MI@UXN=Mp2KSx_-qVJF+34$ zA^YZk8s@YIv&nj1`(qNrJ_UvecJyF2i#G65pxs&$Oys;x!@?h9%G@S8X@ATg%*8fg z{6HQB4a<6P1@jc%y};wFUmoGM*?_eL?zt_LH%HRr+*kOP#yPZ2K@;kG^-VMY<7GmG&sS+n#dfI zuRCiI^$(gcuL+Fi_g&5V@%$chK5-y89`N1F`#i?qA3lX&`F&b~#`8DEe>3p3=J)+I zyz?5vpO12n^ZNsU2R(n+^i;u*ab}QweA>RatG0ga0~8C8K-=(Ah!qQ5yV6e23?BekPeAUr~^JMfe^3v>)PU%*FAHzjhTr z_oL_kDvpP7{fF~$T0dMC>;^t#FvB>1rzl5Rkno;%Gk3l@zxEsTNw6zmv<|pabgg|; z!+5^F%}$Vw>-iKb1_*1sMlERD@dF4ub_{EGkLcE?HzWc#jh z-0CfCtT^bkZ~Dto6%4-}d};|FNf5RN@s0ho@CgRV?~CW{&IRgK{=J-^vD%>y^D`t5 ze0>NsodrI-a#m2=3<8MWn-KEk%pEJ3Hip%-6~HAz+9?EWLE6b(muDK77odT8I$ZOD zeZ{~Ax^z8>7le!Weim#HaHDzHhl6$P;N&2|JgZ@3p@!*hcXr!`brpZq{1*sA!YeS41{eDA9tosZsm%Xv5;i=BJ!eNE&qy|v$&kMG#^%CGx_ zH$1Yby!ggGXFk7c&x>!r61?knC=~F!PJjNd`V;&%Y9IGSNDpuk&+F&{`y1vfdNtah zOl;MBZ5;M%^hG~=j@J&~Vwg?V+uFD3i~IPWbQrfE(}DIgbog}|(RGT;IH}9Pb|(|Z z;ra6b^EDPu&*K7Z7eAwSyw~tri4A%hTI0u3*EROX+oc|e!8t1@i&fVjN{_+AI za!mPmP>?@C9XE-Gk-Ep1UrKM7z%j-_4(I0+nEXjAWy;cn7s|k|x4-k<_itDK)0Xr1 zuH3V0=eVmb3f}UpNcpDg*CO?myMvc){P&|>AOD5x$UarpK~Ny5Ge!ippP#3MdBW=* z;0bi#pTv||JMi7v>?i%4c~xe8rTwJQVV%qC7R;N8jQd_d()wtStP$ux%!>chSg~5p zk)1`ET8~1mPSteL_%WI3Di9s@_z@Yc#r5QIIn)ZU=oM5?#Iv4H{EG7C zvzF!;)sy%|FjxGpp5=D7g|&4>o_KE!o431#*LGIg{lyy$V*|$Ig>+%KQ}E>m$~ku%m#dOdis0mZ-cK1C$V4$!m>c4a{qLUf4A(=gH0%`#m0; zVgG^7?TBkppkbb~MID3ubNm~n?84b?5hUz4x80Vf3DO6Tlbvj`Z+<5_f)zWnSy*Y>}sBJ~kX@%)0S^h-20I zlH^6}%WRa+{USCTi@Y3tCyI6Wex~mtCl?FuWHUX(&u4(%mqKS@KGB5vyUWhd>o*Cs z=0H|9?S(-VQ8!E%Y@`_hY@&u$$E{9e1vR5}C2UcwYVE;Jbw<`Z8+w@6;K84%wzk2R zJ0qjI!^U9V)BC_I#y!oMV9#c~_XhD(REjON2T|r6=Ulbj9*H`BW!`7i-jDaI0PlpXW^Q#|7j4M1IfxkNJT9hwr1o1*={;qml!uInao(jBwC zHTqWI?P(sbzBDk4^?21P(7?6P>f%iX58q?FkX6XMFW%DAoAWR(9t+fHxh1{%NAZ@7 zhxC-jjyns zP513Bz@__kF*2Z>ssqD#*#6ge3anaP=Z3uY8e#uyd{k$`2ig#ZiyAi!p~NZ|611@m z$n|C2h_?CjJr!(=QQL5w4RHQREH>jLJ5e;|HuY>cfoZ>2ra&9xcjoa|V!W0Iip6mw z>BHahIuyR8dW=hDNRIz@A%Sxn&P9EO$J>t#&euc{L3ZT+(b2!QzYzWHRj$Wx8s}h^ zv5w3e7ZNzxj^}pMc6>2nMY!FX20dFvkKq*SKx25&Djv#_4lV@OLC*(BRyCdiYnLml z{wQyT)%d90G`>HJ2iG`BPimaoL@ynmkVN(m#VCbkTH~bn1i~4@8F$t2zJNDLH2;i* zh0SQ+$};wj;p5Ai)@BqJO*%gu_fQObVKa}zKWaWEv5YkfQ7gKT;N!#4o8REfl#bSi z^(?EC)eXKXZg+8$#(f6w-$DFEm}c0j0qAFZ^DFvlCu@yuEoW8ev^82p9 zJAuFd#^CMD?~|RQ5q8LK8?pzy^PHm*cF1lUx(x4=S%+h7!szgw_DQVbLJ#=X#94O- zmjH(JU&z{N=fk1{jBoFc#~#QB}|Qs;mf{KY2K} zhjG%LK|fBKE82a62RxkH{}Shq9?ospYt>8BX>dl=9dsV_aBiFTa|E4U-KiZp#-<(G zw-eUCutyTS=k_GtGY|B*!);6J0MtH^PVA{-NO}Tf#NH~+)8{-|w_5)Y?Bn*L4#H~_ zy4}}!v~DfrvBYbq0e+s=i}i5cVZASwQLQ|jbV>|}AvxrBqVh?Wg5r(^eF@UTd1eGo zidjSbVIOY+&f$NBGt|Jtxn)7UzrdN`;oJ((9XB}v6tnL^HRi~g5CE0Ry6oG&3QUvPr+{cQuc>yyNLR+ zwu^S!2i$(_#UQXf&;6L@_0*3mbU*g(OVfDLJv>{jDzgW(?j8-S<@271ptZG(_vf|q z$0HG*^&!#+Ob_(IQ(7N1qFBMIMt*%j_RTr0511~%UX7e8kP6=GKx1#%z8Ma@lS8Bv zG~OMs+gK;?URcsIo=&i0A#2B3ClKDC*zq^k3A}%s2Ar2^!~i7bnLe zlVuXdNwkh+ouF}U{|lUxL!=Wl&TZEHS|@lo!#Y8?3+V)nbK5f32_BtXd$c{v1nUIg z1YX_;EJ!CnHmIljVy9V7SSJ7{>4X(pCqP;VGGY(mF>vR{5XnwAEf;F4mK|SQ&8_(5 zNRVQc*BBUg4cqJv1bt88fbZ!%)&URZRlC)6jwij%c}b*lO#DdmK9yy8x$~s`DbKe^ zIZ!=*t*rr`sm`Nt{?nX!ym@~u$J;Ik?>`OETvLy`JMAB^YZA5b#n7-_7hJ5r1#foR z*XVU#-(EqDhiqiV11misW|6#k(J!4neMR`@28&#Lkj+YDpdwgWyRX9j-Y~4j`>=<1 zhxIe!V*$&1imO`t|ScJ<;h zko%DEB%>}GPqr8h&mr)1tc!>CoN7GT?w-?*b@33dHJ+V;c){@}b@8w~YCN7i{ti!y zhi5A?l$=BKbP30(=z4wY(c|q)?c(E)b2M-|I7Q>({&bqhT;lPYHs-oi7k;n%(=O+5 zMBMLg``@(=`riiFif^!OImy6}U_86P+Xq=s^wv7SuGMQZpo^V+t$EipJv}OX&zeBF#BTLA`~JV_YFMlP?pA%ExKwS zR;#*rNM~p~6!Xdcsn&Jzkp9zncG~~c^{R`9^`FM$)$4b7XzbK@wpyR-u`|i8Q?GYC zdc1h{Her7a+9j9~?4|K=dwuS6E_uoYsjorH3a?$23_7}f3 ztvqj1i)nA- zfVK!`UWq?i7anpd11-7DvEoI(O1la7(H%~u-G$p6Ya;Ys!7fFc6Z~+7?`q)D5O{w( z;QKK=c2Y5XCcp22_x`;kmEs3}pXyYqdl~+F4KH*oOMk#0V*GlZTd5vo_;kR(#qfHb zTPaWQ`+EWZ6T@Rp&*h?g&{GWf8ixN-zn4FI@V7?5>o^C3-y8woo8cb@{!R>kkH%xI z;K|Rv&WF_!af1=A%9QB+(c-7M;@x@9)i~E0Ju4tl z|3qt*u0J=LTYo;1%6)K?XtCC1gXsw z2`W0pe>xD(7s1hbRiWe6jrlMKlWoh0CLe5;(Ny3(RN3g*(trG8DfY^pdRm^fTGs58 zSIBGSy)_f;O>_6`nd>Z(n*%j{YuaFGNWeD7`4$*U60vKSiREgzJmm_y!-~t`I(3rq zG)OdvXl+!1&${?uRzVzCQ?Yw@g&6ESvO?T&jdaF}ch%K0uI4-YhT zG^GCbXL5rYv30l+9R`HsNa%>VP7o*@3RENxuXTFt`8>E();#I-Tq{?rE~j6c8&mVO zY-!I`G+!0&dK_X7r~34PD?7ipLMYiPWz6$VB%lX3?W_N2%Id)}IO-NVZyI7=8K9(c zOqI~*Rb{BIKUMtn4`d^b= z`~->2&oI66kLVr!pV8a?MKR+V=XvM(YsHM?&pG$6Lv=b_>)d}#{NmITFE|zXNcz{j1L!Ze*ybpqnxPS?v&&G19DH`Tjb^*BCe{k=FT06 z@tnqYowbw#Hyz=X~ zT`1SGT4VP!j~2KGP3B&}N0wynB}(mP?iKd*rJH-(2NQr!9AVxE@%{pHAF`6IB6A;w zH5fYeh5i=ji(XOFr=ioJb6xDd0z7Dl7$zQ7S1auPaaxQ zGOs8u&2hX|Mr|+vLL6Rw6LtaFt0cnSn^BD z%Swtz70%8tF3X>jytsHyera-fL4NX}g?Y1aF~4+AcIim(nOaa@zOY|P%F?Avd*(4z z&yv!4DMcDbS<0y4Ik{sd|OYC05#8A4Cp*y@qgRzPrvDBux4OGc|N`> z12&>9871|^f2mw%Chq!s6l6qT>k&bLpRz(=OXj+j19KkgnvWFuMB9A4FR|w0ub;}E z5l@l75O)?}v7i876W((C&0{(>H;DFfyeHa;BePLfF`n~LYBG3I%%zv&z8pA+n}fjZ zJizIv$Zxvi_qzN@2R~A|UCQxgKcoszv6k|`p1>2v)e|(7q8(Du4t_ey@MaX!^5kH{ z=ooA;%|)oW#_4a*aBHHMOHvfjl^25eKlq;=4`n3*g#^FQEFt#1L_@R0!sewt3h@{l z8bP-tAhJFYF;(OPXn`3~E38YjhIUJauc9qhR@x)87J1S;BePIfXu9qottZIU;+6r8 zn}s;`-c}z(%=LpHoN1k9osE6;1Hr^>RA?|NGX#w{4AmO}Ykw4SL5;D-BCp7Jh{^=) z@|XyAPQuAUld&E<75lZPTQjVg(2;qFa$JQNxJTjB`5b5PT#GpGO6yLI3wZ6khaF_KXcH94iSg-4>Z()!96YCjU5$Ev$R=K|s0c1%FS|3^; z!HZfCBgH-uW$hHv@cG4x`p7sCXPvY@u->-*0nPe8;)dT7@uHzqEaLY{*;B45lE^F#r16I>|fiz2Z=6pIqE zP%MHExJ;Cb#bOEe%2$Ys#4_io^(7ICZiJFJflVx!oE8TMwe1rg8N#CEX*zWh6o7iyQ-E$&2g z`Q73k~tg97{_5Yk%_XYY$lt_7P6&m zCC`wpWs*#mZDd>7PPUgFWJlRac9vaaSJ_Q=mpx=p>mHdRQ>`y#noO4&*xCFHJg9r1 z-e=29^!n$Zs*YiQz)RRq^@8;xROYMJaqDGR2=fpHbpjbQ3lNEPAr#GgsK+9!SY|=} zEP^^BRlXR?ZV6OWg|!R=%ipYvt>xBAYlU?QvJZT1JtTYK7@j_|FY=1_w`wd$o+;0g zXJdq~6_y+*2gz)iBL~Y|IRxjt50k^?2su)YlB2C(tbfZfa;zLD$IEl%1bMEUD9@9V znX>z)pA!o`9WS*QQXXCh(d^uOnlLfL+UMT0wBDp{o%M!UzE|R6POqR>V za*13jE96CTnf#kvE-#iVcnGd7JgH+#ol~O|sJZ)cQ@RR`5kbyA&G7u8jDQ{7b$)l;RYRF$UERfft`S*n-nt@^0G zs-Nnw&Qxcqv(*4KPz_SqDn|`gxoU_Ss)niIIBs&J8l^_7F>0(Dr^c&u)C6^|nyAiG zlhpZYvYMi%s%dJvnxST@3sjz(rDm%+Dqqc2^HhN*stR?HTBiP{maB`^3bj&QqApdJsms+Wb%nZ8tyWj5tJNB{R$ZgkscY4Gb)C9i z-Jot%H>sP|E$UYFcXgZEpf;*a3O-D=MQv5v)ONK)-LCFXJJl|=TivPdQg^F+)V*qt z+N-M6K2@#mQ~T8cbx_@}9#9Xeht$LB5%s8gOdV2>t0&Zx>aaSZj;g2B)9RRdMm?*Z zQ_rgx)QjpRbzHryUQw^A6Y4efx_U#MRBx)c)Z6MG>K*m2dQZKtK2RU3kJQKN6ZNV3 zOnt7tP+zLA)Ys~t>Kk=ReXG7x->ZMAAJmWPC-t-XMg3d-s(w?aRgH2~Ew)GrECwqC z=LE3GAA*x23JX{<$RSf7i!E_>yxkBBA&n6*-^5O|ezu!hwmoLzs8PWMd9zDPiW@A< zFD)#Y1Bp*0 z|4!t;i|KD@adBa4dPeU++3bR)dHQKcM%290ye0XtqGv_r&0but@5&2{=J1_eP*O6V zK{HZ^)SFXMJ}bYdWNDzhq`0K4{+vRPQwGzUo}%)KOUm<$@(c3mSXI8E1QaJsqn;%jEAe$GtIG|zp_b&$Dco9hsLP1ATX(+qr?!IRe8{NBf0&3EY; z`Z?XeryKZm1D|f-(@nYQrrdP*`yBKAU~|niS3^&Rp(n%CBg2%JVam%e0H`CzFG;4$YztmD$^r*V~lW+u-YM@bxzMdK-Mb4Zhw6UmsJCKBgXh4E{a_e;$!zh}F@8~$XQa{cf>BE)V6<4MMSFR_nOb4z^2d+#9u1p86Ob4z^2d>%m*{M-B zy99&5tfKmh7DMrt<}ZO?C4UadWO{14!Pz@As<>=14CxQ9r6mlS zW{OWs(`2Qk^@_@eGi5#XdVVV zDjEY&>}+_Pir|l-hj{-(QU2WW823ea;p_&ph!NiKRi7W}D;nVRkKQQPcy?jw?8OV_ z7UfrXA2bTTbHDO|c|)b|org|i_dpu@cu|T`t2{qAh^rgS)|VW88LTh4`Z7dchU&{O zeHpGVBlKmYzKqhB(fTq*U&iXoczroXUnc0wx%x6uU(VB)NqmXs)@9BIC+i=k@I^Nb zwHG%H-;^&c@qa|`qUM$?F4Z59Xz*RVvcd{|LmyDA;d?GQ z&8V%k)ND|Y2P-l-hcBUAQwF@MWLySwbs715iOz+Mr#o^$E?%&_oRF$LlK;BfAk!9u=-h8xPEoS5?An({); zo#BSYLVb-M?vXEtkC25I#*7Ffj=3;=A3M@VNh~P}SB1fBC5ssLCS77j`F@Hm@;wAc zX?7Ix#U6!%?IQdMj?v#2>+i?-K8Y>%Jp{+-?~64%i}Mzil$Dp3EG)#r~(zMAP_-^)+TvnA(`7zWd3(`-{T&!6~}l%lHyK#S@+A zW!`OQP%i%(%FEZ>8CzDAS5~0!OMLgb!)x7_TV9~G1oeEriy6d2gt_Oh`96M7m>lyX zGl=gS407jM{HV1D-^PU%2|w4*nVmleV`Uyc#pL=5)8zB}_}n^$HOP%9AZEDlyWu_} zhu8gXc;t6u!ZgQ>_2C%n!!foFj+n9Gj~a}P#5d80W1LTUiR*y4SP zRR1`Xdx8FnX-H4yhlYMt%5UO*DpY@~b*KK;XioEk52;a_{6kz=WAbynPhs+lhJH<{ zacK>yfA#A}^J}3glz_&(OCH1k84+tIAe_;sTQWoAC} ziAB6mf$^{LKF!518cdFqc&)+sr?{~G;^&wt;cCRetX=@8(X65}{w;bC`Cr(B6Pv3Y zC;U(^7bYwFb%vAiN_S|ELK=7V!$co&^jLDQ@cV}3p>ZkWHvule&c?JOWJ<87;6b4T zn~(=a<}F;9Cr2-qV-{n;<1*Aa1tscSICD%fDyN_@mVjNJ=1)jX{PU)20qKY z&ob|`-1o+PkY%R#S!PAWw?@MxZc}5_cq+wgN!q2km3Fy z(~3C;e~!VQV_GrC{65(HZk(Q(#_5?k*tE)EQ;)%>bp{*y1{?YYoAL*n@&}t%8f@w} z*w8cBl$UGD&o%gS4gOq%KiA;THTZK)eREBHb4_`D+{k5Fq+0Sn~%bXQFdx|R98uYvDtp0#-4 zd((}z7^Y_SG2ffHWM*GxGw3vQ^<}o;*?iZ>)T587hZZl;Vcu(T!n65Kizl94`i*+j z-3s&?IPJDf&C+W;h)>Hx5D%8t5vN1BH{&?6FB(xcgDp9D$f$EII4sMH5usyKun!;v zF5!E8IX}O&*lM8vGA_brbDWU0qO;z&gqlWQh&xkXPklXD9jcdBk$MS23)-jG3pL1U zo7FabVdjZcTyfVvbxriJ=x5V!N?(}zkJPG+Rat{mXT)TteVLY!-a2MU?AG)VX$h(0 z>fe&Sr2Y>XpQbNq&>$_L!MMyuX%*@1(<&M~8@E4xd&5f_wN78ssC}cJ3Ew6@+jM_g zLbE;1_P5y6;^S6JTJ1igW5(ARUnlj+YMb<8^5Yq++B#HnT2K1h?il^nVMfQ~j(a-A zcKS49S?8jRPkY|e`IauH(-OKb>%PC|nx1RY5_-Jb^8&iVeMS0+)PJNe>3L6D0ur?? z%RG^JBE5CSGODZo*YowBpQkiPX_nGDB{gMA%EFY(Qf^9lDCO~#*Hhk44W_mNAKIti zlvWY(Po~$?|A;F6kKqWmefmQEFKaOP;`^80+WZ@l?*3bnz65x`^!`Ig2mJ$%dVsC- zpIZ`Lb(^HNrGH-eBk&#nmpYFAp_S;Lp@y!hRat}6mr$G0Kk%j=<7y8|(dOy(QfJU} z<_Y~abxrzBS%cBWZSmEJ^dSIocDo*0rS8Ns~-h+l*BipX%TEcdCDDddKww#6P=j@EtF_0~Lec^PpXL0r^4BtE7uAzo3PGd?BhqHD(2nT<3Dvk)0C?nK{;Lfme{ zh?u!Qj+m<(FGo>w6d^a7W8%(5Je(U1H{H4lkxTa=_Gb^`da5WE3K38T5zqD@@~BYc z)8mMQI)aF(rx6SE45EQv{D1A;d7NEEnLqwI_jGqUou#uc7!Y@MFd$$65l{&ri-2Jf zL6F5^5fuf2VG|Hh7z_xwj3chYFbaH?K|x5^nkCSf1u~N9kcH0e+sRGe+v&70I^_J` zRh=dsU~p!B^ZoC8@9T4`&beo)<*BDW^_;5nq&Ywf%>{}xfEIgi(I3rZTVhVzi(#2r zZ7ah|alTBP`C?XGx4Cg^%#w>U>DGsr&EENQoK+KN`DB@O`@=WReA{Z{ytW<9XFI?g zwK&UcV2;@>W_;aYu2-DnH88(xaCTRm+x23aTUGvFnO8M9t7_9+syEJ|dY}1I+nYOO z-c)Q}rCm$Al|Ha>F4KNyEPd2$rGv~=I?Vi}Bh5{kWnR+p<|LiC*=(fGnTd3^IY$?o zZ*+;dMpu-sG`r{;Gm8f26@A;BqM@^L{@RS3QRd)`OLK4DZ060tyqlr3ZsMGq!5KGk zp3Oey*bL6FiF0cPX4V{GPEDLmbHba>p^5Wn24>I188a8ZZl+9}A@jdKH|Do*IWOi} zvtSl&Hru7kJeM_Tj?3WOmN=(ngSjjX4b5hz?rDDN2hCI6D@^i+x(TIHm{htpj4ORh zcs;BSlkyyzV6QMP-v{=E{cO()6LMZr@@23BUJ9I9nCqH_vBlQf$>?HI7z6L}X5Ae& zykZvXgm6IdV)$sWCVUJIgoD8Q0>e>obWsk+6syCrMa8>@D`B>MH^Z&={mM1&0`EBv zzw_Ut!pGoo|2^xv3!%?;QLM>^7j4-D;iRIHZ6VwWb`BG=-GzGy4-mR-LM+gKo!1O-r%>6I-Yty2$F_m(US z;myKZgtrR6EBv1D`@$ax|6ce*;Xep}B)m=dW8qJPKNbE=_zU;A9qxc%!kyr~>G`kW z9=IPKfI09GJObn~e;l5KdGHK83-e*2@_G&y!yjP@bij+ST%J}!C#)gITZi3?=fj>w zr#GTi!(PSG@T~2H#q-(3qBGlBxCh)GMwd#(($WRR^Q8;nVz{=bmcC`*^{~EJn&;32 z+ZNB~dwJ8}KCmzBXWy)%Ge1$d3|7EPu%>vvq1pYmkb=9VV6D5)clW#9{cd+(>+W~E z``zw5-<|Jv=eyncZg-vUuJhe>zPrwM*ZJ;xw>!;ur?u`h-<{^W(|mWD?@o8S(|oh! zcPM(o9z{>K0g9rh6d;4c;1akDu7E4yYPiN*0Jnezu*kUw;{{_dgE8jbPcScj9Q{(E zUn=xVB^(4t!AWM~&lcVc_rjy_81zAr^hAZ8sL&A=`k_KUROp8a{ZPry2xGiubxg+B zpH)3$va`b&?YyF$SG4nrc3#oWE81v98?9)g6>YSljaIbLiZ)u&Ml0HAMH{VXqZMtm zqK#Ix(TX-!(RM1@O>8rj{D3ef{|L;4BW=@%+Db*csAv}zZ6daT3K^}C(Fz%@kkJYm zt&q_Q8Lg1f3OTHh!wNa9kim*|10N+%AA#AH=<+>`@Rk^Opbycpba$S|{ zs$5s)x+>RID=$7F#S`2qVj@g}$uI>@fm7jhN6Q7>R;9zLbWfGuscPp{?Yyd;SGDu1 zc3#!atJ-;0+pb#qF}k=)FLzb;H*gMo5xx}nk?bnTu9EC3$*z*@D#@;r>?+BwlI$wU zu9EC3$*z*@D#@;r>?+BwS|!p@tP8{8*rHF5*r(^~3+syhY*Nveol&ggr(|7rCY%Ll z7whyQeR`2T8oZCT?xThKXy85?xGz7TSeJhUX2LPHPlC(f3b+!M!%FCMj~U@Tezyfz z2)lx#!nff&a3{>Q%H0WS#Ha6TbA3h z+?M6GEVpI3Ez50LZp(68mfN!2mgTlAw`I94%WYY1%W_+`is)T>l^MlCdVLX2)rnJe zhPhTOFD@41O`TZ=wd5vaVxoOm%DbkYY&fT8^eos?Q<*bb1Ut0EA4YDIc=BI zb~$aA({?#+m(zARZI{b-xonrqcDZYpvv#>@my33(ZUODam+E$@ zZkOtIscx6*cByWc>UOMnu61Fh(56?VqvAT+qJuW>pp83dQ7jHe3Xihy z7`^ea#R{!|1x?*SQ+MFQOKIy4+F(VvPY-y%ntj0W58}Ubitg|b&(RMTU9@=zZQkLI zFNMdQ^F;A%c&d0V%q#vaR2*N0wV;iLI`l%Hj+Bj3$7T}JD!pmkT|2a6wRKV3-cuF$J>=+!!C-xYec z4n12(exCon0vEX6g|;siUgrNR;7Yj0f8VtK7jQe=0l$Ph;coaf+ynPJ?*W(t55Xhw z7(5P7`hOlg1JBx?FI*@u&%t8&BP@XqcoCMn?@H(dvXZX`a?wBr8gghP6X)xn__KkJ zlDLn-fp8EU1;==wvfPr~4w73Zxpk6TBe`{w+d*2ZT0|>JT}@K!B(+XbJ4kAcq;`?S zI;pFZwhq!(CvA0-Rwre35>_W+brM$B4=&LUF3}Gz(GM=s4=y2fby8O+b#+o#Cv|nw zRU=(B(p4i}HPY2Vx_Dgk-!`xv>;OB#E-)Q-1NS6db<$NQU3Jn`CtYz8W zH4;=KK{XQ8L4xX}r$%x*NKTE^)JRR8q|`}D2T7@ukPZ^kksnYj(JwF2FE1e}byCtn zO6sJfPD(mRNu89`Nk*MibdZV;Qqe&o>Lj90BI+cfP9o|gqD~^}B%)3t>T12N*6V7$ zuEy(Xyr#x$YP_b#Yihiv#%pT4rp7zec!wJA(Em3Sx2f6N!c6+)n4(urwyDWBHQ1~6 z+SFc8>J=YWi*3amwbmP+RQi*Qk~)d7F0$7}_IT)kZD2dt0d|62U^?su zu0zJU$XFK{>mp-aWUPxEb&;Dca??d-y2wWt+2|r0UF4#RTy&9(F0#-?7P`nn7g^{c z3teQPi!5}Jg)XwtMHafqLKj)+A`4ymqc$U^OO2jJ8a<6v4x2_zGi}F_(uf|S4MdEJLdtI0}sI?@EEX)sqamrzh`Y50p`nHcO`VH zvr*xAwRb{dBP+t{Vr}ULm<=}>uTO_l;9R&Cdf-ovJ(awSATJ}x%O)${OxpvNyl(Qc zhMWvo?xMABfT64-BLfz@C!(g%rsmP}gBH69MK?Jau+&8>-RmuMXON@M!I^LtoUKk< zShL<}Y3n8f-DIGf40Mx$Zgu}Zvz(pc+*9H7qFcSMQSaUAyjz_|D_6HVU!%U)sOJ&t zd4zf%p`O>M;{nUoCM#CA`i)ksZgsjwJN;{xrEYcFtxmhuX}3DuhO^7)3?kE zyBmk>iI2Kk8jl>#d-V};Bpi#=9#29(CH!6Dw+q6vj$a6i9lwMuF2#RWI=|xh)sC$S z*Fp{I&e$YN3W}F2FSxcBW{J^8EQkPC3g1vun_G;VtjNtmO?V{O;ec1=ysQPXqO?o(=T znVMRwmTGE=CBK-XmX@iZIoaOyMy!=t#d0NHQ{puxJVy!7QNnYSZscG!B{)Z^)s$3C zDbr!m1U_clY=fY&_xEi$Uv9z z^ExunrS5yAysYkHTkciIUFxz+J$9+X*tUDsVQk;M>aIt<^{BHR^;J<xTVTOw52+}H5?B^k;Mqnh zY$Fv%T22olQk$67F)KI ziV|C%O%_gtw}B@iN^m)wN<|4SPpxo*z`wvVB^Dz>{} zHLQUutOfVY72shMVAKxD~z!KY$;? zkKo7fQ@GDHeh&}ATzD98H};|mdr^hGsKQ=UVK1uW>XY;=BR$JV&oa`pJhkS!Ft+G* z#qx%xFs5M`G?R_#VX8Km;K$%rE*$MQ_sEFNiPEX64$!;szZ6&*{uhS^8S1FUl zRwY&@hpkGjoHuwsVUrLqCX1~D+Qq*8?DKYXr5Ae%J%oLy+CCl3dCD(!{N?a9xT;u1 z25A`kzXjJh=6bjRX2VTzGu#T_gCD>T;YaXe_$e%Nj}`C|B(3B+HP@}XZm)2iu-`it zS=Y%|t6C|WskJ*h)(j=Q7n|j?;`7B93ZGB*%T?h8+e?gBdyG5+?5t1U0}j{Ef0B)| z1Q!%9k*Sx+)JtTlQz=E;Wwcv%lBrcnr;|)|E18$b)G8$tpOSTwr&Z)>6?y6=Pu=9H zn>?)|Ppk6lu8t1OHzrR>TrdBl!D^|-vC#l+9N@t|huax>usb4AeE3}MG zsqajwXML4}HF6O9x|MRUQVwFuS4#OxDPJk2gQ;98l`(bEn%eog)OAW-r_`;HqLotA zDMg)9)G0-4JQu;Vm1Uo@Tq7m%Zk~^0%O#A@vsZUp<8Et|Q=fA3ZWL{Z?ME5KHn&FE z^eLM@dGC|=K6&qRr#150=UM;Z`tc*+NH|`rdO%o#ZoTGe+g0(kP=h-3!aD!07h(z6 zS`AyPVQaN4gGSndts16P!=P#yQw?LP={@V% zQVmqGc^w(FQGOgVwWwxde5iur>KN{r}f2XK(#{f0I>h;Q4+%{K&X?lyUJW zGhFIQyoXJxhfS%+tg}(!AYruXA0^ymOX&$W+rAf~E#*<+W6)jPq5a=wY}~`v)I$&4 zHDGl&?wz8ZJ^Rk4v6E~i+#L=8*Jpp~$v*Cw!{BJ~GuTQ#2WP@ra5nr`Y%6+Kvs>z= zM$p5Slyph2SQ-v3p1+TPkuVBI!<$+12kkCfJLjG7Zg{U_w}I`zGk-R)9yYKZHn1Kx zu%42g976fN@Gt4-G<0gFjM&qg~;&k#Gz zDC6@{#^#~PAk+CYpe?$7nxf)*xLg~dVkq%3O~JzmeI| zFiVfy;@zerU?hx!(ePf_2DXD8U?U${Dbl z)am^7$zsy2H;6r1k7r()B!Yq*=ws z)3ta`OubaUYxTQUziaioR_uxTU8~=<`n~w-4!z2qbo@p=ABJbQ6o0gLoxSVqT}S(` z%kDR8?)Pl94-`*ibBnoN+;@wsJwS_P^v=R`oz41-(Bgz>f)3VrtWxL$8&E{46UUGWxM_v?Yo#Ik2q+QU*THSxH)?mhg!qVrM;Yw0de zY|K|(TIw+^^5L0Vv_8jtCms6G>r2GHt!&d{*rvzCtC04A9BsNvEQ9B1`QwV8N%d^U zjCV|*T=#A)!I+c16`1{w&KY&PV>Y^ ztC;8hKVnn(gezUlel*Y3ma;3XGyeLD@z*@%cewOjrk#osW=A7uO^fGC@TWkKceNl>^ zx4lx%J_)xweoi`Spww0?m)|*WwR_b!vfniuEnd|mwQHm$GK^Ty@kxv)0G{j6*2R;` zuh-n(ql@L2n#x9q-U#qoC!e7K+EiP1Zmq_hp?*3gV zUZMuCP=nu9gO@0&->Ajgl>Of-`|m6Jvz2{WZJs4pH!8tjsnv_sYO9i*o$NZXjo*#~ z-BH}9KJHT=_mQ>xJQI3Ay+m!W)~t$d_Sh*(eTqCiCr@=xDA#VR|K;g<@>66&KS~zH z$wRkv|Eu);tF$bVmc`Q2CM{jOgpK0OFZNf9)BQJZ58X;Vmg{hJ_NZ(8!8M*GPhGCD zj0`OxLsfNooAVbKvmRZXqx7!}XT3T%T(semaM^|jl>YWg{}3rXSxRqE`mJHkhKkaE zdw68SDy9Fi@Wh5VOXRrl)P`5XybUiX{Ueorqm)0W^bZQ%8#XBY@lxTU?KUNy|R{FnG`V*D@-b#P8l%A>d50c}NQoC=q&xT$(ekhx{p{DfTuk=q+`YlSo zQR;V*`)J=du6S5V+ob9qcmG#+yw4qe?G6jw;YnAG^%={q(^Z~vm1ms&w6kmKtfJ1! z>TE!lG%Njyn8ZXS*6FNO($T5ZUQ%i+m0D+bcW92WJJMyda9GQC)-R><`I(%(%Eo=&>xDRUO) zY13a&_hy%ouYZ=-c4>WDTAwCgPm`@avQ-PEVc(?JLd&t^wlntIGKAvh;v2=YMO#rV z9yK%ezws$%{WlKY?9k#HgPU|~DEbSQ>*Ak^-xog-e^z@Rs}+wUOMmsF6|hLcQ=1=3 zBmI>R-uGYr=ud`x(mnYYB2VeV;<52le7{(&US9XnazljAgu%b$w>%jCPr`9S_YbC) zObvX-ij9pa@fka?Yw(xk{QvkAv`Nb0Yq^s8ZW6okQ~dO`*h8N7r*w$n?{QB)w$YwlNyVDoz$zI*k{871sj{KJqIsS{GZ~6;)lgeaGlcd z26Jc)V~QUazbhWoHbQY}@wa~88_y`F6l02d@tYL?mtrBk8t}Ny?ps7##E=gS=3{=@ zYo9{@7VCRsosS;;V`KdeZieFO7}d9K_DSg{OL$29q_c}P=~}T4$I`JIKQU#4AFblI zJX8G<9w!H5X^L^`d|dH@HoJ20C|BK)o(RP=g|XU3DU93kei1|DtzggFblw|dwDN!Y z(ObO5XHZVx>=5;w&Sh_U-6!tfyyRbZz*}y<@p_vMe-o+N^k>ko{trJG-+%fkdIzri z#;Yei66G}MgEzUx=50R7(2(22_7G<^`W>=&v#1`;r?`2uof|je{odrBZ+7VG_QjmM zF*mO}=nb32hl(AFj}*JY`$*I<2Mp8a4=WBSzEpg@xY0FRi;-IPMe)=Pr`TSAr3F3U zW}gk(B-R^n>hvK;sr@9Weys)vdVu2R#q8oidiX&tJU+7+_-qV4r4M=;8hXPy@sHx# zjsI^9-nxV~>A<096&DWO+B|NS>c-E24jbHZ=YA~j0zI+582cKIPmlI3(O_eYl-_0b zZv+1c)BUr%XSd^$tB0wq8V4F59PGO#p9n{qQ-8GYJ6Yk5bVb@Dpn>KN@~+J?4So7uIAR6#mh=%tONM)@B|S{;70C>4mxV{IRcZdmR`1^ z@Q>c1K0KIFm5&PD)^D~3Ys>O+VNG1e8LHl){*KV&o$2ohuXtnn4&g7}l)hV*#rL9T z%~ovgleJj2xoL&JXJlK%x1DG2wO;ew zY@6JA&1`!sHZRV0v}*IpY^V4>^XvoGYyL~NhqsUaHv5cqmXBvAd$;(r*|}C#F37%M zW#yvmi&j^5W?%9K@viKv)>d|B7g}GrCc7xEvCJ;^2Jt^-mw0#hzh_s(w})q6^Y-u! z*;UqCma?m@xopV3?%m{Gr|wV@OE zHHocgyjJu}?d?~-B`d1$l&ZUYOQ~H=P3>w@YFFb^yV^3ft6`~KMc*JV$jcJnty1e6 zmRi@a)Vj7zt!vBFy562z*A}UDjZdv>Ypv_g>?D8j9iQ6R)~Stco!VGQ8=DX&^Dr{e z*lv>cHdTAu#*y1*+lFbpiEJ0%p4#5<)b@s_wl^`gy|?rA@i!XnIa*+rT40u1U}I{5 zBdxpcQIoZ-#`aXt`a%;=7O#Y1yjZ+y6t$t0g=YRMXemA{hFe$L!Uj5l|BBIJqINsp z3fl=<@8syMB24A4;_actXT{cze1|8yCB7@(DgG``cuRa(yj%P|C9=Vn#d}@neI;6t zPm68Dw=Hcez8yO%pHaL$W@({Wj(3Gml|JQaCzMVQ|8(io;wP3)6z8`>{N&Qf(tJwk6eaW7 z(r3j_EuAWUTIn?L)9I$kNjFVNx@k(%O;eI?8kuy{$fTP_Cf(GWbW?NEP0dL+H7DKF zoODxj(oLi3CUYwIw75|*ur`#p7;%74Z5umv9$yE)iA6^QGZ} z`~vyaTll>szeKJtH6vmxUNJ6n$IJ7}#jo&;XetjGUlYI5{N1T~lyA7swfVKKbG;c7 zC4Msg&K++sQ=-IQ#<#_1n=w)1H{(X}oAR5)zmtDQ{AM#KO8jWtB7Uox6ea#NzAOGc zGb&2_YJ6Y(2WD23_}BP*@gJIDQQ~LgAH;uTrbUUr4PzcYH-0Ssll&**KQ;5B#Q(<6 z#DAXuT&{oNdB{Y*IQ~)mcF#p7^2zZ};&*sHGLdhNe-{6x=Oh#P==hcRot~FW*O{P*GyUYUgJmHjTu zmyvggxxe_QpJk+DwF|Gv}yO}&0dy?(Pke;fO^^=(eQen`Fk7W({M?2kQtbL!~> z4!W!OZoYw!un*{iW8XhK_5CfW?;nx+{*kHgpPc&sQK|2rf{*U+tjGZJ!~lZ+|3GP< z=^H!;JV^ZDaG3bvJc%_X9?+C{K%*ywNBKAM=)kwwC-vF0d;=e2$H-@7)~%iy9A{5t z3DXiwXiY3(4Bumy+kb^`GapmYUiEF?W=|YvyXK92js?D>zGKhLz70H+@i)%{*{!bp zUECrJ;TFvsxy9W)Rt3*0?{)ldeM4d!t?3OeA#sjIKF%Jo|4~me8`#I@z^?X52D z;?MdH=jZ7U?mORiEY82ce)Em(U&Lw|5=WVw-u4pklouQmnaafE%`EU|wiK6o(K}y4 z;wX)*oYAfo#{tv40fs#xRJ{kL(KFN@Jjr|)@pZl-@t6j0hgok=zwZS8)m|3o>B+y5 z*)%3*6TCO(Kg4;9vcK?cz;yy1tHqHJmvn|E9@{G5EPqv-xiDQ)E*)G}p z#iwV}-JSn6@egDlaOCcu0ypr)wufW(%sy=Ye%XGG**_z7iCs1D#`ZDsIKFA*k&VCY^;%beF ztA)hX8WUG*PF$@iakb{e)tVAlYffCPsdPr^Y}YxbbPmq+`O@dHpL0v+ihrT>1@SMI zz9{~s(wD@~E1f6)<*8^o+QPS)S&fMij^yL) zo30so;i$w5TN5uFm3ZNl#0$qHUN|N3!ZC>#PD#9QO!S53+*?YwDAij_J>r8*QF~7u zu{m+XQPJC&J%db9drus33XWLt_8oa)GhSE{kBo3sVuX_uBMgZVj^c}K7$(%5Yww92 zHu6i>B0eG?foYA**^3fiY~rVEw0In6M}K8w#K-1i9TUggO?;P)7oUJThQu9{_cHOw z9VfoV9p7zFWQxtvinTrzsKdr$uG}p{*4^8IdRa2#6d?T4%(W3CjX3oBL|(FM-DnIanLY?gXZ}r4w~nm z!$Cvhpbh!ixt5ZcXhUM6lk><#r{!PBzhwV;`FYaz<^0RyU&+5B9vNzL9vNyApKV_i zztF6ghWw)ZBJs#sn{qzf93MIB#Kc)!6K9>6IBRR-tP>MwZROqVD(vv;{A#TF>-pE6 zbxnSayF@NKIdR!(yuNuJ#`D{^!dTwluET~mvD1Eqz3-&o)VvDK2ifecTbBylRqQgp0|rf2HeE&9mc}< z-F*8a8*bqPZ=qHkIdKbLc+ZJHpJOk4;+dz;FCJ?*-*|r%e<6QCd`Z4U{NHj<`}b>LTTwRmLM!}-^% z+7o&9d@ok+uv|zUL!q9hpz84qt@vhHdf|9K! z{I7-eY}5XX3O4%20^^Fw(I;~f6J`zkp8YpxoE%Qv_{*D2I5ql|38#J`{+>DT8~x*i zFKqlhZNmd4+v^gB%Y#_18SYnapUVq;6= z{*ALz-dLH8KFXn;7k!L((Z~50eS(M4=wmc`8I68M2Rx0o^ELV`Z==!Q zX!JN5eU3)2ql@?*eU9hR=lLFu-bbVV(ddCR`XG&7NTVOp=!rD?B8}ciqd(H+Jd#GA zq$^7=`F1AHq|rBNnRn9YpEP^ay_7~jrE5#yB@N@1@Y_hkyNu*ojNfLm7$0nO zwH=SmR~pw{?faoL8rqjH;afdzcqn^3>=z{=%uKe+gR?S=;m5Jfy~7Q--yz}0rNc@m zvHG8kgFS?IeU*j&VivB&TK6hrl>w=24q0g-d5g04tL)!~NZ!Iw{=Xu5zj}jz*?%BuD!vIl4N@(XC02ewO6u-Xup)COLX0$&vY) zNsEyqSC4Y!{mI#lWcm=Xj3h@ro#cz&Xi0vspWws#Uk5x+M{m=Pjps)B-|W~o(>spM fQws>G1!SoO#Cs0hgHCntc;ACI+qZ4nckllP8pbT8 diff --git a/src/kivymd/fonts/Roboto-LightItalic.ttf b/src/kivymd/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index a85444f2ecec38a4df2efd9f09b8055169909a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 133172 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⪼!+`pB8ILOqDAf+mbV8|B%!V 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 diff --git a/src/kivymd/fonts/Roboto-MediumItalic.ttf b/src/kivymd/fonts/Roboto-MediumItalic.ttf deleted file mode 100644 index b82820554134a817749ff81922c5a4c0082abf35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134312 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

VTi)^qwc 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 diff --git a/src/kivymd/fonts/Roboto-ThinItalic.ttf b/src/kivymd/fonts/Roboto-ThinItalic.ttf deleted file mode 100644 index b79cb26da0377370ab3e41bb7a5a62943187124f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132860 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 diff --git a/src/kivymd/grid.py b/src/kivymd/grid.py deleted file mode 100644 index db310193..00000000 --- a/src/kivymd/grid.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf-8 -from kivy.lang import Builder -from kivy.properties import StringProperty, BooleanProperty, ObjectProperty, \ - NumericProperty, ListProperty, OptionProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.floatlayout import FloatLayout -from kivymd.ripplebehavior import RectangularRippleBehavior -from kivymd.theming import ThemableBehavior - -Builder.load_string(""" - - _img_widget: img - _img_overlay: img_overlay - _box_overlay: box - AsyncImage: - id: img - allow_stretch: root.allow_stretch - anim_delay: root.anim_delay - anim_loop: root.anim_loop - color: root.img_color - keep_ratio: root.keep_ratio - mipmap: root.mipmap - source: root.source - size_hint_y: 1 if root.overlap else None - x: root.x - y: root.y if root.overlap or root.box_position == 'header' else box.top - BoxLayout: - id: img_overlay - size_hint: img.size_hint - size: img.size - pos: img.pos - BoxLayout: - canvas: - Color: - rgba: root.box_color - Rectangle: - pos: self.pos - size: self.size - id: box - size_hint_y: None - height: dp(68) if root.lines == 2 else dp(48) - x: root.x - y: root.y if root.box_position == 'footer' else root.y + root.height - self.height - - - _img_widget: img - _img_overlay: img_overlay - _box_overlay: box - _box_label: boxlabel - AsyncImage: - id: img - allow_stretch: root.allow_stretch - anim_delay: root.anim_delay - anim_loop: root.anim_loop - color: root.img_color - keep_ratio: root.keep_ratio - mipmap: root.mipmap - source: root.source - size_hint_y: 1 if root.overlap else None - x: root.x - y: root.y if root.overlap or root.box_position == 'header' else box.top - BoxLayout: - id: img_overlay - size_hint: img.size_hint - size: img.size - pos: img.pos - BoxLayout: - canvas: - Color: - rgba: root.box_color - Rectangle: - pos: self.pos - size: self.size - id: box - size_hint_y: None - height: dp(68) if root.lines == 2 else dp(48) - x: root.x - y: root.y if root.box_position == 'footer' else root.y + root.height - self.height - MDLabel: - id: boxlabel - font_style: "Caption" - halign: "center" - text: root.text -""") - - -class Tile(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, - BoxLayout): - """A simple tile. It does nothing special, just inherits the right behaviors - to work as a building block. - """ - pass - - -class SmartTile(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, - FloatLayout): - """A tile for more complex needs. - - Includes an image, a container to place overlays and a box that can act - as a header or a footer, as described in the Material Design specs. - """ - - box_color = ListProperty([0, 0, 0, 0.5]) - """Sets the color and opacity for the information box.""" - - box_position = OptionProperty('footer', options=['footer', 'header']) - """Determines wether the information box acts as a header or footer to the - image. - """ - - lines = OptionProperty(1, options=[1, 2]) - """Number of lines in the header/footer. - - As per Material Design specs, only 1 and 2 are valid values. - """ - - overlap = BooleanProperty(True) - """Determines if the header/footer overlaps on top of the image or not""" - - # Img properties - allow_stretch = BooleanProperty(True) - anim_delay = NumericProperty(0.25) - anim_loop = NumericProperty(0) - img_color = ListProperty([1, 1, 1, 1]) - keep_ratio = BooleanProperty(False) - mipmap = BooleanProperty(False) - source = StringProperty() - - _img_widget = ObjectProperty() - _img_overlay = ObjectProperty() - _box_overlay = ObjectProperty() - _box_label = ObjectProperty() - - def reload(self): - self._img_widget.reload() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, IOverlay): - self._img_overlay.add_widget(widget, index) - elif issubclass(widget.__class__, IBoxOverlay): - self._box_overlay.add_widget(widget, index) - else: - super(SmartTile, self).add_widget(widget, index) - - -class SmartTileWithLabel(SmartTile): - _box_label = ObjectProperty() - - # MDLabel properties - font_style = StringProperty("Caption") - theme_text_color = StringProperty("") - text = StringProperty("") - """Determines the text for the box footer/header""" - - -class IBoxOverlay(): - """An interface to specify widgets that belong to to the image overlay - in the :class:`SmartTile` widget when added as a child. - """ - pass - - -class IOverlay(): - """An interface to specify widgets that belong to to the image overlay - in the :class:`SmartTile` widget when added as a child. - """ - pass diff --git a/src/kivymd/icon_definitions.py b/src/kivymd/icon_definitions.py deleted file mode 100644 index 5b717356..00000000 --- a/src/kivymd/icon_definitions.py +++ /dev/null @@ -1,1569 +0,0 @@ -# -*- coding: utf-8 -*- - -# Thanks to Sergey Kupletsky (github.com/zavoloklom) for its Material Design -# Iconic Font, which provides KivyMD's icons. - -# GALLERY HERE: -# https://zavoloklom.github.io/material-design-iconic-font/icons.html - -# LAST UPDATED: version 2.2.0 of Material Design Iconic Font - -md_icons = { - '3d-rotation': u'', - - 'airplane-off': u'', - - 'address': u'', - - 'airplane': u'', - - 'album': u'', - - 'archive': u'', - - 'assignment-account': u'', - - 'assignment-alert': u'', - - 'assignment-check': u'', - - 'assignment-o': u'', - - 'assignment-return': u'', - - 'assignment-returned': u'', - - 'assignment': u'', - - 'attachment-alt': u'', - - 'attachment': u'', - - 'audio': u'', - - 'badge-check': u'', - - 'balance-wallet': u'', - - 'balance': u'', - - 'battery-alert': u'', - - 'battery-flash': u'', - - 'battery-unknown': u'', - - 'battery': u'', - - 'bike': u'', - - 'block-alt': u'', - - 'block': u'', - - 'boat': u'', - - 'book-image': u'', - - 'book': u'', - - 'bookmark-outline': u'', - - 'bookmark': u'', - - 'brush': u'', - - 'bug': u'', - - 'bus': u'', - - 'cake': u'', - - 'car-taxi': u'', - - 'car-wash': u'', - - 'car': u'', - - 'card-giftcard': u'', - - 'card-membership': u'', - - 'card-travel': u'', - - 'card': u'', - - 'case-check': u'', - - 'case-download': u'', - - 'case-play': u'', - - 'case': u'', - - 'cast-connected': u'', - - 'cast': u'', - - 'chart-donut': u'', - - 'chart': u'', - - 'city-alt': u'', - - 'city': u'', - - 'close-circle-o': u'', - - 'close-circle': u'', - - 'close': u'', - - 'cocktail': u'', - - 'code-setting': u'', - - 'code-smartphone': u'', - - 'code': u'', - - 'coffee': u'', - - 'collection-bookmark': u'', - - 'collection-case-play': u'', - - 'collection-folder-image': u'', - - 'collection-image-o': u'', - - 'collection-image': u'', - - 'collection-item-1': u'', - - 'collection-item-2': u'', - - 'collection-item-3': u'', - - 'collection-item-4': u'', - - 'collection-item-5': u'', - - 'collection-item-6': u'', - - 'collection-item-7': u'', - - 'collection-item-8': u'', - - 'collection-item-9-plus': u'', - - 'collection-item-9': u'', - - 'collection-item': u'', - - 'collection-music': u'', - - 'collection-pdf': u'', - - 'collection-plus': u'', - - 'collection-speaker': u'', - - 'collection-text': u'', - - 'collection-video': u'', - - 'compass': u'', - - 'cutlery': u'', - - 'delete': u'', - - 'dialpad': u'', - - 'dns': u'', - - 'drink': u'', - - 'edit': u'', - - 'email-open': u'', - - 'email': u'', - - 'eye-off': u'', - - 'eye': u'', - - 'eyedropper': u'', - - 'favorite-outline': u'', - - 'favorite': u'', - - 'filter-list': u'', - - 'fire': u'', - - 'flag': u'', - - 'flare': u'', - - 'flash-auto': u'', - - 'flash-off': u'', - - 'flash': u'', - - 'flip': u'', - - 'flower-alt': u'', - - 'flower': u'', - - 'font': u'', - - 'fullscreen-alt': u'', - - 'fullscreen-exit': u'', - - 'fullscreen': u'', - - 'functions': u'', - - 'gas-station': u'', - - 'gesture': u'', - - 'globe-alt': u'', - - 'globe-lock': u'', - - 'globe': u'', - - 'graduation-cap': u'', - - 'group': u'', - - 'home': u'', - - 'hospital-alt': u'', - - 'hospital': u'', - - 'hotel': u'', - - 'hourglass-alt': u'', - - 'hourglass-outline': u'', - - 'hourglass': u'', - - 'http': u'', - - 'image-alt': u'', - - 'image-o': u'', - - 'image': u'', - - 'inbox': u'', - - 'invert-colors-off': u'', - - 'invert-colors': u'', - - 'key': u'', - - 'label-alt-outline': u'', - - 'label-alt': u'', - - 'label-heart': u'', - - 'label': u'', - - 'labels': u'', - - 'lamp': u'', - - 'landscape': u'', - - 'layers-off': u'', - - 'layers': u'', - - 'library': u'', - - 'link': u'', - - 'lock-open': u'', - - 'lock-outline': u'', - - 'lock': u'', - - 'mail-reply-all': u'', - - 'mail-reply': u'', - - 'mail-send': u'', - - 'mall': u'', - - 'map': u'', - - 'menu': u'', - - 'money-box': u'', - - 'money-off': u'', - - 'money': u'', - - 'more-vert': u'', - - 'more': u'', - - 'movie-alt': u'', - - 'movie': u'', - - 'nature-people': u'', - - 'nature': u'', - - 'navigation': u'', - - 'open-in-browser': u'', - - 'open-in-new': u'', - - 'palette': u'', - - 'parking': u'', - - 'pin-account': u'', - - 'pin-assistant': u'', - - 'pin-drop': u'', - - 'pin-help': u'', - - 'pin-off': u'', - - 'pin': u'', - - 'pizza': u'', - - 'plaster': u'', - - 'power-setting': u'', - - 'power': u'', - - 'print': u'', - - 'puzzle-piece': u'', - - 'quote': u'', - - 'railway': u'', - - 'receipt': u'', - - 'refresh-alt': u'', - - 'refresh-sync-alert': u'', - - 'refresh-sync-off': u'', - - 'refresh-sync': u'', - - 'refresh': u'', - - 'roller': u'', - - 'ruler': u'', - - 'scissors': u'', - - 'screen-rotation-lock': u'', - - 'screen-rotation': u'', - - 'search-for': u'', - - 'search-in-file': u'', - - 'search-in-page': u'', - - 'search-replace': u'', - - 'search': u'', - - 'seat': u'', - - 'settings-square': u'', - - 'settings': u'', - - 'shape': u'', - - 'shield-check': u'', - - 'shield-security': u'', - - 'shopping-basket': u'', - - 'shopping-cart-plus': u'', - - 'shopping-cart': u'', - - 'sign-in': u'', - - 'sort-amount-asc': u'', - - 'sort-amount-desc': u'', - - 'sort-asc': u'', - - 'sort-desc': u'', - - 'spellcheck': u'', - - 'spinner': u'', - - 'storage': u'', - - 'store-24': u'', - - 'store': u'', - - 'subway': u'', - - 'sun': u'', - - 'tab-unselected': u'', - - 'tab': u'', - - 'tag-close': u'', - - 'tag-more': u'', - - 'tag': u'', - - 'thumb-down': u'', - - 'thumb-up-down': u'', - - 'thumb-up': u'', - - 'ticket-star': u'', - - 'toll': u'', - - 'toys': u'', - - 'traffic': u'', - - 'translate': u'', - - 'triangle-down': u'', - - 'triangle-up': u'', - - 'truck': u'', - - 'turning-sign': u'', - - ' ungroup': u'', - - 'wallpaper': u'', - - 'washing-machine': u'', - - 'window-maximize': u'', - - 'window-minimize': u'', - - 'window-restore': u'', - - 'wrench': u'', - - 'zoom-in': u'', - - 'zoom-out': u'', - - 'alert-circle-o': u'', - - 'alert-circle': u'', - - 'alert-octagon': u'', - - 'alert-polygon': u'', - - 'alert-triangle': u'', - - 'help-outline': u'', - - 'help': u'', - - 'info-outline': u'', - - 'info': u'', - - 'notifications-active': u'', - - 'notifications-add': u'', - - 'notifications-none': u'', - - 'notifications-off': u'', - - 'notifications-paused': u'', - - 'notifications': u'', - - 'account-add': u'', - - 'account-box-mail': u'', - - 'account-box-o': u'', - - 'account-box-phone': u'', - - 'account-box': u'', - - 'account-calendar': u'', - - 'account-circle': u'', - - 'account-o': u'', - - 'account': u'', - - 'accounts-add': u'', - - 'accounts-alt': u'', - - 'accounts-list-alt': u'', - - 'accounts-list': u'', - - 'accounts-outline': u'', - - 'accounts': u'', - - 'face': u'', - - 'female': u'', - - 'male-alt': u'', - - 'male-female': u'', - - 'male': u'', - - 'mood-bad': u'', - - 'mood': u'', - - 'run': u'', - - 'walk': u'', - - 'cloud-box': u'', - - 'cloud-circle': u'', - - 'cloud-done': u'', - - 'cloud-download': u'', - - 'cloud-off': u'', - - 'cloud-outline-alt': u'', - - 'cloud-outline': u'', - - 'cloud-upload': u'', - - 'cloud': u'', - - 'download': u'', - - 'file-plus': u'', - - 'file-text': u'', - - 'file': u'', - - 'folder-outline': u'', - - 'folder-person': u'', - - 'folder-star-alt': u'', - - 'folder-star': u'', - - 'folder': u'', - - 'gif': u'', - - 'upload': u'', - - 'border-all': u'', - - 'border-bottom': u'', - - 'border-clear': u'', - - 'border-color': u'', - - 'border-horizontal': u'', - - 'border-inner': u'', - - 'border-left': u'', - - 'border-outer': u'', - - 'border-right': u'', - - 'border-style': u'', - - 'border-top': u'', - - 'border-vertical': u'', - - 'copy': u'', - - 'crop': u'', - - 'format-align-center': u'', - - 'format-align-justify': u'', - - 'format-align-left': u'', - - 'format-align-right': u'', - - 'format-bold': u'', - - 'format-clear-all': u'', - - 'format-clear': u'', - - 'format-color-fill': u'', - - 'format-color-reset': u'', - - 'format-color-text': u'', - - 'format-indent-decrease': u'', - - 'format-indent-increase': u'', - - 'format-italic': u'', - - 'format-line-spacing': u'', - - 'format-list-bulleted': u'', - - 'format-list-numbered': u'', - - 'format-ltr': u'', - - 'format-rtl': u'', - - 'format-size': u'', - - 'format-strikethrough-s': u'', - - 'format-strikethrough': u'', - - 'format-subject': u'', - - 'format-underlined': u'', - - 'format-valign-bottom': u'', - - 'format-valign-center': u'', - - 'format-valign-top': u'', - - 'redo': u'', - - 'select-all': u'', - - 'space-bar': u'', - - 'text-format': u'', - - 'transform': u'', - - 'undo': u'', - - 'wrap-text': u'', - - 'comment-alert': u'', - - 'comment-alt-text': u'', - - 'comment-alt': u'', - - 'comment-edit': u'', - - 'comment-image': u'', - - 'comment-list': u'', - - 'comment-more': u'', - - 'comment-outline': u'', - - 'comment-text-alt': u'', - - 'comment-text': u'', - - 'comment-video': u'', - - 'comment': u'', - - 'comments': u'', - - 'rm': u'F', - - 'check-all': u'', - - 'check-circle-u': u'', - - 'check-circle': u'', - - 'check-square': u'', - - 'check': u'', - - 'circle-o': u'', - - 'circle': u'', - - 'dot-circle-alt': u'', - - 'dot-circle': u'', - - 'minus-circle-outline': u'', - - 'minus-circle': u'', - - 'minus-square': u'', - - 'minus': u'', - - 'plus-circle-o-duplicate': u'', - - 'plus-circle-o': u'', - - 'plus-circle': u'', - - 'plus-square': u'', - - 'plus': u'', - - 'square-o': u'', - - 'star-circle': u'', - - 'star-half': u'', - - 'star-outline': u'', - - 'star': u'', - - 'bluetooth-connected': u'', - - 'bluetooth-off': u'', - - 'bluetooth-search': u'', - - 'bluetooth-setting': u'', - - 'bluetooth': u'', - - 'camera-add': u'', - - 'camera-alt': u'', - - 'camera-bw': u'', - - 'camera-front': u'', - - 'camera-mic': u'', - - 'camera-party-mode': u'', - - 'camera-rear': u'', - - 'camera-roll': u'', - - 'camera-switch': u'', - - 'camera': u'', - - 'card-alert': u'', - - 'card-off': u'', - - 'card-sd': u'', - - 'card-sim': u'', - - 'desktop-mac': u'', - - 'desktop-windows': u'', - - 'device-hub': u'', - - 'devices-off': u'', - - 'devices': u'', - - 'dock': u'', - - 'floppy': u'', - - 'gamepad': u'', - - 'gps-dot': u'', - - 'gps-off': u'', - - 'gps': u'', - - 'headset-mic': u'', - - 'headset': u'', - - 'input-antenna': u'', - - 'input-composite': u'', - - 'input-hdmi': u'', - - 'input-power': u'', - - 'input-svideo': u'', - - 'keyboard-hide': u'', - - 'keyboard': u'', - - 'laptop-chromebook': u'', - - 'laptop-mac': u'', - - 'laptop': u'', - - 'mic-off': u'', - - 'mic-outline': u'', - - 'mic-setting': u'', - - 'mic': u'', - - 'mouse': u'', - - 'network-alert': u'', - - 'network-locked': u'', - - 'network-off': u'', - - 'network-outline': u'', - - 'network-setting': u'', - - 'network': u'', - - 'phone-bluetooth': u'', - - 'phone-end': u'', - - 'phone-forwarded': u'', - - 'phone-in-talk': u'', - - 'phone-locked': u'', - - 'phone-missed': u'', - - 'phone-msg': u'', - - 'phone-paused': u'', - - 'phone-ring': u'', - - 'phone-setting': u'', - - 'phone-sip': u'', - - 'phone': u'', - - 'portable-wifi-changes': u'', - - 'portable-wifi-off': u'', - - 'portable-wifi': u'', - - 'radio': u'', - - 'reader': u'', - - 'remote-control-alt': u'', - - 'remote-control': u'', - - 'router': u'', - - 'scanner': u'', - - 'smartphone-android': u'', - - 'smartphone-download': u'', - - 'smartphone-erase': u'', - - 'smartphone-info': u'', - - 'smartphone-iphone': u'', - - 'smartphone-landscape-lock': u'', - - 'smartphone-landscape': u'', - - 'smartphone-lock': u'', - - 'smartphone-portrait-lock': u'', - - 'smartphone-ring': u'', - - 'smartphone-setting': u'', - - 'smartphone-setup': u'', - - 'smartphone': u'', - - 'speaker': u'', - - 'tablet-android': u'', - - 'tablet-mac': u'', - - 'tablet': u'', - - 'tv-alt-play': u'', - - 'tv-list': u'', - - 'tv-play': u'', - - 'tv': u'', - - 'usb': u'', - - 'videocam-off': u'', - - 'videocam-switch': u'', - - 'videocam': u'', - - 'watch': u'', - - 'wifi-alt-2': u'', - - 'wifi-alt': u'', - - 'wifi-info': u'', - - 'wifi-lock': u'', - - 'wifi-off': u'', - - 'wifi-outline': u'', - - 'wifi': u'', - - 'arrow-left-bottom': u'', - - 'arrow-left': u'', - - 'arrow-merge': u'', - - 'arrow-missed': u'', - - 'arrow-right-top': u'', - - 'arrow-right': u'', - - 'arrow-split': u'', - - 'arrows': u'', - - 'caret-down-circle': u'', - - 'caret-down': u'', - - 'caret-left-circle': u'', - - 'caret-left': u'', - - 'caret-right-circle': u'', - - 'caret-right': u'', - - 'caret-up-circle': u'', - - 'caret-up': u'', - - 'chevron-down': u'', - - 'chevron-left': u'', - - 'chevron-right': u'', - - 'chevron-up': u'', - - 'forward': u'', - - 'long-arrow-down': u'', - - 'long-arrow-left': u'', - - 'long-arrow-return': u'', - - 'long-arrow-right': u'', - - 'long-arrow-tab': u'', - - 'long-arrow-up': u'', - - 'rotate-ccw': u'', - - 'rotate-cw': u'', - - 'rotate-left': u'', - - 'rotate-right': u'', - - 'square-down': u'', - - 'square-right': u'', - - 'swap-alt': u'', - - 'swap-vertical-circle': u'', - - 'swap-vertical': u'', - - 'swap': u'', - - 'trending-down': u'', - - 'trending-flat': u'', - - 'trending-up': u'', - - 'unfold-less': u'', - - 'unfold-more': u'', - - 'apps': u'', - - 'grid-off': u'', - - 'grid': u'', - - 'view-agenda': u'', - - 'view-array': u'', - - 'view-carousel': u'', - - 'view-column': u'', - - 'view-comfy': u'', - - 'view-compact': u'', - - 'view-dashboard': u'', - - 'view-day': u'', - - 'view-headline': u'', - - 'view-list-alt': u'', - - 'view-list': u'', - - 'view-module': u'', - - 'view-quilt': u'', - - 'view-stream': u'', - - 'view-subtitles': u'', - - 'view-toc': u'', - - 'view-web': u'', - - 'view-week': u'', - - 'widgets': u'', - - 'alarm-check': u'', - - 'alarm-off': u'', - - 'alarm-plus': u'', - - 'alarm-snooze': u'', - - 'alarm': u'', - - 'calendar-alt': u'', - - 'calendar-check': u'', - - 'calendar-close': u'', - - 'calendar-note': u'', - - 'calendar': u'', - - 'time-countdown': u'', - - 'time-interval': u'', - - 'time-restore-setting': u'', - - 'time-restore': u'', - - 'time': u'', - - 'timer-off': u'', - - 'timer': u'', - - 'android-alt': u'', - - 'android': u'', - - 'apple': u'', - - 'behance': u'', - - 'codepen': u'', - - 'dribbble': u'', - - 'dropbox': u'', - - 'evernote': u'', - - 'facebook-box': u'', - - 'facebook': u'', - - 'github-box': u'', - - 'github': u'', - - 'google-drive': u'', - - 'google-earth': u'', - - 'google-glass': u'', - - 'google-maps': u'', - - 'google-pages': u'', - - 'google-play': u'', - - 'google-plus-box': u'', - - 'google-plus': u'', - - 'google': u'', - - 'instagram': u'', - - 'language-css3': u'', - - 'language-html5': u'', - - 'language-javascript': u'', - - 'language-python-alt': u'', - - 'language-python': u'', - - 'lastfm': u'', - - 'linkedin-box': u'', - - 'paypal': u'', - - 'pinterest-box': u'', - - 'pocket': u'', - - 'polymer': u'', - - 'rss': u'', - - 'share': u'', - - 'stackoverflow': u'', - - 'steam-square': u'', - - 'steam': u'', - - 'twitter-box': u'', - - 'twitter': u'', - - 'vk': u'', - - 'wikipedia': u'', - - 'windows': u'', - - '500px': u'', - - '8tracks': u'', - - 'amazon': u'', - - 'blogger': u'', - - 'delicious': u'', - - 'disqus': u'', - - 'flattr': u'', - - 'flickr': u'', - - 'github-alt': u'', - - 'google-old': u'', - - 'linkedin': u'', - - 'odnoklassniki': u'', - - 'outlook': u'', - - 'paypal-alt': u'', - - 'pinterest': u'', - - 'playstation': u'', - - 'reddit': u'', - - 'skype': u'', - - 'slideshare': u'', - - 'soundcloud': u'', - - 'tumblr': u'', - - 'twitch': u'', - - 'vimeo': u'', - - 'whatsapp': u'', - - 'xbox': u'', - - 'yahoo': u'', - - 'youtube-play': u'', - - 'youtube': u'', - - 'aspect-ratio-alt': u'', - - 'aspect-ratio': u'', - - 'blur-circular': u'', - - 'blur-linear': u'', - - 'blur-off': u'', - - 'blur': u'', - - 'brightness-2': u'', - - 'brightness-3': u'', - - 'brightness-4': u'', - - 'brightness-5': u'', - - 'brightness-6': u'', - - 'brightness-7': u'', - - 'brightness-auto': u'', - - 'brightness-setting': u'', - - 'broken-image': u'', - - 'center-focus-strong': u'', - - 'center-focus-weak': u'', - - 'compare': u'', - - 'crop-16-9': u'', - - 'crop-3-2': u'', - - 'crop-5-4': u'', - - 'crop-7-5': u'', - - 'crop-din': u'', - - 'crop-free': u'', - - 'crop-landscape': u'', - - 'crop-portrait': u'', - - 'crop-square': u'', - - 'exposure-alt': u'', - - 'exposure': u'', - - 'filter-b-and-w': u'', - - 'filter-center-focus': u'', - - 'filter-frames': u'', - - 'filter-tilt-shift': u'', - - 'gradient': u'', - - 'grain': u'', - - 'graphic-eq': u'', - - 'hdr-off': u'', - - 'hdr-strong': u'', - - 'hdr-weak': u'', - - 'hdr': u'', - - 'iridescent': u'', - - 'leak-off': u'', - - 'leak': u'', - - 'looks': u'', - - 'loupe': u'', - - 'panorama-horizontal': u'', - - 'panorama-vertical': u'', - - 'panorama-wide-angle': u'', - - 'photo-size-select-large': u'', - - 'photo-size-select-small': u'', - - 'picture-in-picture': u'', - - 'slideshow': u'', - - 'texture': u'', - - 'tonality': u'', - - 'vignette': u'', - - 'wb-auto': u'', - - 'eject-alt': u'', - - 'eject': u'', - - 'equalizer': u'', - - 'fast-forward': u'', - - 'fast-rewind': u'', - - 'forward-10': u'', - - 'forward-30': u'', - - 'forward-5': u'', - - 'hearing': u'', - - 'pause-circle-outline': u'', - - 'pause-circle': u'', - - 'pause': u'', - - 'play-circle-outline': u'', - - 'play-circle': u'', - - 'play': u'', - - 'playlist-audio': u'', - - 'playlist-plus': u'', - - 'repeat-one': u'', - - 'repeat': u'', - - 'replay-10': u'', - - 'replay-30': u'', - - 'replay-5': u'', - - 'replay': u'', - - 'shuffle': u'', - - 'skip-next': u'', - - 'skip-previous': u'', - - 'stop': u'', - - 'surround-sound': u'', - - 'tune': u'', - - 'volume-down': u'', - - 'volume-mute': u'', - - 'volume-off': u'', - - 'volume-up': u'', - - 'n-1-square': u'', - - 'n-2-square': u'', - - 'n-3-square': u'', - - 'n-4-square': u'', - - 'n-5-square': u'', - - 'n-6-square': u'', - - 'neg-1': u'', - - 'neg-2': u'', - - 'plus-1': u'', - - 'plus-2': u'', - - 'sec-10': u'', - - 'sec-3': u'', - - 'zero': u'', - - 'airline-seat-flat-angled': u'', - - 'airline-seat-flat': u'', - - 'airline-seat-individual-suite': u'', - - 'airline-seat-legroom-extra': u'', - - 'airline-seat-legroom-normal': u'', - - 'airline-seat-legroom-reduced': u'', - - 'airline-seat-recline-extra': u'', - - 'airline-seat-recline-normal': u'', - - 'airplay': u'', - - 'closed-caption': u'', - - 'confirmation-number': u'', - - 'developer-board': u'', - - 'disc-full': u'', - - 'explicit': u'', - - 'flight-land': u'', - - 'flight-takeoff': u'', - - 'flip-to-back': u'', - - 'flip-to-front': u'', - - 'group-work': u'', - - 'hd': u'', - - 'hq': u'', - - 'markunread-mailbox': u'', - - 'memory': u'', - - 'nfc': u'', - - 'play-for-work': u'', - - 'power-input': u'', - - 'present-to-all': u'', - - 'satellite': u'', - - 'tap-and-play': u'', - - 'vibration': u'', - - 'voicemail': u'', -} diff --git a/src/kivymd/images/kivymd_512.png b/src/kivymd/images/kivymd_512.png deleted file mode 100644 index 7dbae604b08b210b328811e55eaa07a4ac208161..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30694 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�Yr6^*!j4`?xt=1o7 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

{o3)qC%_NL=ZyH!i#uU@H7YaP~Sij5YY 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 diff --git a/src/kivymd/images/quad_shadow-0.png b/src/kivymd/images/quad_shadow-0.png deleted file mode 100644 index 5d64fde5abd43c793c2fe2dd0bbdf9ddcfd923d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29962 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 B=*s{A diff --git a/src/kivymd/images/quad_shadow-1.png b/src/kivymd/images/quad_shadow-1.png deleted file mode 100644 index c0f1e22642060aec1971849ac7fc73c3c4a1f6ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30186 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 l{J(65`hR_|Q9i1{Yp%_~=~Fq;?y zt*%_Tn*6`tb$aTNL5&>KD_6`!On~~w65w3X3jG3=hkTyuR*6ID23AHSap@-*=yB*dd0r)YJXnHv9CrCK+ld3)kgQ zC|vGaABCK^9ro`rl1-s|$TI>ixQ%dy?z?W&@V7nx36`x$%3*4YkJE)raCb@VQ*Reex1#i!`QRYVCRr4W{?r&cv zHW7>F+JqDPcMH&k6z^v|O38Qq!WLVfx2vhA+^r6q zwuiKy>V5hN$>82t-f3#}Paufcw^Ugu+s<4AYwH04^}8p8qdPmLDl4-JO?yuO?^Sw< zFg8ji1m5h10Mp|S*tU(OgCnH`C`11lGU!|9CytYl=h&Y$$%@sjWWwP0y0p+44Dp%K zyqk$|;p3O59YV7Ujpuj7#=r%2(8?3OxS~v~!FX5@XAZamX6`Tki_qPg-4{_4RN$ItTS~_?D%>N8Gny3PW2=bT=9JBXwnZ3Imo*2Q_CftE-6v<2p+U!8Zna33jZ#~%sIdF&bNJIm^A76 zDcHY24nDtVdcB!Nl=*0CBYAlxg|=E1cN{iT^*xASTsrsdv_rDRWoyNx;L>;}`dNsm z2Ef(2G3;JENc8kUIJ{}BqHqv!Po4y9 z@$Fq58EIS{XvqpOuw$-g5&AMQ@pcSIR>6`|drg_vg0oe&%7U1LUYUbIl^4Vh4r{?jUU=Qa2-y^P6rnjW>UdaWr(K z<%;3BCxU}v=`-1ojXb`14qB2xRg8QBk$-OcGJiPp{OTF)#lV#;y7bDr)+b<&9{GMDlvO4Dnb z-=Q%!6lsbr0$xmI2^kJBSpk^12gBxozgb03o74+&lazYXUs4Im%Nj3Rm+YEn&(nZM zd%z?4+?_gNHI1M;x{48%`=Tt1)zCN(>ys zzC2oHBC|ir)a33orC2u8#dW!Co!nwSPl@lWAe}o>iVOo{pY6|0H^xw&2!?~GH>~R! z$bD%#ubdNfeQ_#=5Mvhyu`YBWf-54s&l&xKql)|-4)%fs{la?E>oQVQQ^$>`mKyQz zKB6vY`~ZKJn(5N~2QB#AII2`KrrniiIbo{W5)~z-x*=xs@rROgyEbEh5Qp^og}B+M zsXYbMN(HQTOga)YQ(Vc!1H{E4rkMf|efw`$3MvW>?0Ng;bD!x>z)VvGC6?+oXi)$G z!}6;nEkWgw?B8K?Z@zZnRb1`Iie4$-H)9~&_u1579g|H^72FRLsG<>_zxq)lGd?rc znC4VqcTY=>tT`9nBP>6E3VD~S?huJ8Tg14X7tWBC%hXQO0e_-fb-HnfM-d(l@qdll zoKydlsb%;Xa}V;*z4NBnWl7<4^Pp@>fQoLjgK95iW^o0>M7|=@rK zK0gQ1noxNu(!NOHhwIQ8a7waLULP~K@D*-DxHQfN)Svscozj@Nm+Q-u+aH#evB*Y+ ze4vM4Gn(eVEa(r7ytG_vj$_H7wOZf_xO9ozuVo7=4-?< z48~4e!WsDru)F{4IBnomqPy(<)+se z5?N5{>pdYQ{91Qn_)By}1*S^9;E_>Km<9`7@6l z7MH6pHYDyqf*HB~R_^xXH=Pf=ItgE%LA`6bW~6$vzIj)>%?o3&7iv>I_Q?S;R*l8K z&C#=_`IZ6LzxM7ZM$vfStokTH8%8RZbhX|%ltA1ePZ|8W-qBq=+|~*z9^O%jU6(=? z@s8Fx%s2g3PM2WfsEcu9Rn?XgD7(7HhtL+yAKY_f=^HM`06ymN48TI`P6Zf4FS!JP zgW~w%;130Q#Iu|;cYdN?G3h{R41dx6Ap&m?&+o;vV#z6_G5xLo{%!lBf7Ez2?FHw7 z16Myru&TC%OUs`f*JCJ{t7}`|JTy|f0;}ZpoF_$apJSY-ACJ_q(#qdsc>C^^6#N>W5#++LmK6XTPo@i#BMvUe^8t|6 zqO{F}4j-X}9KWpZl4(B7_AHNcBVU{-MDvu1FTMheGUySSZ zBs1~MTIZ;7`WIAa%hZf8$Y@*Sn92_f)ALnc;9Hs4*o+imbct3M|up@iI;ZPPES zp_2oN;sa*Vy?1UTjd;7t1SZq2L@doMeK1E8Md0%h!2ZhY2D{sNO}i$XN5P0P5BJ*g z8>}SeVpCmDbB@#(tUo2+ixgYPgaQ%x8 zfI~*_yHPT|?wmz(`(gr92V~b9keij2f4OZZ4dlhLVrSv;;oZn(?3zpX``*oZT(j{++jNS( z#*D)jHRYRoifeZB|9sq8R-Q%*Yuv>HHk4C8W=?dJd*x||usk!Re|e4af))Ew=W9J1 z=qzR$q@P2ptO@<&8E(}5=i$yI>-49^p^NSBQpf-54xwc`jyuXeZ6iMYz>3Mr81Sd$ z+z|STWneYIc?RMtOH9}KFfjjnU6~3jGlRs};E1zlUo@aiiA~OBLYN|mt{54TC4vSv&bAm4Ii=Lbrc#|C-=1zJF-UpD}MJ}f;D`-ZfG z^)!q$TavE-M79LfT)5Vm!>@g{7DV$Y>_Yx7>+t4*-)wXot3vL&*77Mh->SnZUAf}i z_%J=48iDXd$Ka#a#@p_6TRTKnOnJ|TP4!|=Y5b)d0D=+!VeFWBC{m}k4nmQOK5^}K z4w03!|9?mfu}!RG4zbG_U7`Lyu%i3$aJQ26rWx9Y1uThvYeHl9WDxEtgt z$ZjZDta6|A4}g~x0qOu(*_V@ylLxOnp67*ibzy%5)cue{j9&yVN4@` z@zXE-j58*t_Lwb-0JHszi>mQ@!l`ued>*piJR)sm(s;M3~YxVyQk^D(ahxLtRuI&`)r)qGg1;+Qi>y!Ljb8I_M(F zc68f9ja2*_AG>xoK7-BeQh}`*KYJ@QHWa+qLtqCntc3aF?g^YQ{ftLn5`A_*rRI9s zmtc@!f*hEa-3{W7gLznCrPD_qYA}b9e;*XGf1z#aEwQlQ8nKeisVQt6z z$zm0y(tT6jckc=A(qLsjzcT*u=JvT?aR89k*UdN7@Vxp;& z!|+VV-oJHH)%eMK+9kse)d1;sP3PYAm5s070#In10i!~~CmV){U&c*swMZR`_`>H+ z-Y3?L0|@qSi~QN^4m0oNxc!^Qr56|PA*3{&M-za2`$nFGPkb^Z*(IrYz)5z1x;y1r zL|qF@+ruf_fG()N&#&l#T`}!QQT{5oP7y{v!b|O#7u6W(IZFwLHEPTa<5LngcIVbN zXNPwa0cmonD9IA-o5K)j&jSYL8o`=LaE6cv+pMCdOQBDT;qkdm)!l>xWZ^(-ly&5k zP}2o3*kit0TYCp|ey65S*@!;bG=2F{nq|VVO|+t?ojEp(jNs+me(f$1N*JF=b&7J>sfA&FfVLTj*wXD5 zn!>>USl^$R?HTi&8ezXBT+{P0(s*{=ThM3l=Fun1)e_PZ7&7dRsmR)W+Hi}7%u_x z#waX%M(_)Ke0bydp~>io^tuWv0$DO6iZ`$p?!yjJEiSeR^wX}1!6ap z(Gh@_y?)h9gW_hna z#=-l^`=`BZXB66GqRs5qCxE?i2Jui!_Np!O4+GoV{*Ic=GBF5?2VHV*?zT{9c8QTc zpk%@!r1ZZMx3S8K&UV>73=$dY>ui+z0FZ?KNQ6Vjsfm|~gP3{fV$7+r=3vrzm+F-A6b0CN3jT7(t!!VeyGxekT^nttOh-k-zKAgRvR2En4MW zpl_KUceWawrCAL8L01htZ1L7WZsRc{DtEaE=n{D1z^YZoa!j985|r-M&B%EQNhP0& z*D-x^p8mzu0enC?$9WeD=b~i~P>Bxh%`VEUbco zY2kN?hSIrUO|;I$A=BaHx@JJ<1pgE3w<|aPGtK^FqsZi^TmbQrT)}$(JL*wQ=6~1h zrz|10Bd=1j;iEAeE|yBVcO9i8H&P_wNldjk`f+@4fyLV<35`9J)hcw=&_ZqGwFr3a zPyM*sH@x=cW;^ z;fKMX;2p7`<&!Huz;0m+p2*@F?nsGw;eD&K>!IO^3lw@Lna@+JcUxTOlUx#rP|?%q z_=`x5i_tP?Sx(hX0Y9KcU;8mrqifIPJvfVPTJ0h}cu#kNz`ZSNl&p~Yh3`p73An%p zTd}hkC63yY--t4s`Jx|Lx&XOFFt!eK>#o1{j&iEZ5bNSO*~8kbk?gWrO%pIQvZdm9 zd$uyO!9xg*r#p)g-rQncoUmbVNypI16sOPR2nZ@P)5{9(duHBZIA-woBJmUavpc|0 zciM?jB9zBLuRUN}K|Mdj40tJmy8I+?meKmUhxZ-lU`)f0TguWUMTnnp@jFTkd4?vE zzY|(t|E6I-*PZ*gj%#j7A@6JQA%xb&*T{_-`C~6&dh2*9$i-1R_)K$(f;|nQss2rT z*}J?!gKYCHhCD^%`k3XBOxQkjPT(7ERf|_SD9qv&hv8BDw?i5STtLuoM6I95c@KZP zx8Bz4TV@6S8kJc3OiiQGO!*xtl`%0YTqg;ws(&Q?{Pxp^TLs*Kkv%n&3TG7hWT~cs z&i)i~s;d6qlYnjN*huBphVlhK6;ErLSRt-ZSW4^>Qmk3=#`$wB=Wtzf!fKf4DWl)h z6Pu4R!=qa-xiRqNvlZ|!%jN}5eDLKG{+HDEV*zzpxe$1IGqJlVw1x%kYt?z9T-Y}t z`23aVsf?eWD2SJfp@GkKfBF2!*bnYKFA@VfrmZd}%H-_BP2_0| z*Lctx4^8%@#6C0lI3@w1w`~zU7Kd_vSF;5TkEERp#i8oi#xw-apH$@dH)!@Er`6&> z#R(=-5Hli94sxH?CjxA)IsGcaZcmsApw&>NERm?1l6@luXRO6b@f(USLd5O|XBWzo zma;H3gllR4e7CfZMs2Z*UKZ~a&k4IXR;aj2q@u4z797j@?c4$JEGom?vo+rG)=k?g zzS7|8DPh*wPA=y^dZDCrycjw{@SPl@b!WQ+e;&>~%+Rj$H*GO_UjSrX2MK9yJsxf! ztTKsh@~w&)YGU-?(yw#ehH;(>kiyMqCXSIT=vVvN{cIYEvmeGy-l)jA@8s_E0YX5y ztn2>b?4t^9I(H6lA(877n$HXBZe7>j5^213Bl4rc8!Ja1t++GFjYZ2Lz`*{9o6f?TzK+=bUhZz;Rg=>$229fyh0?4{hp(1q5*Mh%+p z9~Qs*_1fJaqBOVb`;p>11YSQla%v#s(5FWcEh%KlIgLiOr7ESv#w{L*2~tU!+Uile zY@2D#b47=_?@cL$=&39CKy9F~(=q-y?bL)26?D)INbl)^8(3Mj?07OOOdpRKi4vrG z;qw!d-9evmr)6zp(gWW;bevMP!8&`y6gNfq8>8X)djC`ZR=1GBpzM4n++?)S%b}lrF%Q15M}23`OFN zl;3y$O5RLLEEy-|jP%Uud_a#jzU^_4ghR?J3LH)N;t#g#o`&s(lK>!gi8Od2#mWC> zqvFu^W)s%W8f$Bq^}pGGzCRSsQ~nN|idXc64U({|Rkkl!w8;ZT0v*rY5rk0ZPayEL zUbFmZElgX`zM93GbM|_Bz- zkLI6Yq27Uq?Q@$oXXu?U6rTdhy*ZMeYyMcA^OR4_C|XI-Fj(8aG-vj+dv=4>YBvdT zEkhzB40O9`4(Qya2KL&dfa~{%_B~~#4d*kkUp~$ZyYusQ6IU2GkoAQJ^{z%EibvFTw%&5_2|B@+j13*Ld1!2Ig+B|5 z@Hu_*#rkbO*xjx%)!Ws6RNok$^_IQlA?jGw|6YETg-^?)hC?~8Vu{cYzsW~@{-u+r z;ZHwsd+?WR=ui7_#Fu`(f!-3(@~||7&m3mHW*1A=);IR(4aDE|Ji49Gi3BPua*j$&iTx+B`6)>5LvxG*5HG|@}GZVMS6zo3XOWiNiJEH_Uv9 zxS7|r*sE92iImv+yvIplReydscF6zV6qEl;)b`KlT}l*gi4-xqjD)>VLVLX4F6=x! z#uQ(AVLNe-9Tgeq@;;jozxLNGz6gAeG`&Na5VR>-f#q6o-OD}d(WmNOI!+8wzUlzK zg1oM~yC+Dc`7TukE7)~Pc|tYIk!&Bfv4bU5_022nj7aQFB-?He7^qq+aQ2Xrp=TVI zt`WEROlA^ALz_&xAZo_Fe9P`2_|=DvzNtfxe*Bh{a~6I4foq67ymC$xV5!S+gk-EW zN-L<2Tv1>idA^p&<{UU)dA(>l8V#(&x+I;4_HHMQoBmCWHQai?k7{I(Jq`vLWoa_|~=%;jkPg+m=W+ZNKEM(MZ&`5Dnm7RC%7T6+=oiQ2z>19`{~~ zbL(<$YxRGZ$kMS4z9Ib>rcjL!D=Q4z&%XJO)YS}(uNz%%4Rjl=u$7RdsEr3 zI*}U!(XzuFda8b9xary6n3u?l+E-(|ZY5W7yR&fH<3#;l(SR4oNYQ@Oa7$`k5hE)2 zvt8DpRGvLu%{feW=B!2ckFUVwy5KKHBidwJDE@;Da0UaQG97120E@h*n~}?ciM0SQ zi6zLf?iXh@&_Z`2TE)*RrPkJ1NR$C*=64B#jg56}u_W{?WS^ zKeG6mJ)zgJ&V$GH1fYl3;sR^b=4KRQ@A3G53E)K1hiuL+O+K)W{n1suBZ1G(&e0#* z89^@oZfZ_<|C@2HRKPY1cz-`kfyR;ne0l64coazjfUnGct-MzyOXJCvU}t0-*Ywfj zt=ik{{?hAih?N}o1(GS{;nc3ImXp1^O>O91a9k<@rpl|qaK4bUT_|yF5tRCm(BMpT z>!EZor84=S^-xRenP`iTC~!}ZJ>L-Z?a-Ra65hr=ItNHKL=Bm^g7mt74 zD@=y%&DEIeThn|kX~1+DcrUc?%CVUn0w-Ayo^9&odP%T?JjJ(44&J*Tdd^Qq!>~Cj z>=IE(*74T1AlDNC+_6DWJ$3F%8GimJ z;1#l7$R*H-r}Kvn8gMGe_Ji>TW($s0tuPfm&y6COUbZHqOrHSK31EGy>mQ~XS!&NJ zK6aa{dgf7B=kg|_lHrdXdoS6IOz~KC-d8^rx0ee*}X@9Ymn>MQR(L4}m=th@e zI@f_#?#G<`LF*fNM~=$7{FSP9w!8*fm<1Cfk*=ka(Q)+1_z#S-6`*men_e8IKQ z$L13kr-yp^cbn;(WA@9%s1zr+^w{t?swlU!doudy*6Cc1+fy#VdaSmf0{UuI9JWeI zPp9mB0H2gX7|LE`O5^=&rxh70jWj&FUCcuA*!^q2RgkX6PixuD~|!=6huLO8cf^+ZB$bR zcoa8$pcceMt4a51Y+jKxzN-H8t-hP3Zs_DgMLlCskHsoAJ;mfHwDo6*pa(OO{tZUVh!aY zA(ewHZwg`so*09EGx}Mq;&S(}UEv|>A2bqHAYb$vU4I+TfPd{#Rh`Z1m^%6XwV<2| znmzrh+CF3Sy?f3xxXL49X3HHxYI-c6yH`*DM}vO;$7G+W{rTeA0Qi?$^X$cvyznuD z?SV){Oc{-ajn}jnJ)!C5N%DiUD=eaWUo*2}yPSts*#|)2@-hY#O?daf(i3~ZX^wsx zr<8L+Kd~fTc6`(=ys%fG5VeAg`?$V+r&1*fvy@Mmd^{1_A%W_e4AzxJv^BR})ujx) z)eri&z7p_L%H9}6P3$i9^I0y)jh6H`NOU(W89?;OL(SPA5%uMj>M#HBJHhsE`AxF# z8S>(Z<}-aarNmlRG@cFb!Zjy)_B>CdH4=h0iRWz8Z7&_7kmn4h7 z7ylET36IM{`QbDa6G^A6P$bcB2@^wj4Sx9zyetC0=suH~D=&@&IoAJCn|l-g@wq3A ziEu2H5dtau0d?mkDATc;cYXeNX$jZi>Z73PCcKYI6d&O-AP(a=g;JJ_996mfBe!f> zB8g-6kZ^D+wm&y%D%7!QO6}&&8uTc0hOS~#punDv3bI5!5mBl?55@uhB2``XL38Dm z=r8)YToS2GnZ`1Z@%aql@vCdvehD;qgnFay{+r_GF1X{qBZbpfJkCY?jWLRnPmWYDe*P|u7`}lw43?H`ezOu?e~Xv+rs@cAi`7ckJLKCdv*HI-h(PVgF?9ox zk1jm3-JK|&f>#!56c_#1pJzPa_v5y6G09{8?0yPko3%e#u``G%2GzS3SJ}Q@620^$Q9&xAx_t z^nzM+m)dq|@Y>d!gq{Ii9U||jQtjA37%125i>7IC@;6d)MppX9U}$KbiB@{V<-uo% z@phJ`ggNy_Yz{U(@3D;OsbC+y6j-DP(|A1?&?-MA_~*4-HTODkx6{|)end&)cYfzO@%)J$?#g#Oqp zXe`&7SH>Hascc+WltpiL`ydP`FIZh0W7mdl9#bZ=$6lzk9VeVJB!i3GnptAEo(6SS zj`$4m=X7D}W0weha#kDYWvR8!0q}mr0K;r!$w2DMpk*IJRy-C~V0fSUg*F`;7R7D= zxa6ozPFjr7j0Vt$n3VvZMLdKF-R{tF`Ax^v7LEMSjD!H?d(sy%!dgFG=>t z4Vm;L_c*COK%a?mwHTw1^w7i`H77W8w#4n(4tMXwmlP^jM>&HQYBOfvkl1u#O@*^kQZ3@0f=aspu^UD4asOz)OYyK*oD%#X0 z5j=d=eo`T4ZDr(j@vTy+C+V=pt(}zr<+ste-yfa1)iD5j65;q}2&_>k#PO;=g*}3W zm&6^WQe1I*6zRV;_`!Yuul~CECj*)Rs@n4b4MwqoN5KMlkRjJQb(f``w-$1z*^ge? zeHp69xaq(8SQ%(9CX3T=zRRK{@UG(BP>ZcVwF^cyc|INBk$EdC4~EnSv}|eN?JC5jjYPRgZp_lTU0B?P7YzJ`m#Ob zA7C`b%0N^ce~1^BAoJ8OnSKW!<(a~QiDNq``bGy5|wx%8$5 z#@v#M@AvcCmO0#LO-=<)Wq#t5=RJl?`Cx1w+fj+2l78}(*QyKXQu zuJ77Va$70dJ*e}x_|Z!z9O0f{49=*Z3GN<&G<%~ZOm2h7)Qm7NV=KC=&0Qk za{HJy-4?fX-Qbkgvc&n^@kq;t0hFSE;!ihA8>sR~(J&Q39?p#A!)} zOcNUv4Y6ns1`sWad{+8dHS0GSNI=;?1Qnc{CBNOZ>Xx0B1=+Zo;U=MA2Z!d!t|vJQ zXJVL~pyd@Z-cx)fhu!@r*yV$E?|%7;!!GU&2#ogT0nsH_XE=-<@&zFDI#Pu-u95s2 z*vXS6xlILM7xkX_fm%mD>T}9^q$p6|T#Dz*=MW9K8K(kchQ&{E8_5Us}?MQC)4l8(R+c>1{P?@X@`*si4 zu)o{$`J(!G$$)fy@Y3mV0&h81Ja!Vz^2UiFGL^*5n-0Yg(u#Y>rMw<*95Q>ae$vcr$ zL%^4Bu#^E7g8ygbOgBPVWgI;*XCqZu#|_({<==U`luvybKOUSJ!aDewsrHX^j8gNy z;!QK(8VmE3HE!7WmcY>o79tT;ucNJBX2bXxR`1>YAM|$&psh597nbAyuMO#inV;>t z(B8dgM~?p**sHi+xk5OTyQQ8g5wk`Wc$^Kp>}bsrJw++iG0EDjntNa|3OZ)XdWysE zf2RWBZ|$g^a-cNQ!>0AWVJ+my0XRQ)3Hsr4{umn?`YR$Af!~Gd2>A#o5azkH_r&)w3WUO{!I#=bmbGk=UiE z9lG};iv_LgzYC5q+fpz`tM|qOl3vwbI0r2v0ikEOKaN&44HPvRjF@ae#3sz?mn_<6 zi@a6%mM6!2(cw{ouQ0j6n>(_UrQ;dG8S@hYsZb1j+c1}wYOC053d=K`zG#|%I(7Z9 zGC-_@v>CP7l-YSqbp4taTQZbVx#g-3N>hL zEi8k>#rm4|!Yf9xy|Axu-&_a$7n%wuE}Sl*;7FQ~D30);4c?q}8^s%g)fPoLM4X8A z90Hd#)F31ahgW_d4Ffsv)r>s@Z5Zv;|A=y(kEY~?)bI_AW$>jtyf35i$;P9+NFgw{ zm;W1MkSov3Lg&)+N-CWzwxrgAhdCY0oNR-yWzf`x&&(YI9(wrTz#%iFsuI{p)2pu+ z+DoGX_?z(Gr%%_zGFXBjT<2c83Z@L&=W2{>ki493m3MhpOH^)AM4NRaKd`oZdGS_H z8r3?6am#N5dK7vt%puMilT!z%PD+4&PblHjG+^t?6HAdwH$n{u8B1V~p*E77PkjK#vQI8c&Z;imIG@6xkGSDnm4DEmTtwbTf#sqibKc?`>5UQtsy9BZRAC@K+6j z$4$Q$e)$9zbG+Kqj^F|s7d$ST_HyhUOU86v=GFQ=Xg&^P#CbXPqgpfjvBwkr!c#g% zP`e!V*nj#^WZu|~KaNNHZrk%DE$Da+4Yr`=G3URSMmahAjTDp(O-5IG=klP&%zW)s zL;fsIq0x9aB~wLpPjhX$K{W4s&1?y`v023@6_noZgjz~r%VVFX6Atnw>uM|+k>udu z#$ z+CM~*eaGqgZ(_>H3)R}T{7>ALsB_&KxuaL)Q)?qSCP9(vz6;3~AsB$W`<7FbE(h-_ zk(!1(K=iZkc^3~b$y5)UmSEydm)G9v1BNPT;Oh+wxNwZBnNUXrBCGzRIcKuJ{;dqL zX|a(J$@C-s)h_D*J5kK$t#H9bY%LP&R$Pj z=LNf9f1r23LLl4eN6AD%x~hmp4d_p=9y8IPjeS7Q-{j`7uVA+x&7042(qutf-8KGX zA>35l1`V2la)1}$6BYLAV3FP+!H4ioY71L*4|Z7Nom;=I9BV%{9nu_Q{+)n? zzCRFs~XL0 zvfWMT<3f$zbaD;}d?11gLt&Wh8Ew19XPj)rkgV}@i7Fy6*V)CJoEzO#PSWbTn0Nw#4g0FUkS~N7*JOW_yFuA+68cM zBWb4lAq+WVN5(k8w}0)A{qxKyyLaY=HF}3CO+3DD%XYjL5qzS&>TDwHygW&fpCJdP zfEp|~Nkt#jkDAkFYBT7mgPfNgiWCvJJoR{Lx?A<@F7|4P`_04^`pnrLYK>p-B%j^c zXmBGmkN{0nsGg-=>ROi)Ek-Xh9XB^jYoOZ7+*a8}9kbLa$zO_XXy&}&si?1m7*1JP zbfnmM^fm)HeU!R5POIBtX6f;(Pfow-Y{%Y}a#esXM|klNj6dN{#%Fu~C+3;hyJw1t39=7K6BW;{;V61_xBUv7yHcuUuT2;zIxLvs2v?X9F`yOB7zzU&uKF17y??G;1pu_ z&8+~Zv#X@O9g!?!`IqY1N*9JQ_(NY)7JZDxn#K)9#F{To{FWKQ>xJe(6|W2jP7t(juKYUav^7 zI?xCw5Vf@nQ{y}R-3uVx08{E*(TZ||&>aTXm>XXj5<1^~Dq)c&H1?t`9u$utl)RRxD4uBeKR@CE*%V(_$)?H1Jy6;B3|{cp6IU)2_MM z=8m)ElZduesUyXkhyx^9N-Y0FayhRD{Y^6lJ`Bx?K<~uWww|zd@0FN8|I9m`((yhF zavda)&)uk|iz%^`bsVs)*VCFyIxu{Hb8`qPygFHAXs2ho zV8b$rxXCt=(s~sWHp2Dab!t)U~53(#(&Us7|>t3d&?KWvdE6d%I#+0LCvw@{x&K z9)7vAn!V|w4UNuqG%sne5-2Kv#x?W)r7~(}C%WFT2T6vSOy>>-=(u-6(jdw&m0C%* z*}-+C8&oE&)0W}4&)V+6JL1VdrqJ1*f_4l5*9+)V7t?-#$4hYmL|(J8 zn!0Pa8PW4g8lU)#pUR-`2e#*ZsRB3xBE5WO$6H8c0pMRm)9ZVvC%|s<$RsQri^iE8 z(Ym*5Gkhm-r~S%Sg~v*XrT_d}n*}hJGNK>RveNd%@&GjI#iaRV&1o}|+qXv(^k^k9 z=}ZZYR;kk9Yo!wA8;yr^1R>O$%cRkGZUS>ulik!ME9ySN$dpv_G$x%tj?{_P(- z!+Z2L98ttRPQR8HG>KEQJz~_4NtQZ=$R=x&pNekHszyz3>KDC|v@~XYms9Ji?p6tT zxu(dUV7yhT_`ttt4-bd7*{oX>J#s{w#4K^U6)J0HqURa#c*BmR(6$TX%KCd~PU_8k zQ>p+NGd=PjdUcLBT-r+e&%Yo+p)VkOU0|%FegS}%O~LexA+ET074*TfNIs8_*89hv z24~4=elssnL}}fBHnD|TY+vH{OM@V9Uy9VNG9Ok{c8`FhgLUqEQbvej#ebjae81h@ zl(d95pYhWIeh3Z%zpfJ)Q{&bxA_{T1($AjQv_6nj0wpi5WMS20gJD|$qxhb+1x$7^ zYk1GMBKEhUD`#`Y;s5*XHH;ba+pj9)OP#=kuVwAPQH%>}+WRtx9+)mp90TOOvuoCI zY?*?}g+860JPMELsOM~`25fTRl%5E8N!{Nng<)F2&iAYC7jmN#{5J}`oqxmTrl0F< z(mq6tqOvkFE5Y#m+T{!5A6gYepicwMOnKhyl$V@!6AVpMF>Aw`rLWBSj-Zi#BBV;& zRW@)t|E@OPOHz(pa)Y1{TzyOro4ivU%j0FweBYU@j{$RNf=#HYNw#X_xAysUl1hs}^Bz z*;XBs(wN=s-!PgNb!+`-9QWi}XY7xsr5Aog^hQultwvL*YK^Q5Ktbth^>N|Pru4oa;H}y{GLvEVGU(N0-(FNd5>gxY?sQ~85(w{7T=ksFX&rs|)v}SK z#DG62u|SN=u(nqaAJ?MCU=7%TFNg%OTmoRPS=BAbz_YWZW9!2c(zPZ3p*C4+QSCIO z%fRF1@8^tDmc67@w{I9?`M064d7iJ4xE{(=z+>3lvx7W1IN&C%#8dH#Yzjz+tZDlt zba}2zXiQEX#ki^G97M&AK-=cpyNG63W=6-GO=(288VU>xoK2PXy^G}~6h_TS%lc$zA(y)y(|z2CESNdMzSK(4ch4ALT?_gu!KU*PllvRu(0x)d=s(Anu3?2*$-m>T1SoX0aL?+Eq zRO+O;oiXJ~glunF|FphW-g=h!3D|ucx0Ci)I0 z*cvMX4ilCa^l4|$^FW3U{Z^Sj7x>8HmVsM=sTaHOay+B$V^i8#Kw;+BsUS{ zME=?12E(a`*1Y?`Mbp{whaYFjnf34!GklM1dFs|A8Xn>`xGFzb5q#QG3rDTpI7yubT$RB(~0MxnmcJBVrPu!@OHN z9_@164h2_o`P-$Qj~g<$4t%gZ>106z4m!hPm2HTWR;}?LrBdTY#AIoa6M@qd4*XV z_O;uARtCKKNBidiM`#I-3g{Qby*mB8L6nKSoHN! zx2ULS*r=#LN%VBUlY4*7{HUm!3Hm5ai;(K^J=zg{pY_nV?JxrPbX%bnidf*xGPcTDKj!P z_EJU91o%$0wB4X#j=6AfTvn4VB=_aV^-)@0xS)%V$~R{&>d?R+R{Z&bQ3P+a@rSa{ z`FYoTq?9LxHZ*FVHK+cl9@*EfYr1};FPB=o??Ktnr?=S01`WLWw-`h7Ao?G49I;yko@}z$ zuv1rYm~M-20xo_@%;%EJ!R8!s=v~Oa_ny&o(^DL^Io@_TrTOz=(*Hp^PyMJ;N0S$uLVyMEVkZP($)kCy@KZFz1gbZ5MEr9 z44L`>-4|uODusonHc#6^5G+&Lx6%L$UohU(bliS8RlJ4)tdJG5IQY|JU0--hDI|wi z(&%RzA1G*XuDS-S+7~@9aQAYU1WQ<1&2maK@`10;?5(Qex})P-PtCwV!G8u3s-R)P z_2ZUZ`+sN{t6WD1@dTd6cYz1VG)!Zl23orfjs71gSn&9llEkmpflkkyZ^ky|AnhwW z$%PIfYj;qr?)I^%W=1T$4X*QQ)1hlxz#u~WO;T&l23Vp$U&G#8?dGz2w|Ql{L0umK z7h^e!mlDN&FZ1u#Z9Ad?9A!&9+S<-5@S_<^1FWb{tW@a!yA`1Dd{F)3Ka0`e`eM?c zH=4W|$36yJT@suf-ISelp0eY3m8nwhjvsT;s#1-WH17Y^@LJPlAq^g~H(x*bS}c@p zT5SX0*qHLjXy>?QHC9ryYKic8a0{+(y^qhkzx{F`E)60Sn_nmynySQ%Xibi8O}XyV zi~+)ng>U!!*|`C?zId^#GWR=Gi5c=+HfykpYmKh4l6@~$UJatVK%Sb0tXqLz5?qjR z^|>MVkaFB4RBNL64cKN}Q{>^|PfQu;nJ0*oJ~p+j2|lBm3?eDGsB&ip?`yd&&kaOO z-KVsMUC>6&uN*B#W>kTl)_&U;X4Gl3rA@ou-wFO3aF3D*b@8dtf+=1%{Ham(g(@3| zlR-xhz5m7;t}`))k$h#X565m>XE4?Tv}SS2rB{qY#yhVk{7$DM?U|}NQDfNT;<83f zPewmtxJ~27_?}F-X=Pz8MRN`m;_YG7AHL<;|BARnlKdSL$>sJ+bL=7y?WtLvDFb4c zFXZvgRY9+%>GpzJIwFXF8zyF?L#O?0KYX@x>afSP*G z+WK+YH`Ysz^?n;cA8n1e7Qk`b zTIOFprrq#&176&MhQy7aj~_9Et<-U1Z7c{2NZ}_F6}4PfyPr|qQ?21qYoEt_<9hc8 z6ZWR%v~-56z)~zB>2|7Y2|;+}oearxTJ%i;BC$`XF*8OzeI4|il|*=$vni=pS3Ulj zd1J8cXLG-mrH0?46D;ofo|6B$Ita&XqYhh|$gZtEiW$-FI`O$AQFw#uLf;5-(USKz zx)l?nIGb=tc7K7gzXg%A`_1t<4XVJXQ^N(JLt8te<9OF^;Y9Ya!U0jEW}jg+bkZZ-J;iD<*F_ zvw`56dEK;wAc3&+)`8dqw^r`GX?W*&vb)VDB{e{9l0U~bG!_}v2c`|e8}gOYF;7O< zaL{`m@}pLkDPu?oLf-z*6c*c_K(J>2`$tVX&e;#e`ooI2cz|qgKZ}svE9_ac6jtey zOQSeUyDJHr$HPAdw;5B1?X8Q4bEZv_J8O5$)9m89kW872nl_E(D~3z1s>z;vl_36) zlNh~wVI)>Kb7eY%pw=yi*@vt+B2b5l&9Z$yeuRa}=9qp`-tt!oQL(fA|RThkv0g zGX0rp$eV;%72b)qLj*$o8R6ew*B_i1n`AC0KP{Ahg+umOfSctoBR*V)yZ5`cFF1+d zK@3H!)%q~=5zdA2Jv3sz+f4%G6jbF0-nA`6P2_ z<{LzX7A*OGlSfY$qoH$a93= zGhK%``*0c)h(rFe8HA8-G!7c#-{pWft`>tk`z)DW)IOMVyPA?f?cMvJ#XunZ#WUGs zUG~4~sFlumg8CPc_>e2J?0?G3%{sqmi=S$vPB$qH3#%iP-JqCYO9Ff#IIo<0WVdj7IoX!@#+M?2&oiNs9Ntwa(;a)^IE;;aQx)K5V)R#0ruE*WtC{MqAlFRo~AMbxt3c4*aV;utT7 zS&broQBcAh6{m@YMP?atn5}T2j!!%6TZi$QW$Vl#ppPT(&FX8#+oE>ViRr6ABq<&~ z0$iou*UZ?p85;gDIl*=@GoS@4nxA)xfyPe>d0OMp>$q|&;ZQXDCe60qp+pBAO7*81 zI%|Z+gb7iEZ?skp*9=t@9aYOcb@lq0AOAyJBq?@MB;f4*9buv3Ao?hlY>sc772V z6-WG8Sly6Shfua*LuT>Rkc%qE;@p%o-8Mz$NHOj>!A;lrLFd`7Lfw&`c)Z}z-h6d6 zv?pa}FEVX*BageS!-WM5VNTE9xRY;S$RsPcYxed=?x~ryKFv7DNC355bU`tdJ&B%g ze!y)@8^uDT>2_S%;KV|w1U@#3$-FABu3%a3)P*r9VB8ll*d5Kk`qBlAmEeW`2wE-q z7YRUw$liiTz!*1J!)3B#F-PD|LJf5N_cjhb9r;2p=d0BXp0QBVxbI?ZG^~+(9Z3u{ zf7Z)|urhi_`o8`9Bu_9-^(bvL3K|3ZvfJtp`y8dpTo|w@!dB_CJ)NAN;z=8Q;@!`@ z-E;aiyhSxNvc2{!!(JZWp<(Lti4M9hNk34lZE+{6@3|FXcq7URaV*@5T*Mh&F%V8% zVVH7Y>6z#AE93(YIg}!2rxkKk@Rh>VIz;?;%eTv?<8V{Ru6CjghahEMC}B%r1XG?) zv=Ri?;q^+bi|kK<(|m9YRFzXtL_ToHngCVnG@WX^FdaiJ?d+J3gCf*Z$1&G)?%ukx zY06UyvO7&G34*H;4uFD2V=#(~3wL(KbY7??P6WvuJRgAY{<-wXe>(!tE#{%YM$4?2 zvfVee*(^FcnxUal)-`xs&UQDr1lM!qyUo;kmvxFoxHp~*Dm@*j6t+IY{EYXU4UYOyHhI8d9*6rEY zwF(#r-(_=(9JJ)T)Dj>#f)S6x@97q;J(ls8oEQNy!(|^vVLs}%0hWWX%`jRC#CvBb zx_>(>WVxU4v7EQh6H`MRs7(8qTiZ1I_MR)K%OGQ-MX~57zH!fH<%rLMLY@b`=8YPM zAX;sSBTsDJ*9TDx`b#GB8nKTU{y6+~p|(H@O`@g`;KsQXJ3=IEvcQtek$T2vjIY;d8B6)MEFJxPw4? z!F8{yJ1HX7EBX5`a5?iYL`Gq5^tZGSX@(+GvVO`NAf~*WIOz*b z7Ddkgo+Gt$gcpJjmTp(CvNi?ctptCD*5XkbOXNcNg38{05J# zQ#l%;3qHJ5cV7{z!q|?d2P?=vww28Vf4^#cil}qBO>HTuERfrtElqJ-rMHAl> z$%Ms-mb$>)_@pWgBBZGxl4HS{xN$Kew7f&34_)EuVm^K)#V}P#GFNm;INBJ#ey%rS zNkvr97AZT@f)hyHDiT4%?K1URCW+8HY;E(S{400QNRzkQABF4fDphKvJAJ#=^U=FcOXn|umixh;7hP(#Do!mGJ*T9&So`~7pQq3pAO0K zc0W)tkP~qc2K;Z#H-+z-@16PZwo}Vx0W>n&^G>%xINn&my|#+{M{$UIw~|vgNP_P- zGUH(rhd!?7f*It&#XP;H;3#D3^spz8tkCBgo?8iF_5UzOQklsX(@CbHrye|S{pkp%3ky}Y%IpQZGMP5rkkz72PH4$(-1ELU8Da_vZ{kfM2 z2RU$Czu-*})d@(s8bt14d_&;hEu>@)Jv*c}0`|d=yH^ixw-mg(83Wto5n(Hqpt&Pj zhf{?VHXgtTZGB-dTLzkwYCoIEtl33S6)Vvh{|IA&RtuZ-)3ktYu(*B+#53_$TGG$| zt$#iSLdY3IiVJ()i}WBC;4M>8+M?$9`o@-IfkyVBrwt0&^HV#?81pyOuWsc|9l^&y z#YsfawoyC>{Ra0G+Ai+O`cR%-B-S-j)##?||Jcu@mY$?DBgpJf>vc{ATN0%oJMotx zfso%z01+=`3F+W6hH*ZQ#rJ#vKAW4JP9t>0ZAYMB@nPpL_wWFTJ+vfHBYPHAyb)7_ zsv|eRM#z6UQrxa*M%}H46QC;F-K5P&&yO+dZR(GBddhdSlY8|(tY7GMArDh{GU!eG z4I#wn5LO4A1@E@%S(| ze`a%_*<53n@iV5iCY!A;BvZ$RSoa#b_4j>-LMGlh7AoFC-8Y{%pPowPdug;{o=1|UhE8klk)ZpB3$uw6sOS0)&XWC~}zy1qz z2?u@uD(}&|z2QrFnZtdRiu8qeD;QmtB*&Xu4emRScII1WolS&DYPNA*$zT$-hxh1& z>az>OIVNe8o!8^shgW?Zx@9X>+*$77|5liaB@c;zNSMb&@2Io2)vDEH8t`arULDTb zwVru!P9-lXP{4o}fI!TjqavdKSS3~v&B}NLp5U%SVk5a=@iR?4|IDN_%DA*G_sz=j zWh}+`XDEIdz4mpcV-GvQN}OtWLAGWj3iR^Z)lLbcmD3p_>XxROt`KD^c>Y5R!QbUr^whX z>i;VF1US)*C_LgAZO;I2Z$b6b*YD2>ZBU^>3`qJ+yylrhzK`}VPA(g#dalBVnV?}( zOKZJc;a`T9o$=_3t?jUk?YcgU_$AD^&NTl#dET_Nga&8nqh+TJbDwT515Xom@{7LA zzrCKT1xkjpY&Kg9r$%py*=H3 z$FBdqGXSPE&=g|t&sr8#3<#EQDRUv2Q?#$?r*7K?sYrlstavXf;RM2m7Ria9la|mX z4;*(IrM;9KrcdGM&QcdX9H_0;FH3K0``i96*XHNqJPS8Q>f*LuT2q%vCa}Rex#G2b z1lOEiKvfcU_QHlbHX5Z3kTZ^t%9}V-)a|b4Xb8k6m2xqM&Q7~Z{jMe{BpC^$_TC-C z5yRMYaqQ!is~ZLJq>D>D%*8XL338XmL2b}4s}Br6yQ(zef7#i)l_{oB+27%A^vF8rXHZ)6zQvYv}Or^-(tQ)Do&H0Ph zU(628zZY|}Q?W`h_li7aNQs&C`82n3M})ytwU>ZG1TFq9Kfa~cvXId@0PmUca@jF2 zw4Rs2yC~F=422$cJaRnA7tv{WZKN$!rUeU8(b8wn_K1dH*EQiar;U>h z+EoQ-(+e9fM7SheNOjH9`{6}a4^k#8G9?p8+aBCOi}pz)nDyx*99TT;e(3f_bJeH7 zC}CqC#54ie^d{~Yd;}wS+4?e&FNZ4u2kWd#F{-u`9Wpz;Ka(D~&05LT%-{ARt{tI}6>NigX zIHdgxZrdl$mbl3&^Irm^)MNl&Q&h05FF;o-^@{YmJ)e(pD5lgMWEfBXQN3l%TOHal zye8c1!~$Dqx%mV7aEb}-r5qH68W_fS{^!RK9h^Q7bF!Vpjx67*(TgAC-qs!Le?fU|slEJd636hz zvwPR<*TVYC(3gvUsYCcMK9|?T)?7CtIKD*=H&zD~ZXAtsGE@T=8UPty)3p{HaP^%= zC~;4p42NC1#adJJxSHm|@RhZeZT45tRQSXQ#_D3>%E++W>?m>p?h`5FQw%(AnZStu ztn*mKbTiUu>B*RpUa;Qt58i$COLZNc0g)0bT{{$dh2!)WY5V|JZVo<^?0|+)eBq|_ z*D$H^>(&`zf!J}))=Ij6H=bZ@(yOw3*#N%6i?cqN^5qS!B(?^5^U5d1uI6!9x4-@( zO~AEUu%3`%6V;nFI`-%OojEvEr>e0VCiSljwBXkJcI_el?SfQ0ovB#(jgvjk3qfA9 z*RY~&OV+ea-d8J4>&77;!XhF6!q`Cp?ZG6de1GE|N`}6!t7k$}^P|J8HsL&Khstw1 zX3FWiHmL?gFq_dQ+zLSwDakZ>frO`W-$}!3+W*0}nH4fd`H0uC`5;L<-{)1NA0^Ab zSY{LiTb&jKM%+H6_?oAjo)GTIEv*eaA~U-I`&Ns7nss~;gP|3q+I{wDI| z39n9acR9NGheVYF zbQ8fy9o)4-qy{{9f{Ei1r=&M?P*i^IosLI9xeGXBy!DG!$_@H9xmDMs@#`unE@M|p zmQDEyxfK=yAu?XG>8hK|g1SOSu5>P(u>V;S?j-h{pl+`yYo+?^VR)N7xC6OpG^LXHb}Z~PyJIVbicQ2?m%`c+3`;jK)ernFSt?$=}7mt=5!CiZcv zE;fiCT|iw4_Vce|syVU3{96Q{t-45SRdxqk1NAs0Z2xNcy1Yel5KY)@ zE3b0X84f;&qh*q`$|{apNMdex4%{BBPvvKOvgLh?GxGyM5BdgIVY>Aoow1m<-i4G} zQpf$t%Of%6x}P1yHmEA(v>~=Tmk7Tc{nVRiciy2JAEvdaN0F>6x(O4@aywIFAh{=I z$i=@j!!7gmS6K*KZVzt*n`D{^$GWGAG>sK-*qvjGuv(M;uEa3jBHr2kmOQpMt~eHY!PAwt8Xw#XT7x>O<;s|>{^du*%PWgW zwemij5V=Ubs6>gmn#-AL>@AUyUvMSz}?h)Op zYM9-pSBddS;oK1!^ZD6e%;(ZOw%zhR?yB8B-lh0ta9n~}B{DD^U@i1Z!8PdX?>ki^ z6?s3$_BQf52RWrta{g_Kk*1IR7dLZVAD9IW+q_&>sqg(hXSDs0SdneCn}zQ6RAL%; zwHwV)9ClrowG4Y;JDHjK#{FASE;PQ8FXf45)1%~aso{p^ipSP|$~)g!bKl<7muHj9 zt}L>}nF!g%?+YRQ#yVd8+qO1|2A`WaoLni(Orz}wq@1mX0s-ZUJHeqtBq`lxJ+iNf zoh-&wAAxlU(eK$3sjMMgNel5U73SD(@RYkUd!3OlS^mYPM*W?=7q6*&^Zrtgfkt}H z!OGpWhE!o99F4Eun<+m9utY%@L+{$EQ^8#Gw1gFh1s&sL!xg^uCNgVRYpw3u$5nLa zkgn2gce0;<=!L**Y*UmV1O-c0tMH`q<%CroFfrEzR~w)E7&5E9mxJ1u;J7?#1Kb*I z1Ns8{N1%CmigtRnkNIR!*MH@J$?jTBikjW;v7+imP0f|S>66ByPkj=c^tp`lep0;( zGdfOanY1k03kdR#`tIY72TUregvVhVLHLVje0L@%cud9^Hb511sKrH}g(Eb}4Ci!q z1l-T#tVL=bna|yJGB_cIM^!$$qy4M4aprO9bKS}f1Vv~MVv9`u8G|E_!`s*Ff1sBm z)Q=tR|I5+NadkByejdDU$){npf~UTT=c6m|Q-Z#$QGJSJNoyp|w%}qWZwBE-EgC** zXfx60c5^Vq>M_xfZooofd@8r6z&25<7}d9yk@(SDqD*}wM*0FSeW(vA4YZ#`hg8wF z_K^S1LHvDkqt9+5%Q>R6))lKV4a0M|TiUb9m+rwCDu|4H`;BWfA;~dxLyoH*khf(l zq#V2SW-&%8dCVbg*789k$)|Zy|838OU7xX~0XNx0fX5VOYmg9{`}NGe8Ef0oo*nyg zrl?>ktRQSCu=QLbqrxvG2G4Ae#+_JTytmvNe z#owP#Up>mR562Ao7irYbq9&!o$RN>cTYs33m;n0jX**Wc5aH4hwGkB|eg9OW6mnP% zD`okgx^^(+;QJOsB}u_)(FuLAIs-eaVknt~2wHoR%4n7nQ;?GX#C@Km=uYiCxP#U8 z`NrrS8CW2nyDq{8z%Cxv{D2%o4*}avPcY-URSI@sRiV2u{I}(!p>N3SqMHnc<0sVy zW=TXEsK@mykx?Xv&`FaNb+&1X{ZRV<48*1c&0UVcWPEK1OU~2=(@EMiZQ_hB!|3E7 zJA!nxndApnEsDkA4-Hq%1_S6hua;R-sJMZii%vuSaIG=7^ z(w8Qurz^~6!9HB~o|W7cbE3<=qe?EU?NY|#9CY7c<=H~~BY#3@m!)G}%Ik(GC9 zPp@*|XXseyNxtR9MSr`9*T_^_mifQr*Gx7km!!GdYVaB`{0hccXX?A*&=Q3veSlLg zQyf!nZUSjv!PIEf?SLD0=z8ukO74ZTdJD-ZwfzUmNjMBSWXbMM%u+G-E7UYP^@Uw% zpo&gSv-ss_6y>U#;xeInRwbqKszb^kO<-1|W{%}gnq zW6QU1@-}3#jf)~s6)_AKy~`zl7dPf@;)B>>cJu6G;>yczt;|1kS7H|eKhuLWY(Ml| ztAQR%PkKcmqb&7#WJ4HwE4skVOLImnd|PXh9_OEvrj}H_a zksabUh3y)=Q;pQ%j4x3>_fL!S78*hhmyhj&y6y+!gR5OzkfPo zm*F@5-m9(ow8@Y5bHiX08{;#|HH#|#soLRXnqY`s%jQXVuAaBG*=$R9W03vZo9Y{Q zx4pOo)Q2MJehF3{#nel{yo!Z$$#bKjvpv3!#fdVUpH3Q<-6XHTc{Aupq2D~KPJAoT zq_P4_?#`F@)bcvZZ(vR}SdPGZ<%i%*RPnY^9a-h5XZrVU__%_}-Ax*;AMWgb2ri!^ zEviS^GNor-6_zV6Sj}!8dM4lN)j&hFM4S|(dmh9pNPnI85dbjIwE>UMWd7T|pvcd4 ztMVwH+nhUdA^g_);yAkCt;UV$W>4HE1V-!s(ld z2hBD#J8p|`1tzxmtzAjD8?-ph*HeXbqNTo|pYjbwsvX^$E<-w9quPlWvaZb-&O-AmDrjh9SY5@Frvb*GKC5>BuWTGZYE-58@x{gW+~ZfGbRZ1G&)RqJ0> ziofxSO))+0(#jNB5)s$3}UI>&616K%p)aBw&cRD^ffT%0m&3qpVce zrSb->7-*Q`-V@rw@E#*V305IW)yImDl(eR?-r!dU*B(o@`7E$;y)8K+JpGx@^eyde z%q}0~2?LE>96Js=ujLw{%K(~UGexxZCv=S7d<#A>UIkeWAI1gteVw3h{~~H{V&&W z3Unc_)=}DF#rwe>TWMq+5b9mT)E3c60;-apzu*$oI)ll z3;C-G@gv-XlY^6;9*SHZz|?^j2wTse{E8?ye>7-3{-ZeV!6!5P%3nXkA8z))HqwJ~ zS(0}FS%^mbp-;}AZxSvHD2h@*VW8efm3<7Dh4=B}Gm1Dj3{X9=?55M3319&0Ke>c- z%C-d4HSg8>{{~q=ny9~5%|W25Jr{~eQkXJ^_bPjkx*Gt^%-Xhr7i+UmFf#)@7tNay;_!zEHLN3dlz|__>>_c7vI``_*H_N5Sp`>)O;G%JZjw+w0NEUuXS6nq^I^>h5U+Jx$^nV zob*T9onPLRtpdyK?5L&e__Oe!+~2L#n=J#P1E=F>_TJx%R%e(z`ZJPsR*3F*QLv}L zVwpM<34n~mWTyy_kpQPFTa&>he;yQYAbISQ6q~5y2+nmkW9HBP2?@5Zx1G>Z8zH9l zTyQLQ7=4;MKWN#H+#=s^xV24DxZ4!XidJ4~)M28n#B8M4a>}5omn7eS{kq1izMt4g zlT}aY!n2G%lB!=ZSfaayqor@Kn8HG`oWEZVcVFvqdi+8j#3A&pzc93l$JF z2rP05_TY>u+>2rW1qqCK#7nSk)we%P;W4cqX8I|@*zRKrdEhW#_ELkm5v#tkgmV6) zaSg+Ab5jd>R>X)_8*#SJ*2a;@<4R5EcQdrPfsD>L480 zyhUPrcyX2BY7~c?S~OCl5`fw!$)U{0592vR+4oQQYaHEPE^!Xr2k2;k9JZGpJWKWR z;4q9MT+k4^0gH27vBlI)(r7)=8)$!Z!30oS1f73;{%kctv4j0!$;LOgSP&4rT>bRp z0YAD3z31RZb4rb|Zpe8aG0)^+*IuZry}dmy*=U(Kzxzgyb^o>*wII`Zz}@jm81QN6 z4K~>dr^x5Dk>HMETJ$I_K&{DB4SN;Km;wThamRav!3<4R#p?klAej*I(`!F*Z~N#r zSr?VriXRD9`%>&g*yNo?qQ1-cFQD~$L{gX&lUNXN=fiH!ffCNu?UHexPD8Yc5R%?z zY4~zkX$QctV!*zXtZ-78=(eI>xQDG*(lWdW(NN{bu}KBJ!q(;~NRnQXsdvFp2SrJ0 z){7-i! zSpiO?TbGm3G}VU>oIr)#ML2?#Hlpst0rDJ$`1Azo&CA4J`k(V-wI*_je?Ybc%(*gG z-fWAs7zs2@J-dOT|6PxhYMERJ5NH?f&Y0fGn?ut1Eh#gl54iQy+q@(=rW9wrp74`Z_EPz)dS_;+vH4BwvHyi>ie=vzVSer8g4 zbK8E!0piW^YLz?w>Zj04l435x?r0mTqQBIt1@vZ1PGXIJk|IGYp)aY!V9 zhs^4d{GsbE`FUonGm;g=QLq`qIYgZ6R{`oE{D$TjwAPJ1=ykdV+Y}%{zyvh5K$8x8 z0^U}D-CL*5zaG!sm23?&Jz&UD5kLzV@-D6=o_Ar0x!%?qIV3}vQDFFw*58e$$AoGZ z(0y?1*Svi>L4$B^w}U*K1ZtMxxUOaUaGCAikd zn6A;7YhABjO}-NFU#K89oK<8(9JJC?n}MRrJUz~A39r1s_8+M939V|Yxnn&y;Ydbx8GZA2h_ebKkFlui)fkV6{Z7y5Fe@!scMFX zui*B=eAaQIV=sX7>}dmy61?$%uU43)JyfNX9I7A>)gtH>N2v$UkSt1#0QtC~;pk^xNAWIZW4n&q@9a(S^pG*fTJa3RO(Qw%RLcjfB&$ z-Tsm#*V|zYZlH2uZ7TepX&~Y^gCyzwD;P|WruqU+$*Sl6)9y>KQappAM8~;*D4}72tM;V-Sf>$0zqva) z-ykFkm6SrySDl#O8~l1c0aepfH4|=W{`AJOKy0<#+BQw5cXBJ_@$iOHDLm77~})jp#AzkK)f>+dDFZ)l;x&P`2;HZ^SN^wSCF9Po3Ms_DS+f0e_tq~#V+CLc-*PY|nxr@Q z`Pa309sU2)8e`2PRFL-#^4soDdl2}4+hqWX@_Qo_=<+{RZZ8k#si_?a@24_34x}0&QSH*LUKY?)m)p6f*r3H?`m} z^RVaq=V9cU6`kQL#p`w#+&9}loJ$4)2R-~1w7TB{hAl`J;+(!3g!NMmisH+?v59~A zIlG{02AW8#gy6cT9_z&Hw1d=mu5{gS=0eb-fgirE<<2e0;MbYpr)wq9!_5k?i*Y%a z!HY-N*g zPlcpFi4J{f>-y)mtRNG=`l@(Ntlk)$!v-`qfk-@&+V;syiu)THet)8Z4M|2jH`D{p z!!04D!t6g;Q$=h>`PZ8dbVorSRQ|A3J_K!NZRL6{2{as7$vIoXZhx7w)%ixbkZmSR zn7@#AF2_Gf)vS5%Qdp`~5x9AEE~%x0J)uW;98+;*I-Q-WI-DU}?u!nD)%B~KbzJ|M zBUQv0v^oc<=k`UJgVT)cd!~x5)?$4$v51bEJ@ z&92nc{ZW^tbcR?@(>k#-OsZ0n9(?gnWk$VNDINXz$7r&Wtqx&k--`Rd6Q34@CTeiP4&=hIWY^wKPGw4H=b=ZK59=h1^knaT>Pmy&h7q}VSeqqWM)mR zB9%=`Juj*$i>v{Jf>2V8oOHz!O;c=1(416-Fl(thC@8ABYX&K62~I8rr_X^$m#Uca`x~78QTdk5Hymnz&5Lzm(7T_EuI|CfluF#qjOv@ z+I7WD&Zm7g{BCM7Au~`a>ry+x8B*Xul z*o)TLTuX$uD;1UaSQ{e3bJ`+JQttI@x-&c>;G9CXa~Pj2%_Yg!iO=3<;8PI{2`h?x z8c`Tsfj_pjNQYQ{*cqnYIR+A=tm5%eS#7W>Yx}Z#*KuJWc8SSo7<2@7@yObR*!Fd9 z6dgbU9XFY#0=#R$M{Sv=#8|-UZ;NTE`|W%x|MeG{`-ts98c=sh$3yaXIO{bH7eQDK zfDMGf=u9M0zO-++WMxP7bYy3o-M@BrwZCo5{cN=urP))s3;*LFbEA|A5U@t|e$D#o zb6rVHCLc%g2m0%P9TBZ#MRsp3S`yJqCny8N|V^XCu zT;M|&o1X(bl@im@G@t^aqFOVP+5{g;x-rn2aJL7$^oMn@D)F0dm0Ck&Lk}fe6;eQ`AFNXW&bxKZ>P~Cu zZS|2D@mGrl%61cb5rn_D%^^SnSp^Q`JAkzBNdf!NSinUyX0SE?$$a&_z_(x4=66to zz4Whk!}x;WV92#2$q(*NULiQVAgsADPLr0~oy9B&a&N6LXKA>YzuJ!(BSUaCG(;aG z?o>yKpWDFT+{jq){N4<@L)}o>X}3vZr9+E-h`ZVE%Ok|vz1QlC#>1sWt5%%5xxVO& z!`JK98Y$BOZ)?EsB%c9{5nD~q^4*K=AG_m$Y4p%XV!4>skMn?Gw=H%9HH4E{iL9ni zH}EfLv`BbgS9&yzZb!xwJUH~%VI_RviUiOE5)GlaWzbvk?D9BZqt+HA5}bZhQzXrH z5#$+w^r^H>mGX*!_&bDci){M1dqizNY`Ph9T5;0xGRWc9m5tE3bi(y`YH&VzUt`7L z;+7Ik7J3`#dIX4!COq=Y3L^UepDnf-mWGy!509#;3+BPG4LAN?m-)j$*kcRkgD#X-*NKs*Az5Wj;d`T5gYt0nnby=Q!4VpgviAm5JHsds0YMyr#^yG%VL4 z+2fwAU5v@qF%fTffYg?OY`)|Yw%(?rsy8s)ve+9Vo+ec%u@*oEJ?~bncnd~Uw|nSR zHjF!E$*N7$^H%ybe-&0lmhrCwXD)WZ7xtLyd@@O#x13)uc1P1)Z%3aa%U?SHijE~czd|c#1kq^+gII>H z{*r85S7I(4jq3Gn7P6fC9~TCi5NIghIM<=(>D&7Lwc)z(PzThlBDYgt%n3_th@LuMQ)?okG zJFGQ?2&qHvN+KLr=igRC%fF&CAvt<{pUWMciF(d%)_F zW5%gWAjNyCh5*1I%wd-hF@_O$*HGO}XEx)&0Ie5SZb9ny@P_cI*RM`Jh>IQ=I#!Z> z;WwG{D#ECiorvT>foCjrwrNO>th*jC{7nEwLj4NTAn$E4%{Ii#$X>^=0j-8`ev&u` z(7-cFSZrZ)EIu4SF8@5{yL>)OX0}tj@tqEF zaXO+&rNOb;Cx{IJa~I(R#>O|g238Wg5WH>UnSZ8z9d|8|Dgv|*A$D}UT;4c$IlUeF zH0x~SE8viFQ7F;*P#m!Ubi?gLE_6mdPNPtD_aiG0Lwq(^*u>AR-FE@Rz%Q#2zim*D zInx|hC8+1G1SOKrAE12G^oXuzpG++xu*u!5{^J-E|4maTrIO}|Dh6uve{Oo+gAJBh zQf5$a*MNnjKLa}tvHy&kIWNkIni$21$JcGvGcr^`tD)g%YRyQtAnC=2B{W)1l1DdJ z+AVxaM{*ZgY?^qn9Z^8zOushMW50avsx*?t6RgECl?jttpEh`ZN4d>ddMcuDML`Y! zE()np3Z!;{q31YnQ>-KL8&RGZ!nIIr?^wtyE`G_+<$}zJ2pr3hKY)#$OY3A$>x?X_ z90eLhioHwpB+uLAG5lUd)< zFKhI%5xoylkvbI5cKQx9vnjW&cd_~}fPem_0r~-i&4V<277XDi{f|Yfp3B1@%;lZe zMc7;aFd%08?}D4|jbS>|od2)D};#k$}pBZv-bqLvESNd}CyRb=-I5wyD#FFF0tp>}+KWo29Vx z-8W>4Dd(W^LQ~fP7Xl2gjRHKPGf{F!!hy>95b^Norji_%6qHGTn z`+D@4CWxSd79@vkLR6;SOj|tCG~&9}3ailpE1_+@Mq~FFRLgiNY_iL`%>s6e$VN{| zxAxYZQf*Kjbvq0ox*DW`!&9(deu+ohNWi@!J&5PjL0T*AKt4n>#^=U040e|DZUqmQ z@A3ghNb#%g-`dj99C~(qpD{YXpEya61EBwFu1=T z&Z-p#2qaho6G?tm>|;uY#?mddppO7l870bT22q)Hv}4)|4MKk6Kh%8N_pvkbEGglm z_hEDyc&cUNk-*yP>ksg*x$2A0A5GxDYfB?{`zdRz{=c~_APxhkT#-&*?QV_PdUg7s zDsYR|G$6B17FLNP;8e{4a-;$o1(??!?5$m_cGgMI2A`%HChb~ElRJ$0jJ93)x`E5t z#dN*NP0P7gE<$Y5A+9s@3`n{3_*67Ko9mD6(0g2fza<;6_-IFyyI(IXsGo_qvi7px zSH7r-ZNzR}i6T%xEuYlvKYu3Ny4r8%R}#cl__e9n%w{&TnkH%Hp=8~o!MxU4%j8ul z^wpw9RP@bG!YcesVv-zrTWs2j|8`uLp|~#>z_WfZSX$Kobpmt&5{0{qR{ZanLMk7F zT81cdM>oeXz0Q|l0AV?;oMr)0>py@AOz_uHngj8BkO`n|<-{Fl{lw`q2jHh07bE2& z5ATjkhB^&B@hJz4pXzD97$oWfNZbMFf9P>me*oJ8ZE0p7i8W4M@UWe?6f6|^*{p27 zXZHW2?aia1{^P%I48}UvkbUQiqLOT59Xp|rr5GWyB>OV9L0OVDr0j$&*+FY(AA*(?b5^_AS#9G|H1FmR0u*w)t|Wr>taDHG|p zfU0C|fqu@oSpLO}eDk~6ckwR@(143A&Cw)DJ~wW8_0vr@YgUi z7AkYiK4z#D!;;Rbu{3A=ZDUW(##vuVDiwDd+(O9Br^lj`OC2xn^Cchs`klV=u(z-$ zlv%(b+NHr=Sf6w4`e{xj(T4t5xG6E}%7YKDr0zm{xHE=G={Q?^$4$Y(VJ1&UIx%EC7!|}oyg+9Lk-s(ZN7XQFF#26{h7bFW*?vzu3rVN6a6mS#6 zWWlKsOJ^!Q?ma#nK+6(_;oOzF$i-KsuT(rhA~*fnw%aY&69o*=DKuJNxRC>>$KlQ)iC+-_Oc0dqtyVog_&Pefld zINb7OY`PVmmUUQ~v3dNmyXJ<{5Ffwb=s!~FAfQapLtu^PmN;oQd}Q{~*R&a%n;N?| z!@n{*j)gsexDpHQB#}*^3b$e&-Uu2Zx>uvd zK)tWDswXwpc0>l47OxKo3}IEwsVg0#VK3`UXmAqMQi4EXb_ zT-tw8e;X0$!(YQX<#zIlFvvWu;hZNrz9n{&BiKw#p|N!tu>8?^pydF%H?URy@%tZV zhh{O@4OjobIH<+=PM1U8%7g9(<}N9U|IbeVO5sie7A(7BP7$UpcpSPur&?tLff*)c zI3V>^sSwA6weft3=u~VW*Eqn7GXY&as13BRi?_ZBN;xI}B6g!uGyBlCX-BJ0?pY^S zSIC4MY&61D+Oz@D5%s|H#!G8V7WjBHT1!%h4q8la)H{7dvFa$tp<)>mF369~_J{uw z9{7$uIVS2JNOg_M*-tM_5Zp7i5;l2R!Z>9udD@wufQC!3BYBCz{nDyx_-}{zx!sin zrWmdkg;SdtE3g2KZV|bDM*=l~uika87yrO=@fSO0_1E-6TMN+VrYAlVkGM?lH*YER z0G%)A5hE2u9erDQzpzbS?qK=9act-x$z6y99r;+=w>b)cbp!#Uk&r6>(%w|RT<4E9M|Mt2s7)P(?k&zm=&=mN6(mSf3J*Xz5}Ox z1csX1nl$Q(1K)EC;X-@G3@niED#4A~X~>Q818<`?y%5&Qz)#%O7+_h*n_Q61m-wf4W^`*t2`8q3xSot7^Z@D z*k9)&?M|iYlj^*XW+THnG!*EL(K)O#6d;J6_7Dq#*0Esp8ArZa33BS6Ce z4xFhi#*eVNHr$o79+#wClzcfw7`>EG^fm6&^#ODon|rQg_T*!!4t0oL!P{6Ga?dvQ zW<_>R`8Dhou(B`VzZISixpuI9G6|wY^+H0#3|Cl?4?BE5)La4HygK*a*Im^e!{vHi zJlaKB{wzNp-Vc{_(iX1*2bPCWdjkc5gfQ{UYJsHURo!<4xXGHq znFevGH@FS#ID-k8agwSL&)M$bfbWW|q8sh0m#C~nzj7*zGE_n$E^8U{*Tg(>oga!6 z^m5mZe+bw%n4n1GckPix!xsZrLv2&lh++H2ZBZt7L zyJv)&yaHmo*Z$C6!jt+E-avmQk^L5D%+-2z&4bo7R|>F51y&Y7 zj0ac=k14+8!eWo*gk{>&RUQ==IW>M7LH+_+Vli3Yfr;Js==Fc%jG=nO~ zkR6f$$9ovh)b-dJkJy!Kv1Kh@DkB4iv|qCl|Jg1DCe+bNTSb^_`*VY0N&~61_>nus zuoIpzqXE5s+QUp|0j=~zZYk1yDjeuyQhbWwOK7-k{vh=?NpAPmzTAL`GdK^UB}P$* zg$hrxSHlkNR(u45P;wQK#gzSw&rT{E8~V^WXp1pT`tuOe%WV&Ime^{WEsu1`YNNiR zt(Gw39ghvu1ri=APq-^-u9A=sri`WA*>N7gi;S1#;*cz{(?s`fl^GA#7ASUqTfi&7 z;UC%Q{d1DhHBNYESk~<|1@aZpf`nNi=gkGzX-5EWBp^Ru6&dPa46V6>stri$38>45 zHG~bYWjbkcTu%iIWQgc$L*kmH+Pb&2IK7lM&mmRUNp^}cZ zbsNz!fJ)>Te8Te@Y}rn35X*KHcFU7@@#a_BQPZHlx%$%@fyq2MeJvl?kbmd>QWph$ zvezQXaqb0oQa@kWF-&st%YQFtrSd+v0TO1jq2!-`P)G8tn z7vv$d>NEgnbmGkGS58Dv_yjXFRI>6BSS(k5?7W8xdegKxNu-)0lhZ{o5{zJo{Iy;B zm{4 z%Kpb7Q;3JLnO^%y_aKDLxtZ|K^MrUQTs`~oB~O%VkAqC%7jnte!e5}+`q@)!dk6Pj z`lZK_``c8t9!~ZLH9f~Is`qz1Bu55rV`gSt`4srf1#00eQw9a!wz2za!g9xJycnFL zLwO-aI^D8tO>HnN9jc_rA=nHvWU{~xn4b3hi972yA6miY>Q_J%cZiimgcjFXw=9Rk zQFpqPH~Df_Mh*EY4=KyVI#RQOQwvvgRKo{%-O-P|!U5}0^)!<|Ke#1ttofVs40 zmL0Ph{_`$o?Z<{3zHaT`V9mDP_EvtEtzZ7b7g=dLJd%6Rx+O#fJzk+_afBrwbsBs| zLJ4M{wWpNT^!OVebf6`o-zNA+^nZT45d5#7KtAGerI7(Y%IK4{UP*m8CYxKr4|rW3 zXxcU~h6ZmpoBJZ)lSk^>aCkkCho#=+w3I% z%;p~VykA|PjZ;T@OemXf;|C*3zj@{U6Fby$lP%+L5#*z?52ZCyX<`IYjm0;Xhg2Iv zB@@{{RC9kOySeZucC+ZPE%Ezqm8#4#zVc^v?xXqO11-!EEn-H|q?s4Lx2dSJ`VPhj znv(6rsx2)|w!+h!N}dym6Z_sw;mBSZ@)tZ&Ow@?JKc3Vb+3f<6f`48oJmsiqGMz+G zT2sf`Fu<#MP(@Aw>GmAy8w)&KN!Lc~^I^)OKHSfFPn&R#q+hd7$F@H=syNOSjkk)+ zv@e<;G&BN@b?)-gR3O2z>$$ROJJ$@y>|6f_{&R!~0&&8cf5GkUlBQFhk+F^By)jZw!ZRx`*f6V6*<}U)xJZTh5NPqNjk>J7pFgZm$YzA!OKbdjfD&>1?%X}(4i)s?$+}B$DzLj=+sfnSQ$G<5?jbQOb)W$7^t;UPW>=;#=*lsqVzx<0g0WEQ$HeX1)t1RVX|sF=bA3lY zkH6WwcTV_^YxZ56DWo4GO|5+eGkl+oyOXvO>5-?@>dT7N)AGK3ln=40BgURZ^n}eA z@bF(c+NJy8`^n?sJp(#>4*TTv+^-fH&iZe~MOTae-o0{EKg+N)=yEE>6-W3p9CLI2 zX4!Vs=zkb^V|PJ-(w?Q^INBxrbLg1c^HFytucT(`D1C;9J1SUp&?3w>^UHq+ zt#ZEW6x!Im=VCU)d!myS9?_lnFvgWD7$cO_#m%#8TfVuK2d@bBL;8gy;{@nXKCa@- zj^st#4BV?@`m&opa?3ZXW`W@@GKBy=5`5(8r%HorGYHI6!8(PTRx?~}#Cac8+W?H+tBY24q{a)?za znZGupMxvHu+r*g-b(gsx@-~@$z%-+VMe!>8C5a8hhufOQ8QHfX0=R2kXA+!DhsuV- zJQ_XTQjbws6-B>@WDmEJDhBP6ew2;VDcLi=vn)O6Hon6cvR|8zKP(T*NIk+hCA0(ZT2y`P| zhw%Em2d-)xuRA&Zz{oWQ2Fe0h62h2h1sttP&PH_ov;U)xu2RrfqQ3m{-ZlBvP!W8! zQf+5qvV-YM+PX|pRBQVaS)?mj!Qnou&-4!pK}V;S0=g@_qqsFZGpF)Sy&gLOUq z-TbQ5dS(h5A$-!8uiW5`qqi^;tO4(!cUh>cUEl3TCx=-(@ISVR-hBIxcda2*Bay;_ zE@9}o(7!zz0Y^o=aWfwo%%0y-NxAlQ>T9J}Yb}~FvC3oyv)y;y-zci}_`7t^^yJ;y zsM1z0q-5Nqa@1rBKH}=wwkzzh120p~-M_YAw4)QLPN5)q7sX8|gb3k)+(oC;Vm1Ci z^>ZnuK$Q=ZMg~RRtT|6l*&6AS`Zqv=c8O9$mv8#T*qSVhw@ORiBgKc0g$`e2rz?;~ zHB}Std}C6l7I0KpnQ>a8-TW{b_LY%RkuLgc+vvJS)V?6QQZVYgUiG)x?0HJy(vJ3k zra7o;1Ic#P;&vR9hw>MKFrrqIqXZeFx&|7?)~DMkSj>xLc#5AyA*CY^ZN&^ORg*)U zd&%7_8#;JZ#!?=2XM1xlk2}e9@bj%^BjHD@(~CF!m-^D*LzZIuYYp5~P4|#V{(S0O zqRtMt$*w8lw^N~leJzMTx(nJpRNCoR3rC-h0f?ak@i|<;Cu>30%&u_VTzG37Q<(S+ zi^)tjmGVkz!x|@TGcbCyNytr~vTT{gXzcuXeq93n6qDJ)bmyHDm;6AjbIWLoyJX)7 zW^c#x-a3oMT%K>y=2VpjLQBeJY_VAuY2K)j=!vISGzRp?o8~-97h=@A|9o@1H}T8g z^u4y(3=j5jkEyZ_#4E(TTFc5)Fvg$R_6B%fmIs!5$1|4|T10o2cY^!JrQGe=|F9)i zr8MhB0ii?Z;gOHu(ND2mR6sdB(q_By@N-d>x3fiH4qH=~*54qLans{Pi$mtTGfIzS z8zOhG5sEdF{>+hv&G$-$N9ur)#5_AI#Vl!737?j%Q*;lyGSxYwnBUMUB+1e{-7Dc! zSUhb8TD-9|pl+8J>w-zAYIr{wr_41yq_HSwUK^T9#Zs zTzBl&$oY!zp74?aD#_7L#uC`XkIH+HmQY||YX)!?S1sj|Nm>9~i#=-zZFxA)CHN!>ag>N`x0|gF-~!6AbzJ=YP_mpId*fCwPYujS+z^Wl zQ{63zLGMPig0%7d`%rBxq+{XmOsApl2L4F#Ww6E5P-7daxSrszEvFL(#f{(QwFvX3 zya_2kf?+IA-V!IOW}($?V~gS=t#|;{NoAT2sDO?PG=0A$srt+E@uWo{R@kM&)R;f) zyc~uY3^8UYTx2dhpltP5S-;$UXl0Hc%X|7W4JLkfCYAWg!#`)M@vwvjR7zi`lDsGx z{v=M>KAwCt8~zTm(Fe3 z-_I7ILiitf>}9{(v~Em{Tlk);HKMtp@?My#<;0M7H^}8?hr{<90rZ8!=m*jre{~^( z4|-(HlX58NfXq<=F<82JmX3Vuf*(b12CbYdqCO^}@KKCikgCj!(8)^@USQJ8=4lz@mEYiWA&7*Pv&X-5h|_EgqGD@HpKI?fcc6rqu{D4YE5fE z!(1v+O>&;_!Rp`%>&~Z&9~IhDhj(L~;a~j3`cmMVhdzBJ!1Gg&uB4y#M}7Ou`*#+! znpcX5f;?*B`ETU;i#1r~1H%Oyg_|Gn{%+@T-)OY2ZXgqHd2)OPWwLV~-=0G(by=PL zFhsFPjlJ+0+Q|IYp2(Id>K%LwkCZ2OQFOQ&|nWc`iC}z2%RvDE{1@?tgJ2RTGwY zn`t5C1Y&z#>U8|t7+KX9bsHCK>;d)J5dw&tq(9b!6xRnMpoif{>{F zu*!h=gYLl+rNedxs=(1L3+pvOQziDwHdSpkFMC;n&e;2{$H7cmD7&|9+u7+c}qY}snZ=fNiLFdNUz#-sm6{MicK9vwoGh{8<(9Cs4m3Q-Wl!ho&yJF^YJ zdr5ZQ|Hx|QG{gqtd*7sVcRFEmzG6v_b;lY`(brHs4L}?-f3GgJ82*8_M5}l4C4)`O z(L!ZkWWtrQzv44b5~w9U#akm|WP;uRE|S^WAyjz|^N!S?%WDD~zrzsdk$|y^zWH1R zq49$3gw5TP@MlE_dx|uUG&qV0;M-{UyUKHeIjf&K_NznR68hcDHZT&px$#hZe(Cf| zGeq9W@>KEUkxs$hWs1iTsXP-2gwi(l(Qti)=2oFAY zaMpNq>tl$q*$hW$K*(womiK5D2qajiR^IOBh!^K&z=H^wQb-wv=}$M+BGqL2!|vsZ zwf0y$`F=P>G6u=jl3e(&O*0id+vJHV)w9&N<;Xn zn<@2^r}&w_?9FZdf%H``aU?*3Vgk^(tTF1Px%Cn7byLqbia+v}%So$93U#<9+QY;K ztq75!D0)?O{zR^70w+$9UzO)s#zkqh~@i&D5p{!}3pp@7dQloZ#zQu}x4-32_f<{t|oT#-S_BqZKYqzmLV@T2NX9f)$4 z#;Sh~JD2tzCncVx)T7@ZRdKnL>m*rUsCZ&Gf6`uU5sq|KAGc}`GM1j85)_A zuFyIXbUZGQGCl0a68CHZeFo4T_stnr%=q&iKJ>Mm+-m;U5>KpT*Vp>;$a+i5>{?*@ zhH=9bi9vlrs-dKb_`nadg7(KN!VST^vbeQF`9N6o^20{+9A0+4lXE8<9;3vaUQyKdkm3bnq$@0FW6klkb$={_`VHwe6 zEz?0qiE-k+>2r(pv&Fq+N`Krfn+o0ev)Nd)j0+4kfgnC$Uz#qXu7(9zJs2vnyZG9tA!+w`wPMg_S?e-WgH`jSEYxq5k2MitnH83S zFhbG%12HUR-f}QcYv!q8#mwg_m6~42TeIB~d1GB^7XqF&&n|dSTTk04mne|Anr~EG zfDPO{$xY1dEc4`)Eo1v9DyWK;K6S)&kVnFKVO9?Zg|fb9lat{mZJi@0Ymt6x#D~?) z|5fO}*@pvF<<%BjyCqKL_pto1*7zMl5v)Oi`SGeFY&i6%zHo3aLi*|uLeN6M@ei6k zPwGo-rnolcS}3~5YlPPE#)kdqo=RT?PK zx>H2Xw4IszM#$aPW;`MBSBZy=O?IPxszA?^aUc0dfQap5880AY$CBl^H2ZNhOb*BY zM-$ysm4@tA)XvgUq$~bD*50xGq9ZEv<|OK;VvjXCLYkq|r|K#rg=|Dq?^pfyc?uZD z{Vorbo;!D5ew`n*zi7xoKj61RGz@`#W?LO)#9Ia{+Xw#DLG~OQC)OD=g^56CY{q&Z$N)NYW z5r&!^d_WzRo>Q5)r$RLSFc96-_(iR;U6HA(Hqn#$eDV|#$kMywg;5cu3-aY&?sG`+y^%7xJ+9)>t0 zaYZ+}omL2O%9Ozn(rib*A|q&pxeA)~h*H`Vxu9Sq$~HXX1?4~S%mPDc??VOIlr<69 z?((|rLjJ==FtyyRWgleMK_x7p%l6bl?cXZzm#5S@hgZC;{|%&*u&CK@J|!*Jui`fH zM*)?Y#*fT|yJhoXpJ~2HGTYr}WTmG5G8=vk%lfwOQ&;%|^`hU;Rb=+4*HBY@mZB}I zA?sLg4*;{cABX#)sTS?i){D^xB)My{b>R;l<%LcyBGcB!YX|WslY+Fob} zzYyt_kG9SlC6EKCuCxysR4IwjiaoC-nC7AIjL*eM=U8;5-qYs75a?Gk9|GX+tMSCq zjmWsKx0+o$$By}1DMMMh9LDL@D{H84flV(bP?7ggK4ys$HDefdAxcB@Wby)8Ui~R(_ z=Y^C@H8}&YgxiTHfYyKPnzGeyjcjnMcox45-{S~Mvo)5M*A8WrQ}N3#$7FucQDgIZh|5WvwH&u%P$G>7EIe5T16LCv%WZ*&vC_==b6f;LQb$ zgSN@rn|{05luE^Ve)D=)6`wh9Yi;|ff1RX2`&|N@TxTPm*oO8|(zo)Xr~d+)i6R+g zr5zg`gV|9xefgE770q+^qvO6xdtV-TH>ru@t;#6da_&WVmB`NlFMbG+@b{cyoeLW6 zPsyCFJebf|u0+I_GZo62;Z)KyV1b{?j@-ahPdj$2PI1?2+mD~CHMxuG|GajB6g9X} zCytI74^Vssj0_=B`$#SckDZb?YGv{ZGgFlb|9x*MR|9&mKezdo{*v8%tG1g>!DVQ8 zDds<1T6a}4-sdDmc7%6$gyK_`j0tqSDo}Bp{;MB^+kClC&wKRnJeOgYO{z1I zqMCDfy}g^TrSg58Z!L~tvw_Cr&A~Sc|I@O?!EX>b(H;P#YZf0+U^`?gfdN%*68>4; zb8ZnvAphb&tcd-$96B4Y0EOAUzq2HJpjN<-)%XQx)mo4eqJ*jT-Hb!_`PGkfy@w|i zb?iv5+_2!+LW3#QB`FFpyPGG``hw^<#PyiwI7Gv+E=2ZejUqDqnE)+sVRWQ$UnYrP zyK6*G)oevhAlZ+~+vFt6eRj=crE4aUuxDBGZNG$g@_J?r}x3D z;}EB}U+F@@arb8Jn^;c96H;UElSIXFJL@6a%)I5jy{}@;$I!Xno9GC|pG8Ne%(dXcLL*2xBVnN`{*p}|*)z^pL#=k2sOpCE*WI^U`r8+ck+?QOGRSB7bEUKu z(sA`(3$u)|?9k((RC*$o0F=t8W}0ZgV8EDmX*%Y1s-gLHL5NA0hN?qQ>dlZ#^jjVv zEW<(|P-B?+`8Z-Rr{{_LP<|dfM&EDV=z{~-c*)$7_Z3-}8nmXxg;HGzbPkR>wndoD zA+6s`#aqyV^qeugD|1y$KQ)0F`sqH3f2*-p?o^Qd!PsCp_}HK#VGImt zjdBNKP-)($NXpV?+y`yO^R%Mh@0+|c8? z7Et#?^xkykXhP>wyHId0$JCt2>PO)+B7}#h$k!nI~9Mlz0a7|s>=y%+YwzMWBG{I+tW@OeQ==pb@ z%Gd4(1~VQiSH6e3Xa-gRi|;kuv}2)dskC=!9Kg%87o!P+CTgfmFuZQ!r z6C$Vc0$&0RocgcF9Zz}I^!TUv1>Q^!Dt6gIX)XBHp1G!rsP4mdfsYHGrwKB)8DmPPZ~)J9;Au%`nJE-=A54nlC)%$*B;AtKe=Bx z#jhA{@eJt@wZ`LOD^?_**JWkgbI0*4aOpED2mAy&yTl-r^R6Wsl+hw-~o(%~A4 zLHpz-A8D{BzcCpGOqCQ2xj%HUFS9yp(t+^kk{$+b`4ZVC<}ZQ3zDxlYBZKgWgX=SV zK+sp080GS2I*e6Kihez!>l>-=Nnr6tc!mi(W>@Jjd9h-Er{}P z@h50b2KGs|sx{syNJYFp%~^@?ci%d>Tq4+%LsLc}S1_dy0!Vtq0jtQuS)<|p68?<6 z@kHTUiqmG2QpgpxPpgo2!O0 z<;K<-L%d{X33|GGYZ~8@sQMl(T+}b1$6@wvAjrvej+%YC! zF#bUTjEQD5&yc|~Z{tDVcH%N=*HbkPZ4>pR4s)@-z}$D5~7q9#ap zF7ukRIp)rcpKc!JK(ao=Cx-7)AG-r@YcWx-k8bQXZ+EW9R*jQ6}$=byEGFp&I}c~ zX;p)n5wp|D6P;mnKb|m>by4gzxF;C25zO*jN0(O|Zmx%ywYE4h?3p<5l`vy|_PI>O z`pb}n(=)5O{JI1(bm%{ZC7B#pD8I3rl|j_jtMa~G!no4@;|C+7I;UP=R&?; z%P;p6#%+2wi4E#$p({n(mm-DaX)>A>Yf5G>a1?JaH=F9_nf#E_)SBSu1mctyzocS_ zAW^StqP5|kw{VHdMnJmq{k}DAVM=kvr5-c75dFemx(WJ>dpv*`I1vKyf}41Ux=TL`*Iu5DQ>9q>;iSi|MTEQ z#glJp`>Rp@R*Z~goje$>nmqi1W9a(-_dz!h|B3YfBR1myCxnHgQ7-05d*VF!^mCXe zB-0fC*T;`ej{d)MXZP(lDCOPLPn?q=(_}}!$KcD)%7^`*2SyE82QP1`71z;_iiUQY z0=2UrKfqMDn?SdxU%*U!zz8|g;o*^PBWkt3U z051fw0BnaD4?TEXJOHXwjY>h>O<7nnvE!~osM|Ty1%1>2o{S=k){pQq>$d*@t8~f( z7h9hZ>f|440d8Ab!kq#@^eGXhyzU`i4g*&+V14;t|Ftzgafyu*HJzoO31N))x^HU3 z)T@PR?*VyGbsU98iOfyYr);3W^)$;kG_=ojjb82OYqpxbEB`h2_3zDAk|~z-tbkgvvaT*?+=F*Hf!y6X*Hx?` zZ$NoF!aV8?IP9t+0R1{n-YG7QSbg+cfG!IXal4%r>fmX%`SBe^`XV9^L@@jhM#8$B zdpfw78r(R8Pj2ubZ^u9cY;L^kc`+9v1(mLT$b)FD z11iCUt7j2N+^KK>CElTF09CfxF_JP+LjTNGyk>4@AXlBf7hnquuq4 z_xS4%Ed+lJr&2Z8X*`*JXOtv6X0cPS%BtKMylnNPHyfIrN29gzGXcgeDAsYxO+l|1 z>VxUr-_$}%C?Z!YHlA`R%MBPm18)K1Py4qkHg=U!<7oYn8XdmE{rP`p7dQTYJTB(k zT1U2eSG89aXbh&Zd41Lo|L64Qe<15~9y>dAv{pA)8B?$dE&Lc2sIPPbzXE9X@9~dDIR73+i=|4hDt$QIk7Lm^Z z$%>#$d-MuXCd>fJ$Fh09BM6&(zZfpoP%56?%^E;TIw?#0MWq*=5(k-)P!NRsH}@gF z#B_A`fiEbHQGqsnPb=jb3<6?9nW;>7`Mr0@*H*=v1K4tZgbhBLetUoC5UW6Cx(Dc4 zW@OYmQ)C-YFAKO0fooo9Vdn-O_puqcD;hgUD27<=k%U5&4l@9;iicLnJ@2pA6YZ%x zj|l#F13KlbWx=Mih;hoD>`yzkz3!6MIw;{JZC_&)2Df*3tM){JI$D1xFH;#55C`Mh ziCe3#O2PSRId7Z4v4arY<8%nXkIt)S!n6G1{rGEs7}vEzn5OMYNGAri{<2Sfd&_>q zLxgE1gwOkS21tKHul;EIUUdaH;{|Kk087Iqv+Aq;5<8+blCatc$z-Y%hL1ySyUQT1)#yqWveg zm$Jd0909EQAeyu~z|`YR@5v!aquSPNu8$kf(4c>g^WYoV25>jBY>wp$jqq1L06EAj z5VMO2#|r2gR5>fOmebTDl%e-)tm|IBSZ|H&SfWq;MEwn=Qs>Vp@M_o9qUSP!>X0Mu zqkmdh7(fhqBZJ!@3er9aS0&Ba{=`Tjck>6xC~3*MnVPqPb|Yh|c9|*f%Fb&&<)Uc{_93lCYSRz}^;d>RrJmxt%LJMuG|JX8*fNlWfkj zb{+ULGY*Xp=TAa;l~~=G0jbyy$)E>uas{)9=8U-2n|C|478H^9OdXqWW38pajD@y3 zOl|!#G_WDP_Ced-{8h$+PPK1!uR0kI<&h+RBwF_)ke<=^zO`sq15=qx=GuXd+__-b zJa~WW1q#cHI+X~BMCHEuIN}mjwf9@Y-GMlGlI`20LdY5)2;V(T_{+q@g^SqQB-$=z z1HNT&3fiPC#kch{CEXPe*c{_Gy<#2>?yH@}LQ+;J>Aoqf#0&1rBLg&qS zrxAsR(1ZPZf1+IA+w}_18x>Boaf&HJZSzoPC(e>p4IpEnmmU>R(cie4E0;=f}3oKpcNk06CS zzt`-?+zLXFVFR8?)r3#Cb|~ZwVq;4oSFW_Xk{j|CvaQv*2ZBMAa@*+S$l@SsEDpoV&8CpWWem^M+zbE_3{zc-m1dF}-B9Qbes2bnHAh?(Fb0(lz zVLC|aN?sy}BsRpx4CN6ftmb~1BhDC8fIbRb?t`l{Lum-hSIwFnf~BN9p{LGKlzwcj znJ-M%WY^K){?y+QdKPI|;Pl!yg6~i^7)xij4DyGG#KA>LZd~qYYoIBv=2_JI?})H( z0(zztU&NZHTF*jLad=(nED#8}?ubOWa{-VOjX6(yzCiF`@4aSv-q!D3rpKCBgCj_z zW{9-ecayGoqXs?SLD;0@=II}QT`x-VZVVqom-%%3B@KQFik!N$`1iD{kIcxx|3K<5 zxMp^ z`)&C(3lz`zP}`gLew+j~--MPeyBk_QtJZhPrVY9fNQcw?-BZa0|U9IDdW zbrhazu%r3Pupy2dL~Zy#j`AcfDl zk!NicoP%uXsQb*&a{#gkU^)R@0jSFNDmx~g>ci$e;^R}{!r=1;MeZ%TR_*E^RI@PSnZ;GouMFNwY%`MfA*oZ3 zYa*?PDy%Pk?p`}~;h}^bqXuj}JK6saiD6KYb;2tU{huf&;>p&a+rBQ-pUtlu)VpL9 z#*l`|KWX>5p8>#%=Taeb&OkX^U>$vs{i1Akd`D+M({nz8;ifYZZlK)apL#@n6f z*U+s=Kh)M!aOC??k0%xbXsgd=2TXK*Y=@hkm4__fR_eHK^KYjcU6uEh6VToe)sVBo^#R6_~@jC0M;qupTOhhzd7K$d6+os zNKI}i7{ZnULZ{D#0Pf>O>_4lkf4*d1_Tc!Q4Wc0UnGQ7`E|A2?xG?|PSx!|OIs|q0 z>TXgV%Kr98>Wm6vDKd!ZQ;Wt3pk=!h9;%9IJqK)yR;lHv={dm5z%m$6(wGDOxGU*Q z13hm8=kJ}RH@XS7m9ctX-Q`*Scj@1?Uj9%&)35SE;Q=Ts)!y`MW_Ok88JpXxo2VF- zKNFba*BAmdIa<>Un16XLmqRSmLGZ(7P>m6M4$b)Pp}}k2-A&a!s4RN-cc>k%7b(f+ ze!XK|%`EHVJ2uCBqjfV7u^e@OA>v%?syWp;f2P|g=ZAzmxXn?pt5708y)*4rBoK)RG^LWyFM19K4`s&sS$x@Xeo!Y8zshD~>~FICT` z?}#!(In%#W)=8It!!HWYJ8#m*2J_W8{;|4x`%AU=`JUR(dmc~}f4Z(o24jY}6>?H% zG0p2=J?I1j(6QjZgH}3&%s(G7&R;U*gSX1VZZWO53js?9a(?$w$*>Zm`)4z=+uhjBo7p+uN;(C~gJRc(WN z_e|bB^!#rUm_u-?o6Z+LZ#Q=T@B@lUUWETgP|iO1JCE^ECr0Eg-FbO@%e(g6BHiBC z&|vv9Aa5Xch-o6Qmc{ok&jo;Kt@AII5P?{=6UmYxh{Wr&_T!e13F`kyG%A=5;8azB zkQ}Teu_gM|0myJg7+TtYRove}ZQAdxH zZE42sxZW4MB1G58$u|{G%YFmvLWcKa!7c*x7%VLv1Jsa7N}r!Dk@hd0Ic3 zZ|Te_{&hk-f&wGv>a&5W?cS>`qa?Yj#9GM~cqz`7`Pv9N$y-m#H6{|fS|z>fJ|N^B zK3AQiyw-uTMRjs{P(;p3E8=72m?HaY^YjHf{xVpGZoqAH)~#-hlWROOaT&5TNzx;i zvH?-znOY#g;!-3$ypaeuu>{$iopB&QrkWha$rzF*ACw>d$>Wujrhs}($8`-viQ_-` z=fm%r*HU5?8HvT97d=M0Q2Pu9s4>;vsPnKi9BP)UuIN--PfKg(Wb^X{BsU80gLCCQ zdsS2l3HHdfw*~=p3lW#Jiw~8%JpA5(pH8Pnt_oxa0Kwi&e5hXG_UYfSfu3z;3~2LU zH~`t_cI4XY>62ibjxHi;7McFkjYpIc&NZ}EAKz)tad;!~qhY2_2ZWMw!n6jSl2yO^ zaDa*0xyx&9OE15j`$f6B`8GuA-b7HP@-8#ggw+tSpn@oxlRGurHo)&99m_P&>Qso@(2(zneMe`@Z$LA-`?+5)oD{Ho?)Ws&YG=S zHfaDb8?T5#-;k_A3qCEyd2?YWJ#x==_3-&xs}VjI5hjo8yA?n2Nfyx7%)Y0h+@A;% zgy4LFqJ`MZ;*)f#*O3G|9j+!^@M)3@M1U9DyR1Lbel=X~E~;%2+eTX=$~Y8@ouBpL zkU>W*_hD{LfQGQ7)qwxh&Z~1jMB{WGqY57HG zYvHX|NB)paIbU=w;9Eq;DA~^P<6KHW7AjH0%Ci|vX}D3bfUmsDj}pIxF`Tr(I}JAL zLXsQ(NVWz>$=v=|ZRh^a^c(;G9Osbpv9g(Ca>%K~971!7LL`!*h(gMlISsudXL8Ch zl=JzN7(+tJoKF*qkZs6etDHWU&*v}r{_yq7xZUQqxo!5kuIu@D-0z*HD-Acq@9X_{ z10Hbo=b8jZAyH{mxPV$)O|osv&wpa={TU70gCMy55JZ*w}W7>#iKHA6OYh zy^MF*&;N-s{#aQdl;3QmulzIbu>_k>>lOL|bl!b*db#QorJpWB4XlD8j{7qR4(V6c z-7%X6rR~10UUjRwItZ9C13Sq4^~o%4Dt8W$jeAJgMD}JwLbHY?QvYR430+>P9tOPX zHrsF(A$Qye3s_GgokF0vXL#!nhs5M>oA$+8#TUQ@W=p%T-#9$_&je8RzT}R{<9E29 zg3#8O9H-fw%G?cY8lX#dqZO%Ww_xM^?NR<(VOlB6A%;6|UillLHT&M2<*a!_Go!pf;7^V5Yn|xX1lNaI*4SK@dHGAXd6>iwX|^+W z!2p_>egdEf19E^r;N2m7%HF9iMyWCX@%C`DuZLY`y?p4^&G&N0c@*QxcjwEVWN0$% z%qx4`iTlUL7`xiOlrLx340bq87-|XeE)72&q+V~afE`0YEQV6%n>}GuI5nbkC88S* zAEm8C*1jDye~ZDQ-fLXH6*N^Qv3=q-wYf_pF3IJ4md$xopk(I3EV*!=`k6DgG}l&~ z6RYAxc>w@F>m2R<9^3Hik`H?X-PPAPIFo;ZRbB^`R&P^l+{4{#&T0&XccIz;l)yiG<(rNQu(l=I{(Xk(C9xi=@39T(|+Ax7l)HOmM zQkT+hb#8LijyP9E|LJLG0VqtLR(PD`KT^4+IY8dT5;6?lG%TvIpzzNHR4qGSRD0Sv zyc|(H-6e_mp5qGcihHxm`zCX$Xw$$i_b$T1t~ESKb}SIJbU9kh+1lQ$O}sbA7V@abE@ojBZ2llCH}fyYj9QG&a@ zz_GeV+fe_lkIkmuIgK^H>76yTkHSCa&kWIicm12r$MpV-G07&o>FpruvOc8+xd`rj z`6-UR@Y_5ie}Fu3r}mcJs%98@wJBzHX{KmZ{E;Zbiwn+Bmgbi||M)~(f)<-?DpJ2KoaPBVvGdq<~~1rZ`L)n6fIZEqR1{30 zr*8wK)}!&$vau}1&>g`&sUV|Bt3~)w zqu$`m?8MasALSsD7zMF*xWh=8%^OJPsnkre;Rbsv0gdy}hO+nZ6PQWUW~=mg&^d*` zvRnO@G?xG^>pH-;gG5rWKm>GOP=clKdxY)!wZ!<+uRl27N~sN>opfDz4oHhhYC+?e z2NrTWH5(@@nZA02!waP#>ZN&t-2Q?`!S9CY;<0?Xaq>ZSxh6ZwBj8@WyS-;3-A3fw!3nhG)T6&oWSEc05#e~|b565V;pu(O3Z8nGEJ==!Bu|;M zg~)E$=GQefp(gvz&e_Y=V~6c-Yrc{Nrr&SadK@$6%j~Bdj-3Vd{TL@|li!ny#1M+p9e*gk@9*ki+g@CN3rZ$z z=1DNN6Vq>t#VC{ivXgv+O@jKQ9`;4Q^HZ1a`l(5*WVgmZXp{h720L9<2d&BzYzvWa%{-@yJU+$3&NUEu9qfE{u2K*IeP43Exn?n> z3ZRr8FiZP!HT8xHS0cB99zM;#UOVE|ELzD6WK^&P6_`r<| zcikh2G9KJ-u5PWF?13k?#m$Vx|64l}E~C@b`Qlo6qlq?T_Kcczk%#-^QL@=J!K5!n z+x0S4CdAa`9)ZH&h32;93wbS&fH57l7yIX~xBz-Z9mT_N2_sFg4Yf2qh5h$oJ;osN@lAQ9os zQ42b&)E^vDx6i%ou)sfiRO7@d3jNj8g*s=Q*2)}pLDwO}IpJEPoy0Uy*jG_*PbM!V zpV@kadT~B;)-YUvN{7*yS2Ddc3rL{~O_1_=9hc5qi{l==gNp@+u#YINi>aR_QBUFrF4Dx=e^q|}sMC-TtousCzNn@mu-n>! zq!szMZBygk7&0z1Mo^!T(c-Px8D5eNz_N{8dzMgi_8T=VgxW0x?XL#%R_`E~t%pS7 zS4${}+YE*_xbVSx(35(7>fC(sI~`%f4@iQ`>hGcK5XnSiPXiqv&wvTTk&p=>HeXG` z=kba!SGwn(=1o4l4VMywO@quDU%JZ2&vj(%Dt5ObC`Zh^?#lWpo7l^~aP>riKPi8A zB^d(9c%!!hPhZ{K{l|#v?MXhQ6{?>DFIj(rwHRi2Jt*qII}>hk zeQr%}>Y;)6?izKFrp~>a4*7|q%#J)Ja;?=V&x!}~YCzS-TPb%j3K3;DL5XnYcmaKF zUFt#OYHz-x_zoDK!^#l_goIG3JHQQiL%ig*(8-`6oxSq=0d+2NoJKdHcicZqHl$h! zPrktPH8j&1KYuy;wKKx95lPx@gU2aMs(uYd@%MQA+0Awsvr@t$1S$Jei}W z5{kojHxGfb;+}hb-$j2B@u-}nR`7s}HHr?yX3xMbBZ`y?BkUeTydBbGnz>@}Vyvo= z?&MeTIongDD~?#j6mNnqlg)pv&ReLTBjf%7W)P;C^Apr8WG;(l3{toM*>CsulCyRG zZ8pG?+aIuUfI?qtRzgVTGV4-|YCI_I+8!INOd>mi&eR@pnX_27fhRuy`JH}dWlmPS*(S8#4=M8P0Cf9H2^a1i6gZrOj7Rsu#T#K z`y0mH5Cst;&o7)*(8BIfDPrryxE-xVJ(#4_TXsJnZtC@?lQxckJv=GUMvvYpstE?vskx%_8wYtW8b^}Yzs?W}wxnli}QMz*>;BG@Omp zhGwQ}O!w62-T3KBmT;1u$6wi;^vlwQJDt6KZ3yw8EOIzdA-2l$%3EZ3R zC%GKDH~U|ScjqjLphxK>wV4OHZqmzl)t)&aZm|~E%eOWKa4Ee=X1w=R1@`^9iSbb* zRK(z&GY4t{BY-pskx?fnCxw_z(0WRZhglY!uP zwbv5r`mHU`Du7_=Q&5tNLQ`+{o_Dpoy334oJubdUg#Dg$!5@=CH@+DZAD>5IDIPja zU*~r^1c*GG^)AxXKNs_D0j3~R%som7Q$}^$UG$WIt<*nXa)43{go}&}IjUgqlZQgn zcjs6eL%j6wPMpfK`@;4z@xEIeYrjoq>RevRt8<_FS)xdyiy7|Dcb}cpc+x0auDdlG zZdPfi|5FQaeEhP{yL`)@TZqluF)K6FMrYpY9cGneul3=si6wh{&H2wztk8GF|1Eox zT7XK;SmhLFOI-loU~}~z_VBJsJmozIi;>L=SFx%VZS!p%nnv7KqDd?h`(nmNE>!=$ zEEnI!vbvD}T*7SEaQDig+)+ZwvMSZC`YTlSmc3*?CX2JHWFECUylg5qRemTy`=vnvbRS{VBbZ;q3)XN4QGEY1;uDK<@LH4ny zDc$p5b0*m1yPEd_By#hoZS6do=9W*TTv;On*(-{DI*?$jEJ3^uau^f)H4|tUba0GW zy-72{MkxdjXbwI&w9YG3q-@gX6s~#oB&B2cebcFA5(nPTclP?JAgc1lSUtw7jY)){ z+zq38#i@gC=3Q*TZLWBFCDze)KO{SHoKg4H`e8Bp3}RgL}}i`1?%|B%AHHA~Gw^5u|-p9nIP z);EfHy;hDY*J(cF&nUY?KfZ7yc}K3OGY)-k+~N+)PSR<3rbnAWo6({#eV z&+XD5Ain0^DWwzjfcDS7;FY)t!;ngd3Ktx%qM7Ob9fRc&n)Lg7!^iIz0Vp6G$=-gx zw94JM5vJGOwv{Me>!e{J#MoB3T|iAIl)3PD&wjY9iA}KC#_@b}|C^K1OTJY)@Yqs# zeMWO;X&2o^Cn@r-+1E3GyvI$Kr5}Wu<*96;2z{wMk3dLZ7M=gzC7_2o1T+F{tdlFmo~JQ>ZkV}v)^-3F?zHPf zx7V=xB?!xg^2OjnYibiAl1qj8&nrVq)Ij6&8~&!=4`S5*47rkD3jfe<{L|#+H#c*# z%VLoDd2D&)fkP@H##7WMG=1_W=!v+hqX;ni0;bTecz6Q2lPG z_V|hz&##-!_ac0w;tJDF2T1APfj54-8YJoleJ2G+8&O(TYr_JbAWn-Htt$k?D74!b zp~sEWXF8`GLdHK~AO5n{3^S*dklty&DaZ)PW1s#zFLL^1v?+lJ$H+0B@@q8|5_CdD zU>Nhzi3qcsyxNsajrZf-oF5yFlupQqxbCsCR~Rf!Tj3!5cI??cByA`dJ+P2?qakJKfS_r z5zS*ah@g)TA?%nra!~z1>R`|e(*CmePAfgVij=mT;9ENM`*bJulZY~}ulAGdi!%;8PyhT)4=HUsnibZvJLR;VSLO=qdz6hdFhVY4n2{2}Z_d z(HIb^D+ZgD5aMmYX$M*|j`gg#HGk7H*1`h29A}j}VDmVg(@tNNx5Sq~6`gXrb}24~ znLcGCReOv3zGw?xQQka!fHC`0Lzww!{p@7ZuR7&9c3(vnTu^Xa9(ckL{gUW(^wCF4 zzbjE)gMakc(^QG>R+Gk})AOLU$>}YGH+M*+`{no;xYel<|Mg$Ma6et^DPMDK0`Nyvlg&?nq3{=N`hqD zWR3aVL!eA$e|}+e8M1E~!A-bMwbiWNbEN&=FqiQZq&BwhmaNTG_Fbtl^%Z0q=m*o6 zzWH7$hiGXIFf>XJKQ3)S)b4X>%YaoFFLeH(~h_lNc!}!Jh?ps9$|>>Y+Zl3aa%8P6^uy0o;QMn8v{60XR^d zXMKuB-d|>QNaI=u7J>ctcoiu5D1iW2tFuXepoU`x*am~_Brb%=R;N{rk}xh9*@+iIBuwOwmYMe z_+rYxzJJWu&9MoJSbJ|gsZBQ{zc@B`RG!xEProrXRp0~Ls7HW4+}i8Q!X?qmhLSgJO;@ow0p>;@@zOr;5zH$-qv4iLOw4!0ynk#PIX%m4!{Er{Ost< zC<&CndOp>1zmuqCLX+!d~vUOfa*1Z5%AVBL0Gc^3e}Hb%E_O5 z0i*3yRCQgvO3N}#`-Rf?Hg43{-=uawlx1h%1}zu7q8o`FNMST@*X@7pM7>8jXx74A zOl7i==DZt2FQ3%yu&(!n4kA-<*09W?pl>qdZbJ7sJuUP<@3AF?Mv#K!1_L56(favv zeqXy#=~LOlqf03Gp6F3iSDv8TanKD?_C!_aT7WBby*Lbf%BX>6SM;BOj?yTb%|Nn8 zqtQpw`5WX`(q9ikov5o(yHjB<{t}mc(#zX1|6ITeS3^yW2b1rVM}VR^2dFxvOQRSP z7Sc@1VgK%>5tAv8MjP?3mhqCWR=_ORuUtF(GtCM=)Ga`yliQC6IyO%n@m2<6%Ut>! zpqyMg(Ij!x*;QR@N9PJdkjAygyes$(E{mrHDFmo-Qrxp+<$Q~*tdC)`z2*AkI}LdZ>S_!+o7Fq zxQpQRVTzO#_c%}QCxt`+$7Pw)mE>rns8SYYndGf+!tXuCl{X*ZtQ>9?d`K+e7@=+t zVHVI)Y@Q)4qWCxxNvPe@?|7B1UMq#*M&+C z2}Flfj1`?$beLU-a^Hy;8{G-tW(G(L>=z^P!eioJ8h`-U^cNb6o-j1O%}tqhG5UBp zvcBK5KYfX6(Ybo2`C9w+QmzSWRPQzC{Z=8(fO#J5ahpVS2r(0Eb@=qFma4oKz8vx~ z%7@=lc-kK%WT|jD;E(HUh6HE*m5a7(3IOK-Wz20(fdniN16=mIYe`=R5%Ld#$c_wQ zM_jN9E`l-Coc|=rdFc(1;aLCUr&uX*MMBhj|399(5`WFZIVv0=`|e^vWryNFa#mQr-QoN2n6=a}ryrCQgwf-v4e~JiB$L z^&{l&8~0SEHbc&#!!ri*0mJyoz*{9c_5lxbLn}3go%5I1Wv2^h=%TG?-}G8SA~pDv z=}?FQ)TzQ}9f>+(UN2R-LYgaM!#*@ibZNk6x2=JlgKq@Nad+$v-44 z{A}hnLc={4hu1^mf{ZjllK$NlOn5#R>x~1}PdOcBmC!-IKZ8QxC*K8Ua5d7>dH9dN zDZn4PwBCyZ0X1eHwB17L^7bL!9@fb9-wCNTEPN9RpO1YEJK zj_dw5JT=POx2r=(^7WRFQ)BIpMW?>U**Kd&B%%r%7%qoPVW}o7iAxAl)G$jFU;|vm zn(k%HqP|j${n%ff1V8}34^}niAWZtl-?+Ei-+kHYjopJHq+&RZk150!NVC z%oGaZd)9q19Ge*AzL}G?GraRn8i~=p)Qd7uKi&&bub}DdpUC=S2OMH_5H>-dtbPx9 zao=zgM`kGQGo9?r)Z+Imtu@H*e4pL_lmk}n5lPWLI4ftpT$bdka4&UnotCM5zfbFQ zn;}fQkbb80aT*hr0+8>ExDy{WKv%;yLbVoK1UasT3s^0He(8+qKb8^5KB~AEI)9k@ zMe*w$(`$@Gd|=cn*hYvpH) z&~s=iS&2_=-^N3j4pPCOLbsp2Y=ji*UfeT-kJH?Gdk5k^IyYO(~E*pam8v8X`ypTiKf4baYv2LQePKbpVmhaw7f9TQ6kj~=zG!W%=o6}kC= z%FX#PEe)E1)C29)p55-P1WDHy{X-wKsu=+00(59o>A=e^x&n-MHAJafpff#P6{@^9881d5_W z8Kun6rPJp=Gt_T#$dKd zw2>YLEX5ndtKg_qCPd?4g-YiAzO+qK(8e!s9{1k-<@a7rYw34D_UxZ%f4BqZn;~7W z!njd=^Z7=kr}L-LkLUmJ#6Y7^iUk4SBx1?!Ox;)BS!eUhy1ZtK?R;GLN7E@%$!oV^ zi`3zd7&ajV$Hg?o`!x?#>`y9B`s=4=B_(;4*`m2$poZZ?KCJD?2mwRAo{X*61y{rQ z4D;;awO>LvPVT$14ve*bO0K;&gSa>8OlEOH{nx32@e}l(SywzS7e0PbL`w5BRa%)H z8~<3`Qt7-JOE_BdhfjNq(+uPD#vG2NZ$qj^KdOB){SJV5adMweKkSMGvX7yU6?3yM zS5*VZ*0;1pp~Jo^$(eiFKd3<}ghEE-U2w9&OiQdd>G0&>PRjVMCZ_^oqGVeg_UL(- z1BNavl)dN&>;sR5W*Z(lT0)reK3K}U1T2&eAH{M6*tf+w3?K_j82*sLo;!nUVK7b2 zSa-8ag_Eu)w@wb8AFpB%(o)3(n2t_VST#W-5U#XwM{qc%mL@WH_KM+s++w`j$8Zr= z{uNbL3#v$B4{zjP-1{GwkTl3;>qW~&A=?MSN3KgK?yk0r_}Y+SI&<1*)zFg#YBcOW z**Ai}!d;Fj4R->ErETYFiL4IWxY?_cT%-=s7Cs|XpKb;BvuZF+kk7-S^NSXRJ-&_6 znp|?A9jUlJD>LyClM!sq`na$4(Kol|9U=A63|0ShL+jk+P3Inj>PGD(YyCuY~QPSf6NEFH$bNN&xQ)8IAC;DuWQ=#~d#mUa0 z$>)?zibl4lTx`lK8})R++PT;VzrOtMTfPIBSQ3?yJ^UnA%U)T5GZoBHmRlRXrjYh< zdmhM#$~3dxa!xG$4^#?sDcgvbiTJd0dXsw)k*H6JciHhyw6GHeR6cSc5hD|A9pgc4I;h*Gbe5j)n- z`HSV8x&6?yQO`^Noj8+K(_XT?`A282*$M~YqoC8Iw_j)>tROMQS9RKn;*dxiF<-3X zchs~M#9b?`<1t%teVZ~uM*jHN#rr}$5>&R{&6+(-L^*hFKFh&#zm#K(o~>8OJB*#1 z-38?~nmxLw$Lshe{lWijhjSq~XF6}zUDNrvsj)Th&H1Q1r@00rAiw7IsPdX?(K1&l z0M55fkVBn7NjPNq@7ffvv?gn%1{}@6HnlIL#-1illi>Cx=uER0OcWZe<#LUu9HD>+ zRPeX=3SOBul_|(Cq*HOgc@*JoY||yLZ{5!O+x$=aOYpl3elK^#Iv{H2i%92 zC3s~zx=}s_x`UrwBcn(P&kEu~ryoi@M>#BFjn0Ine^pQK4|w**IyZYnKXXrOHc-A` zD}sUaY|di103iQz6G>VuDo<^VR#s06mtr1L^@Fm31%rUTcpy*=HHQSL^A&~^?R?h| zaRbR@pN=#W-qx1D8s+cN19WfuZax}YKD|3ley7qAwPeR8TAs#O^%;-}c%^QxK8zBf zSc)#LKK63l9MT=^s<9GmOi2lF2Ng=N{{!fR&46T0swHTE&Q!2FL0LY??mzluwVebU ztMx#%J!@tpiX>u}HuWIo?%$X>?c~9+@EKow*$JK23&wjtT$saOdJo$^(|!T^7BTb@ zEf>Acl3e7YqqSOw+8C0*S_SdR+%-GYU^waG%Otz5+EVfu*hTwBFo1&~=jL$^I<;@o z&u>Y-be+kGk1_F;M(wa4^Y58lJ9)=SO^N?(?!WQX1KQ^SM%o-dI~c#yfPs6)Vj^C!l1LHuwb26;VE3q#yjp7 z@y#)lPUL9)s@38!g7L%;k2+VqE2WjfzAMRncRxPjgV&RE3Zy)yw>(tnWG>3leU@Y3 z@hPq{I%rU30dN+BQaWP&6bs!+>HhP4rYg8^M3r!g zMUXJF8e)PfmJ@S%!C$u@R=_^jAOI~`$;rM;(LZlLtWoWXOc$Nlb$-ZT2Ms_pEQuZ~)WJ!^+ZzaQM zLyEDD@WMPphOuQ0;d}LZe{b*4=MVV)^7YHOam_W?d0ppuoX2rI?vF{je$AMlN1O)) z0`Z%gV5~tPb^#CwoXo`u{KaM0${z%(j4;I*+z2UHrg&w|nxwwu-bw8Kih39B9u}5* zC*$C#!{?T3OU>&qUu0!u{}ZWCJINUfzRonTHf>K!5qV* z?(!rdiQ4o=(?9$o$O4RGjH96-K^$Z8e_z;0JNN$2hyI+Onc`Rft~`@qA^RQTs^wP% zVVI$zzW>*Yq#@K@J+++QzS%$C2fXcK9-GpK=lT~5W`dr8nbdYPl*)&OZgZeO?jV#v zZ9*XPer~Qg3#`RP0x`GB<{H#1VQ7!)Z{ypXh&NE+D0Wn>Dh;eIOCu6=&xKaS)QJc@ z@@Z%?p!0k@7IT&$hyvMj7=NsHW}+wRTkajBJ@ILHS!e*g2Yk?1G?cAbJ=Fw6D)6h{ zPh&R>^rLHh6pxKQ*PL&rjw&A^X6hP3sp7t6kbxZ<@ju&i4bZuNgay#hpb7ilQbPOf zXOtf?mzh+X{C5_EMRMXwH`#pZ-72h2CEK<#2w%-?pc=3%Uhf3a(CTlV@4jep4g}vC zAzII~;Xve`T$EFl+SStCe6eE48kB0Yv<$bXg4nw**Aopt2V&0^gNom1`tV%2@%k9| z<%RvR!gz6LvHLq!;m4p&+9Gn;_kjZ9Nm(qoHOQ}d9cs6H=#2tJg9?aKah*3%wVyiz z$!C8n{;C+8MmeepkbKU4VcLa@gdARtoS)45GfBR7xeBs|Noy@?+1PH$wI{-EKWoAv zg_W4Q-G_6B#-l{~>g78`34J+0Y^vY3txL>3HM_NFdPSq$qOZS8gI zucg+E?tl=$2$|?(=R^9V`=|O}Lv#;8I8d@XFT!&R8aztOIL_77Y4{Db`g`x46!O@p zd*gLiWq#Ms*B^BX>puFBg)(Y>aM#>SmpACn=R;Ngy1vr+{|-bIha6-pG1jHo75C#Y zh;DWmU6bBcu(&(59qUtH2FuQb+MR2=kFbS${{bf6_eZ)oBnuugKW+gv5;Il^UGt4N zBIlknbS|{)Z~6NeDDfgm?EM}E>}o^5?X;#6r)lQdO6e0i64NbnkcM2*u8*VC~TC2#||t6(mTz-nrk4 zu}ogw3ha4u@9GOk8H0Gipr)5en1d((MlhZx*Gu=FX+Tk zS1wYS50D`}5Vh;H4N`5kBy=*Bz8%ZbFjSgF^;^;Ib{bN5D90Y(YWi0BJ^o{q?y~gN ztLxN3BD^zr@3$RJ(?(29D1Um8E+2J)7odbRU*Rf^sa(OU3n3;OOE{=v`7L{_z`C3+6O@#p?g*9 z_jPQajXX1$iC67_-p*3RQP(+M=u?~fn-5D;E3&wZY2aSzbm?V@h$3T3;_JMs|2+~< zU57Tp+GvN;EnA-VtuT{rKMR$8DweiALxONQvUHR{*q!;(ec7xB}3kJ%YAID~D+GUd_q-JT~< zr}I`xnFTHEAB1^>`5Mvcs3fYbu`=QNQzfUhOlWQ?LmR$_b;yh<@82$#7=76lr86;) z*KlSm5cnh$S5~`D*e%6$uS7OVCRCl`;I&yN%vWt$eX^cCab5lS0fNywJf1cOUyJw* zPrnHrgr{!^-|gL9kjVvWa173IfoXkQh}!dnZcC}CqG!wZRjB=; zRgkY|E+W4WU5{3hH_OVG&j`5Uq z?f*(y;V_&iK4Wk9ZuBG%y(!Y}IET&w7JFEL8Z+>4QYE(A!{)*Oms`}J@olI@yMRO!V1AzpDTFK+#Mi!&#p z_77M&X|1l7d;qSw5B{Ii)^c`-(g`Q*aOmJOnE9bY!eP`KSn_W*zTCh?61e|Vdav|| z=D01*&Ac=m0mR*xpNs6mC2(r7q#0)mjdVA&rVclDo6jA?6G(mO6ueDI zoei(+zIPPwn=@4?^_!D137`}1jseXp$vFhbLJGwAmfHx=s6 zg)WZdkveMs;nf4;)B|MqoHfl!9^0B@{jD)8yl!GCs)0C zjKhxcRl4?k(X387LC)JmL%F3#y37@@loLP#k$C}+R)p&y(t98^qn)o!>V2c&h}wdX zN;Xp{mmO3^mBxLA3BtxU;nCZuAOi9Na5OWraC1zbb`?66yu7mwC8MWa>!kO@Si1V4 zZFp6rPY=e8PqSBFseyIRd2%&uLtHsx=HY9o&@*E_Z^CY0e}-O59{jRt+SSP;H9Md6 zdzkB?2(Q20{seW)Q;^4Jk((pBJ*nakwyy@0rV^BAtbOr^4?vk&8k$p%sNf z4wE9DQ@s;bQYv=+7-5??WOBkJ=fcxm*U@`yxsK+m)6oK5IUf+NKi-=wEG@v9r{$WR zn_awC?I3ysrJUJ!A;5eK_lc5tBSi@`FoM1~Xi$idzm%l3e9N0KT7hmXfhC6}$yllu z(+uKrbbgZ(+l8N7ZYmwCKQSo2KdXJ+7EHK)`x*JH?S$JELq(WFBC}=3G8>&v;R||Q z32$b)DG4qRq?(bj36{8qgVj%{O1t74UsNXUe#;w&SDQbEVY%bJ25?kxbPOEaS4F)l zgGQ|OJ00mX2_>P3O3TldkFuVoy%uUbh`v6b=Qp^KKMk%nO@nn~9Npizg>VkMWHZV3(~*rV-2c(6Bo{cWZD%pkC?P)FX?X)`lcl zV>@Qx{xJSM`j(XEDY=Bef(D0z~mGhDtw zk;{Tgp7$hXTuYFgFRz5DJZl)&)qvy=fPE+zk_~pWA}n`$Fm$kwit9_96_27MXL>Q+ zc};4i%%Q6WSBV}(AuCTbmaY+35bR0qI~VL(gt-$~Vr&^?N%&9dJp@nwX?C>$V9ATy z;gM!Ci+N>%`5I6d86vl>DlfG4#3ORLzX%d$yAL730@#T98W{rocwj{UNlrr3A25re zsBtEJhn%XGxH1DFrTN}Fju8FjD7x8pLfxb|odQ!iR)GF3ta>f>!gdd@c!@Kg08hFz z=B1T*i{!j#&gm%G5=YOst14Cl;D?PT5oo4VLQ|NSMs^sY&Do+=d?5|TA~wFxz*!Ft zg0=XHas^?rQmsx~D3b)@^A9z5CvM?Y%z1G&GgF??=yB3bZO@xBrqP5*HafUU0>zcF zt#;`++3TA>c(hcJh{pN1locljG2dr>@7iCB_M#nv21?;=3HnY8gl%rzI$D2P+ZLIX zRDZeCOa{o3G+til;JBS8nDlWRc-!|Fx}d|MQm%ga{gA-500c8Msl?&cmG`_dZ9(#5 zGi%}N=TaQ}W80XjrtEK1aNTX80eobtU4QSgMpxzr=>sDLpQ#Jm)XUk~Q*4DJUo;?< z1#n~ahj)&VS@LF*UqWjlY`uw5p(QvG6-4c49Xs8$)~l_P`O};TEx6AjVg7u!L(yK2 zNW#BKQo=k-$XXHX&c5=bPt0)a#r0^GlFr2G1wurwvCH!^OC%ocO;>@{WRo zGBcM=CKSUYHj5a_0iJ}OHm=1FX$vnw7 z?!2av5~jCz2eT`|D;b-d;hNH8j>H-|a}#iU-+xCJ&FOOexjq{`;+msm+ZU5#I|^^P zu!bWrrxe_tRY@6>^5&8>LTGcnDA2Fd890fgBFHWGs|cE1Q7qJ7NqD-yrtv@Xj?Cbr zUccEuEW8osdG)(J5EsLHF8iC54uf~ku&?T0u2OgY2z*+~#+ z6{PL(QkVtGGn!gyl)3X~>JY6ET2%R11GQ$lTvG`re+QvJiOoacerd-1CAeE=fBnVQ z8YB8)tc6j%6xNjekiT*lGRAI5*D^C@zw?mVM^LfMK1wlwJJVpXB0OW98ZV{B_+&6Y zLR|Uf@57m|AqX8NiEWZqbj9$NR5!Hz&x31wQKLk|?WyJCDdG}!I4aNSwxiEf7b&-x zv*H^-jv*MnNPtP|(GHFRev*tP8$PGT-wO1QhnscWw?x#kap^{M4iN{VJ?k5-NscY2 z*iZou+qA#A6U2ee6P5Af)y}TvW;vpMG@~2#-Q2eVVxvR-r&8Rs;)7ZMwXSxM zVMnCxjzcyMIio(jEr*7tUP<|Y&VF}G2!*BhER zLzdH76f<_)_bQI%r?a@}0ScjfkrDle#gI`qKLn$KPu$g*4GJy5LTYwZHAVz%k=vwDh+}W>e!<%R~3bu;6hD#ME!s$`Wke$ z{)}yNW@0}O!ZY^+8Pv=9ZF!t5k}>P8$K-}R3slqlo6Uyp+9z*0_2d6G)n=`+Rxmw3SS~xd`4=Fv*W16@2O#31KT!{E3)n{K&`@8lty{&EXpC ztHRusdue(1bWMhDuSpT4%S9QH-bq*qq$QyjR6O}>%{I-0KZSIDm_ik0aiIc>y3oNEq>1K!Gxta*uJen^ zBEyUaWBD?JtIW*9Bh8{T%6ze9|HFT@dH)0P4l)^iv}E3UEz?%JXrWNQH{ zt6gOMsNJ5DY6m5&_@<-Cuee<=896nq zQ?YC1`Uh+--N?CS>{BufM%)NF&Q<2~V&YZB2sq%H_W{@v+Nf59C$!8wKtz=7pLlKO zvfrdn^=l;I*LB+3n)H$Ls?Vt#Q1Xrx)7wo<8jDD_UjS|Xz><%j$i|_kN*zbeZkdbh zcASqanRqPH&<;x49r;7Fx-6O~#bHtX_~U!l&GgHXI0a3iVWsZ%5ao!PXkjf_lcAOH z`R>q37E&3$85nZAp}KuH^@qmo{?G1Z3Q0xb!sG{X7)pbf0pehS8i;M^I%y^sG)Dw- zHk09g?FE6n*J@l{=0;&GXYE`?{+zSG~pV6~7Imi-Nym+|**Px$<&W zEQr55)XEj8Vm7U|GATwC{vu zpI>9+T(ywNV+Uxd-o+nmweGipiu%uCEE$G+suTgDQ7Y zr&COjt}$v{pU#S%6d7ZGFFY3)(<`n&Sal;$IwpS#H^#}!idr#McU_6}m*@@63-(L# zA5J=Eo8%-f-W2<3o(KcEt0L0viW1KLqO8koH+&Iu^JAS*iGqE^lfN8swnz# zo=M|t{;dbrYN{Q@H;6z#@Qgi^a4Sg(kG4@__QiR=IV1h*1%H_6XLSVDg)4R|R>gy; z--?l)*kHK1QNEfRDJ6a}5Yv*9mGo9UrsD<y3yQGnsQnxiAeG~e0+(c|X(yy`5P4CaM z#!3690$a58O;d|v2=y*6B7G!r`~*-SO7(eieBB#!*PYf#s;{aP^1)GG8~u2Lc6>Z| z;{g>7MSsjiQ4gtELNMF(Kp4BrC}5d=K@N6gm) zo&QLSZo%U0j1$xn&s@p=ydr;0r7rzP$;A0*)EJi^+#CZ{>r|FsZKiYm{I{U^b2~m) zt(|$zP({mwi&uv)Yqc@VZpql1vh%#mpGLdpg%fA2gV^jPIZ1RT;X#_cK^-s$#yfTn z7Iq=6cTj;&Tc_=Mz%{3>qJZn(+BNUE420wpr8xANUMiYJHLfd+>N&j+o>B}~lOB<# zp{}=zkT|h=*$U577iV8x_Vh#2xj1cNUL!nib$IxlJpYS0!eH(ZiQqwy>Kh zKL5MBS0kaR=I2*lDV$SW6+R63@dy!f@j{NYUi=>{ICkn9X~MhTBBV2>pk@I4c4;iy z6l#aylwnfym9z;}Fi1uXq;(NJJ+yb&$3!o0_`zimv|ejy8|$vBeRECC1&$%#2_Q-I zxZ4O@J3CuH45r5n9{4U0M$Wpc+IP5c+5y2?jpEk7qWewW<*DB#Kvc0H&%rS$#x8_( z%^`*xrf ze&jsR%_uBvlH{Chx86^ZLOc|!xmd2ah!-8$C|^Cvn%Xj3!OK(`LET&ROR1AXMC%~x z5O^7$d`+%>;Nalw5T0|{GjcR~{%gC#LVXz|S0rS6g+tf^XW5U7ZvG97_~R%!_{|1a zG#Ypya4W;|F6lKKGF;z08d(W>wg>T%6Og0Bo1(~bn=HT5S;JX%tlz1o9Ol^uzEsO> zKS^66a=vuwWXzh)uvuqb|S-;$p#tU3qRB^HOE9q;DbbIb9tg6C2Qr7fK= zQ=CE@Bw>lkebmVnug+(C=}-IrRNELWpy|@x?4njOb)Vi2MymzDWTfjhADqcKqhGoD zd|^saX>vkLqHf$ZlDwVjZjL~1MgBZDC{5rjc&ucgQzB#<mRwyyWdiqbz|dAKFCB<_pok#Ws4t^ zx3PZi0_p`PYIf?Hakk@6Zl=hY=T(Kj?UL52gkiQF2Z8dVw$IV~oR&W6a|_IE@Q_fA zP5lGzS9m!@oC1oE-{fT-W7E}FYB#q3K}A>S%7&LyZ)2k;EYdE|ni%brJNWzgBYH1I z4I90kwCOXffnic(9nRcw^gr?qZ-N1vg(+*AK4H9gxi^wEMi{wQ^DPLGXW`#tf>0X6 zSE(@&4Z}911XzLaZcEj2WMd{=xBc~l{^muhuxiJ`!&DaBwfbh&XQOt5g%)If$hAg9 znilE!+G;Tbb1~Yf9G3hV-7Q|)bQM=z!Yj&c=o20$rNGcKsbjeLOpROGh_0O_eS9GQ zA?@c}5WPF}xrfZ2!gwuy4LLDb3du;%jT;emTP<+7WVTPZpMEeAHY1^H|I@8skUnj^ z^MGEQfm%DgJ#_pZdks72rY1dV>MYr-0x_VW1+PL;S>({(z8>4W5hCBZC|#7Pnm-_& zSpBZ7iAMApSl^i(m+l7Ey^ekyWr|qK(G>3}8_bXlfx}o*-|L}fkBq*>KHtgegkTAg zu|ifquHQTNrMc~dr0smQ?sIyBtaqo0{Wm#5P@<>lk{giUgw0#i6>DQMWf!U9SQO|g zNcC$qB&eepRZH&(REhL(v)OES_*pyLa2<8;?>`iqi?%Z@wWI(p90oD$opMJ<`KgH3r|pltGnVkT(h$ z&bHSc?zBU+9a~>jEpGz|#lNWlSfCdKr zoW&i2gt$Pnw(knQNhouJw4_v$ z9JHrf`E?NJsTW?HyrtT;9C}t3M0NirWy0EB-sQ}nX}+Ne27Lio14`F7g_DDSpJnSX zYF9ROULMZS0;#87P!nmQ_UnIS^>VZVw15U67$irqU z_B?A1YWU{!$aft*U37%9(m{y1O4W%kp{y*daeyU7x?{CtE>z z<-zjmzCFVX>v6$Mgi)$N*-CB;l=+lD?VndD2M&eXYq1^M?Ps>`-UIsY!?%5YgNt&= zur?H{VMmc;A4o{mRZ)zEQHSI~;VJl9AjuI~mw?-$4QSef4)*cr#)uR3MjVDOi%}oEm+coL z8M}%X=2pFrqR+h1%ujyf(B~?&)ok_NBHHoG8F!7WL0I!rhVp@tc8#){4g%@o=tFwN zB(gWT;)`%;xhq#$wr&WuAs>MS&_pL0h19o2BvzZ7x`4Z{S3>9qUXyuK&6u=)UrN<> zpwBoNl0Ak)_jQO*FqiGmpCH(U;R!$nqwgfoZHH$htsD?eqG}&-uq8_n9$FNEKw1|= z6wcf}*nxl?K^@Yd64Pa;8ytoyL#0;+7V(K;NU~dDaZZsC*tL5~dWE})1J`y!;yh-foC&Qy% z+2Wt>+f40a=8$)75Zw{}+S}tR_BiUhb`u$bo!#nOu4SXzJ|usm5{j<dQMI2s0yoz%rMSShNE}=?Owxegwm7|a z3gQs$*qT?h^)>xy6eTvOsrzqZ_iaaWUQqYo5B2WVl7!YR%G7B1Vd1B3RkJWpztYhj zw}ZQGyf@@xq|AcvRrOBw(|2yYk;XG#jI#XdM`4E`Pq#Sz>pnB%Q&rw=r?8iZ0(Xv` zI#w2RrO!rIwIqKQMfo|_p9zbT^$dM-jj0^>o<<{WcK$k zGRjTpMFO4UK+{KNQ;YC~`~jIa7g_QAmP1;sPHurWLiFE1)fFdoQH-&sSI~iGpw6+8 zFPRq{9u(3F(W{&n4(WfF_p#ZAI=KHVOtcshR=Bg@^W7+_+mrVXm}Xd`e|^vOdEmJJ z6GJHd@M7vz$E(Z}YY&&|)kFs2n;~^LkW7LqR^GzK{yYF`4apvx(yeNlStW;0HgJSG z=ytrkOnVeX6&|~JjMQxej%m;BZ@hgj^j;wb!vJ}UifMV;k4`Ksn-d%H?KX;c{m873 z|Co2ls48i@0{vwOnS*oyRQ8z1u(cc0&(%Jo)ZRKxvc~(8eBV9413bd4iJZ(c>tSJ| z!~es>Nc}Bdrozmj4yWiuKuR9qW>@Q$sgHiqhF1F=wh9L-@9Lz{Vm2`O$}E>X=RNLN zynjcDsH+OJ{KMsMDdXnQmR+|I`I5%62z$r_SE+v@{z_*B@G$M{)^vNu$_pVLQ%+xV>* zW!4=fj0uvUX(T7m7T(k)U7PDOt{W%F&0h1XOjw0s!m54f?g|%~2s5-|1NgOi zPLIj1@!zFV(AD<&Isd!w$|D`{{iG0ZYP(G?1R1^0JLxD*iWYfpgCG>fO35U24uV;F zbk^*qgsyk2+oh>UomfsRpxYa$AZSmOYPv4Aj)K}@(x1*6GeI~&RA-0fPJ53vZM6;U zv~DL*Jjf2DG3j(xiI4ljO9yw=+CL`&y2kAV%tU&+A#`=B1@&D=LTzkPJxqveFexc{ z;LG90!{27x967M>(AGO9ES>t6jE5h`VTNFtdc%|RWhNnTw6fLO%iN9u3O`VZkH+Ut zYY460&eaX=F*=p2K@{SyYYt?BL_0kZG;TKKQw*<%Zps(zY9D|EoyS^mwOBab@F(OG z3Rwfkff_Xop$;F<^Bil`FUndV=_C8~A6I$&5sIXocj$V&&4Gnup)aZ~L#bRw3xpHG zOpn{c3r~JQHB)$v_?_44)#xbY?m<{APQ*3WY8$nV3RZFzlO1qbkcnf%4D(z`!D0dQ z1z2dCv02^Cb(CLms&+L^jAy?FbW>Yfh|_8729Za5hmF{ole%`t;O3;l{gt~|LuZX*`^3c*1qUTn2Q3N&5f17WgbX3KdNly$vh8h2}s zUE;UOEc)3lRRsyVb1IO@!H=TVhk3iM6Flpp^%D5R$y5WjXb@)jH>9nAKM`MYeV>yI zX}#RJQJf^T`pd#F&4~8uw@8d7mS8RepTtz7)cD9Vkd?$QvD66X2 zvSv}z${ye-Gt{ga&yW;D{BiG`RB}5g(e1DH9|PUXyIK`MLdtY=Wh1Wo_j=V9a9oqB zRmD>7XQ)H0%;mjgBUNaug-6?Aw#AIg07Nb990)vt&_Nj5KosI3@3S^s6YfYq&G^pd~+m==@JDa@U( z14x<<@15djiE=_`3q3PX$U>!d&F4%9XuEhml7+8A=b6mH1)H#^uiD@V1`cm_Z(gK0}BC8*z>BL7&6PNsGM>}HqM(JhpL){xF2~k}>{CmblnZ5PHfx9RBk8AT} zs8*kpvxBzX2MDLh$0gwapxORvqABcUct}T@t0Me==J%S=oCZ2K>GEMjv3<=uI=DBg zZ99znA%MvF#LhuO`i}2I$k6G5yYqw6$R@S4B>Hh4fZF=Pg`k;Ylx?dkVL)_x)~z6@ z;^?FnjWi2bWR>F4`zFtshoSz6goFzl*P(x7ST-zx;g6U3@@D7aRubxXNvct$?gxC4 z0+9-+PVdF@B;CZ`@+GOAc5Li#WapnAk`b|CBZiBG@E!A)g+NQf>(Ym~xIQ&id^`W8 zVtzJ!hV+|sWY`;d^zh!bxRt8%3L{#FON#G{GDw?VeWdD3ROkDcp3yi+f(Jfgte4vP zq1#LjWEOI*wG52XYCccU9}KMZ{m5fc!szr_<&r_9Z`9whVzYwYboBfM`F?`7YVdk{!?F5S#tYTO$XZL+$gZFe40}rw@ z6{#Fgtm!mvl^1M+wPjX8$}Ko$JyUp9fVoSo!9~~f%EeS$q{g4Oo!^T3ppFnd8`l}+ z(5Awzzp0u*lMd#@F{l(i>8TyWulFyOG#PE1T6_)+O$8A_3on1)03mYS*CLIKO~1X z*OJ?*nWt^~OE)>RGL#O$W8B5z5?eH2KPoS~2@MgK@6&Ze-;xW_yelsRXs1%Bq6wEz zoUP|47Cm>B^ja?yBjr}EXPaVr6_GCDU;tvF91`f@LV@8N69*2qXjcoTPn`14fd5u<5CVlqVDz22#&wew1-lgLI41!-WV zM7g)bBeq0}5Vx)1$oA^i*ZQKM0IET(WUCVgjDiAPYSYw(LHfhF*{hW@P1yjHM6P56 z;-$^&5Z){^!`tms8t(GuHI0Ytx>~C9`P?Mj9{?HwIlR{dk^bEO?icCFjq=#|6Lrs< z3%jAT<%yW&=)3ZQu0qs7aQolU0XL)qpoU5TFxV!cB$?Y)zT_2TDuA>1(470>nR;$^ z<%aT(`HBl_YE$QQIr$?xqsq!~yWw_cZo=#UcoyTzM>=f@nlIFzhpj|EMc<=Vnc z#dNx@5BfKMa|T-~&F+$Sr>1YoltPxi1Ec5obu6Nuv{X^cYfC6iIsZ|_6 zi_99Cgl6OA|JYL!>FNqd;AjmqRKSkCe7nJrojjdc=6Bzs zs1j~=S-cnmq*|!!uQ7KKjN-2vL_oLL)sv6BT?MXWq0Kqip06bZow%mJKiiw?+H94p z5*_ute&*BIm4o1$x_wqhEu35&<;53>)Qwzl__g{AQv+W#?QG3!c!)8(7icJ|v_o!R z%!>9bYfa_llKNV2rWOF|n75gz(p*UA)T|%E2tu+#T;pCeZuWdF4+H?mzQ`($<*d?f z;-z7^bK zd{~;ftHu|Eu$+5%cVOs?|AMVUUj(3jN10|Jmp*Az284vF@pPtTDk=~P359o&|N|ZGKTN}Ox zl5`4!0Ev0y(NjldQqV$lIw0*O+3_}}cHdtJ?%-e<-CZE)={r95XdS&WmJcieV1=CR zpJr}bU$NxXi7pD(k_GGljZBawfSmc!#hbf`5Efx;T5Og#7cXPrlX~w+3gyJ1Y7KSm zDp|VGxa2tAOuj)|HL8ujU;b0@MpnZ>(JuG*=*XrRJ%3Ik`U|K4hqhAdDp z-+DEL#_rZZZB`S8K@Nus+XEDiu;kJ|C$0fv&XlormlF`1_)3M6to+}VK^$bPqErAg z$y*AI7-u0D^eU!Z!FPX}c_>zmCuBi2oNB|Q%nu29Yn~�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 Vs`!V~6-HfPW?}VP6KRr*>ly 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 diff --git a/src/kivymd/images/rec_st_shadow-1.png b/src/kivymd/images/rec_st_shadow-1.png deleted file mode 100644 index 759ee65285764c0619509c5b8cb27f972b2ab3fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32265 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 G;{P8x^pl$a diff --git a/src/kivymd/images/rec_st_shadow.atlas b/src/kivymd/images/rec_st_shadow.atlas deleted file mode 100644 index d4c24abe..00000000 --- a/src/kivymd/images/rec_st_shadow.atlas +++ /dev/null @@ -1 +0,0 @@ -{"rec_st_shadow-0.png": {"11": [262, 138, 128, 256], "10": [132, 138, 128, 256], "13": [522, 138, 128, 256], "12": [392, 138, 128, 256], "15": [782, 138, 128, 256], "14": [652, 138, 128, 256], "16": [912, 138, 128, 256], "0": [2, 138, 128, 256]}, "rec_st_shadow-1.png": {"20": [522, 138, 128, 256], "21": [652, 138, 128, 256], "17": [2, 138, 128, 256], "23": [912, 138, 128, 256], "19": [262, 138, 128, 256], "18": [132, 138, 128, 256], "22": [782, 138, 128, 256], "1": [392, 138, 128, 256]}, "rec_st_shadow-2.png": {"3": [132, 138, 128, 256], "2": [2, 138, 128, 256], "5": [392, 138, 128, 256], "4": [262, 138, 128, 256], "7": [652, 138, 128, 256], "6": [522, 138, 128, 256], "9": [912, 138, 128, 256], "8": [782, 138, 128, 256]}} \ No newline at end of file diff --git a/src/kivymd/images/round_shadow-0.png b/src/kivymd/images/round_shadow-0.png deleted file mode 100644 index 26d984051562b2baf7d39cb92639aae94d222bda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39635 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 HcaHmiYza5P diff --git a/src/kivymd/images/round_shadow-1.png b/src/kivymd/images/round_shadow-1.png deleted file mode 100644 index d0f4c0fd4a6f9ac07d583e28e27e20a2495c392f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40767 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

(Ig{HG6T4&}_d3cF!08sm%T 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 diff --git a/src/kivymd/images/round_shadow-2.png b/src/kivymd/images/round_shadow-2.png deleted file mode 100644 index d5feef2c8a5a7bedd94cfce29af5cea57fab701f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26510 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 diff --git a/src/kivymd/images/round_shadow.atlas b/src/kivymd/images/round_shadow.atlas deleted file mode 100644 index f25016dc..00000000 --- a/src/kivymd/images/round_shadow.atlas +++ /dev/null @@ -1 +0,0 @@ -{"round_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "round_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "round_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}} \ No newline at end of file diff --git a/src/kivymd/label.py b/src/kivymd/label.py deleted file mode 100644 index 844f2a07..00000000 --- a/src/kivymd/label.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.metrics import sp -from kivy.properties import OptionProperty, DictProperty, ListProperty -from kivy.uix.label import Label -from kivymd.material_resources import DEVICE_TYPE -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - disabled_color: self.theme_cls.disabled_hint_text_color - text_size: (self.width, None) -''') - - -class MDLabel(ThemableBehavior, Label): - font_style = OptionProperty( - 'Body1', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - # Font, Bold, Mobile size, Desktop size (None if same as Mobile) - _font_styles = DictProperty({'Body1': ['Roboto', False, 14, 13], - 'Body2': ['Roboto', True, 14, 13], - 'Caption': ['Roboto', False, 12, None], - 'Subhead': ['Roboto', False, 16, 15], - 'Title': ['Roboto', True, 20, None], - 'Headline': ['Roboto', False, 24, None], - 'Display1': ['Roboto', False, 34, None], - 'Display2': ['Roboto', False, 45, None], - 'Display3': ['Roboto', False, 56, None], - 'Display4': ['RobotoLight', False, 112, None], - 'Button': ['Roboto', True, 14, None], - 'Icon': ['Icons', False, 24, None]}) - - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - - text_color = ListProperty(None, allownone=True) - - _currently_bound_property = {} - - def __init__(self, **kwargs): - super(MDLabel, self).__init__(**kwargs) - self.on_theme_text_color(None, self.theme_text_color) - self.on_font_style(None, self.font_style) - self.on_opposite_colors(None, self.opposite_colors) - - def on_font_style(self, instance, style): - info = self._font_styles[style] - self.font_name = info[0] - self.bold = info[1] - if DEVICE_TYPE == 'desktop' and info[3] is not None: - self.font_size = sp(info[3]) - else: - self.font_size = sp(info[2]) - - def on_theme_text_color(self, instance, value): - t = self.theme_cls - op = self.opposite_colors - setter = self.setter('color') - t.unbind(**self._currently_bound_property) - c = {} - if value == 'Primary': - c = {'text_color' if not op else 'opposite_text_color': setter} - t.bind(**c) - self.color = t.text_color if not op else t.opposite_text_color - elif value == 'Secondary': - c = {'secondary_text_color' if not op else - 'opposite_secondary_text_color': setter} - t.bind(**c) - self.color = t.secondary_text_color if not op else \ - t.opposite_secondary_text_color - elif value == 'Hint': - c = {'disabled_hint_text_color' if not op else - 'opposite_disabled_hint_text_color': setter} - t.bind(**c) - self.color = t.disabled_hint_text_color if not op else \ - t.opposite_disabled_hint_text_color - elif value == 'Error': - c = {'error_color': setter} - t.bind(**c) - self.color = t.error_color - elif value == 'Custom': - self.color = self.text_color if self.text_color else (0, 0, 0, 1) - self._currently_bound_property = c - - def on_text_color(self, *args): - if self.theme_text_color == 'Custom': - self.color = self.text_color - - def on_opposite_colors(self, instance, value): - self.on_theme_text_color(self, self.theme_text_color) diff --git a/src/kivymd/list.py b/src/kivymd/list.py deleted file mode 100644 index 36162329..00000000 --- a/src/kivymd/list.py +++ /dev/null @@ -1,531 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Lists -===== - -`Material Design spec, Lists page `_ - -`Material Design spec, Lists: Controls page `_ - -The class :class:`MDList` in combination with a ListItem like -:class:`OneLineListItem` will create a list that expands as items are added to -it, working nicely with Kivy's :class:`~kivy.uix.scrollview.ScrollView`. - - -Simple examples ---------------- - -Kv Lang: - -.. code-block:: python - - ScrollView: - do_scroll_x: False # Important for MD compliance - MDList: - OneLineListItem: - text: "Single-line item" - TwoLineListItem: - text: "Two-line item" - secondary_text: "Secondary text here" - ThreeLineListItem: - text: "Three-line item" - secondary_text: "This is a multi-line label where you can fit more text than usual" - - -Python: - -.. code-block:: python - - # Sets up ScrollView with MDList, as normally used in Android: - sv = ScrollView() - ml = MDList() - sv.add_widget(ml) - - contacts = ["Paula", "John", "Kate", "Vlad"] - for c in contacts: - ml.add_widget( - OneLineListItem( - text=c - ) - ) - -Advanced usage --------------- - -Due to the variety in sizes and controls in the MD spec, this module suffers -from a certain level of complexity to keep the widgets compliant, flexible -and performant. - -For this KivyMD provides ListItems that try to cover the most common usecases, -when those are insufficient, there's a base class called :class:`ListItem` -which you can use to create your own ListItems. This documentation will only -cover the provided ones, for custom implementations please refer to this -module's source code. - -Text only ListItems -------------------- - -- :class:`~OneLineListItem` -- :class:`~TwoLineListItem` -- :class:`~ThreeLineListItem` - -These are the simplest ones. The :attr:`~ListItem.text` attribute changes the -text in the most prominent line, while :attr:`~ListItem.secondary_text` -changes the second and third line. - -If there are only two lines, :attr:`~ListItem.secondary_text` will shorten -the text to fit in case it is too long; if a third line is available, it will -instead wrap the text to make use of it. - -ListItems with widget containers --------------------------------- - -- :class:`~OneLineAvatarListItem` -- :class:`~TwoLineAvatarListItem` -- :class:`~ThreeLineAvatarListItem` -- :class:`~OneLineIconListItem` -- :class:`~TwoLineIconListItem` -- :class:`~ThreeLineIconListItem` -- :class:`~OneLineAvatarIconListItem` -- :class:`~TwoLineAvatarIconListItem` -- :class:`~ThreeLineAvatarIconListItem` - -These widgets will take other widgets that inherit from :class:`~ILeftBody`, -:class:`ILeftBodyTouch`, :class:`~IRightBody` or :class:`~IRightBodyTouch` and -put them in their corresponding container. - -As the name implies, :class:`~ILeftBody` and :class:`~IRightBody` will signal -that the widget goes into the left or right container, respectively. - -:class:`~ILeftBodyTouch` and :class:`~IRightBodyTouch` do the same thing, -except these widgets will also receive touch events that occur within their -surfaces. - -Python example: - -.. code-block:: python - - class ContactPhoto(ILeftBody, AsyncImage): - pass - - class MessageButton(IRightBodyTouch, MDIconButton): - phone_number = StringProperty() - - def on_release(self): - # sample code: - Dialer.send_sms(phone_number, "Hey! What's up?") - pass - - # Sets up ScrollView with MDList, as normally used in Android: - sv = ScrollView() - ml = MDList() - sv.add_widget(ml) - - contacts = [ - ["Annie", "555-24235", "http://myphotos.com/annie.png"], - ["Bob", "555-15423", "http://myphotos.com/bob.png"], - ["Claire", "555-66098", "http://myphotos.com/claire.png"] - ] - - for c in contacts: - item = TwoLineAvatarIconListItem( - text=c[0], - secondary_text=c[1] - ) - item.add_widget(ContactPhoto(source=c[2])) - item.add_widget(MessageButton(phone_number=c[1]) - ml.add_widget(item) - -API ---- -''' - -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty, NumericProperty, \ - ListProperty, OptionProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.gridlayout import GridLayout -import kivymd.material_resources as m_res -from kivymd.ripplebehavior import RectangularRippleBehavior -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' -#:import m_res kivymd.material_resources - - cols: 1 - size_hint_y: None - height: self._min_list_height - padding: 0, self._list_vertical_padding - - - size_hint_y: None - canvas: - Color: - rgba: self.theme_cls.divider_color - Line: - points: root.x,root.y, root.x+self.width,root.y - BoxLayout: - id: _text_container - orientation: 'vertical' - pos: root.pos - padding: root._txt_left_pad, root._txt_top_pad, root._txt_right_pad, root._txt_bot_pad - MDLabel: - id: _lbl_primary - text: root.text - font_style: root.font_style - theme_text_color: root.theme_text_color - text_color: root.text_color - size_hint_y: None - height: self.texture_size[1] - MDLabel: - id: _lbl_secondary - text: '' if root._num_lines == 1 else root.secondary_text - font_style: root.secondary_font_style - theme_text_color: root.secondary_theme_text_color - text_color: root.secondary_text_color - size_hint_y: None - height: 0 if root._num_lines == 1 else self.texture_size[1] - shorten: True if root._num_lines == 2 else False - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height/2 - self.height/2 - size: dp(40), dp(40) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(40), dp(40) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) -''') - - -class MDList(GridLayout): - '''ListItem container. Best used in conjunction with a - :class:`kivy.uix.ScrollView`. - - When adding (or removing) a widget, it will resize itself to fit its - children, plus top and bottom paddings as described by the MD spec. - ''' - selected = ObjectProperty() - _min_list_height = dp(16) - _list_vertical_padding = dp(8) - - icon = StringProperty() - - def add_widget(self, widget, index=0): - super(MDList, self).add_widget(widget, index) - self.height += widget.height - - def remove_widget(self, widget): - super(MDList, self).remove_widget(widget) - self.height -= widget.height - - -class BaseListItem(ThemableBehavior, RectangularRippleBehavior, - ButtonBehavior, FloatLayout): - '''Base class to all ListItems. Not supposed to be instantiated on its own. - ''' - - text = StringProperty() - '''Text shown in the first line. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults - to "". - ''' - - text_color = ListProperty(None) - ''' Text color used if theme_text_color is set to 'Custom' ''' - - font_style = OptionProperty( - 'Subhead', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - theme_text_color = StringProperty('Primary',allownone=True) - ''' Theme text color for primary text ''' - - secondary_text = StringProperty() - '''Text shown in the second and potentially third line. - - The text will wrap into the third line if the ListItem's type is set to - \'one-line\'. It can be forced into the third line by adding a \\n - escape sequence. - - :attr:`secondary_text` is a :class:`~kivy.properties.StringProperty` and - defaults to "". - ''' - - secondary_text_color = ListProperty(None) - ''' Text color used for secondary text if secondary_theme_text_color - is set to 'Custom' ''' - - secondary_theme_text_color = StringProperty('Secondary',allownone=True) - ''' Theme text color for secondary primary text ''' - - secondary_font_style = OptionProperty( - 'Body1', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - _txt_left_pad = NumericProperty(dp(16)) - _txt_top_pad = NumericProperty() - _txt_bot_pad = NumericProperty() - _txt_right_pad = NumericProperty(m_res.HORIZ_MARGINS) - _num_lines = 2 - - -class ILeftBody: - '''Pseudo-interface for widgets that go in the left container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - ''' - pass - - -class ILeftBodyTouch: - '''Same as :class:`~ILeftBody`, but allows the widget to receive touch - events instead of triggering the ListItem's ripple effect - ''' - pass - - -class IRightBody: - '''Pseudo-interface for widgets that go in the right container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - ''' - pass - - -class IRightBodyTouch: - '''Same as :class:`~IRightBody`, but allows the widget to receive touch - events instead of triggering the ListItem's ripple effect - ''' - pass - - -class ContainerSupport: - '''Overrides add_widget in a ListItem to include support for I*Body - widgets when the appropiate containers are present. - ''' - _touchable_widgets = ListProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, ILeftBody): - self.ids['_left_container'].add_widget(widget) - elif issubclass(widget.__class__, ILeftBodyTouch): - self.ids['_left_container'].add_widget(widget) - self._touchable_widgets.append(widget) - elif issubclass(widget.__class__, IRightBody): - self.ids['_right_container'].add_widget(widget) - elif issubclass(widget.__class__, IRightBodyTouch): - self.ids['_right_container'].add_widget(widget) - self._touchable_widgets.append(widget) - else: - return super(BaseListItem, self).add_widget(widget,index) - - def remove_widget(self, widget): - super(BaseListItem, self).remove_widget(widget) - if widget in self._touchable_widgets: - self._touchable_widgets.remove(widget) - - def on_touch_down(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, 'down'): - return - super(BaseListItem, self).on_touch_down(touch) - - def on_touch_move(self, touch, *args): - if self.propagate_touch_to_touchable_widgets(touch, 'move', *args): - return - super(BaseListItem, self).on_touch_move(touch, *args) - - def on_touch_up(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, 'up'): - return - super(BaseListItem, self).on_touch_up(touch) - - def propagate_touch_to_touchable_widgets(self, touch, touch_event, *args): - triggered = False - for i in self._touchable_widgets: - if i.collide_point(touch.x, touch.y): - triggered = True - if touch_event == 'down': - i.on_touch_down(touch) - elif touch_event == 'move': - i.on_touch_move(touch, *args) - elif touch_event == 'up': - i.on_touch_up(touch) - return triggered - - -class OneLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(16)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 1 - - def __init__(self, **kwargs): - super(OneLineListItem, self).__init__(**kwargs) - self.height = dp(48) - - -class TwoLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - - def __init__(self, **kwargs): - super(TwoLineListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(16)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 3 - - def __init__(self, **kwargs): - super(ThreeLineListItem, self).__init__(**kwargs) - self.height = dp(88) - - -class OneLineAvatarListItem(ContainerSupport, BaseListItem): - _txt_left_pad = NumericProperty(dp(72)) - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(19)) # dp(24) - dp(5) - _num_lines = 1 - - def __init__(self, **kwargs): - super(OneLineAvatarListItem, self).__init__(**kwargs) - self.height = dp(56) - - -class TwoLineAvatarListItem(OneLineAvatarListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineAvatarListItem(ContainerSupport, ThreeLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class OneLineIconListItem(ContainerSupport, OneLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class TwoLineIconListItem(OneLineIconListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineIconListItem(ContainerSupport, ThreeLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class OneLineRightIconListItem(ContainerSupport, OneLineListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class TwoLineRightIconListItem(OneLineRightIconListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineRightIconListitem(ContainerSupport, ThreeLineListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class OneLineAvatarIconListItem(OneLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class TwoLineAvatarIconListItem(TwoLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class ThreeLineAvatarIconListItem(ThreeLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) diff --git a/src/kivymd/material_resources.py b/src/kivymd/material_resources.py deleted file mode 100644 index 46270e5c..00000000 --- a/src/kivymd/material_resources.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy import platform -from kivy.core.window import Window -from kivy.metrics import dp -from kivymd import fonts_path - -# Feel free to override this const if you're designing for a device such as -# a GNU/Linux tablet. -if platform != "android" and platform != "ios": - DEVICE_TYPE = "desktop" -elif Window.width >= dp(600) and Window.height >= dp(600): - DEVICE_TYPE = "tablet" -else: - DEVICE_TYPE = "mobile" - -if DEVICE_TYPE == "mobile": - MAX_NAV_DRAWER_WIDTH = dp(300) - HORIZ_MARGINS = dp(16) - STANDARD_INCREMENT = dp(56) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - dp(8) -else: - MAX_NAV_DRAWER_WIDTH = dp(400) - HORIZ_MARGINS = dp(24) - STANDARD_INCREMENT = dp(64) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - -TOUCH_TARGET_HEIGHT = dp(48) - -FONTS = [ - { - "name": "Roboto", - "fn_regular": fonts_path + 'Roboto-Regular.ttf', - "fn_bold": fonts_path + 'Roboto-Medium.ttf', - "fn_italic": fonts_path + 'Roboto-Italic.ttf', - "fn_bolditalic": fonts_path + 'Roboto-MediumItalic.ttf' - }, - { - "name": "RobotoLight", - "fn_regular": fonts_path + 'Roboto-Thin.ttf', - "fn_bold": fonts_path + 'Roboto-Light.ttf', - "fn_italic": fonts_path + 'Roboto-ThinItalic.ttf', - "fn_bolditalic": fonts_path + 'Roboto-LightItalic.ttf' - }, - { - "name": "Icons", - "fn_regular": fonts_path + 'Material-Design-Iconic-Font.ttf' - } -] diff --git a/src/kivymd/menu.py b/src/kivymd/menu.py deleted file mode 100644 index f4c96ac8..00000000 --- a/src/kivymd/menu.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.garden.recycleview import RecycleView -from kivy.metrics import dp -from kivy.properties import NumericProperty, ListProperty, OptionProperty, \ - StringProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -import kivymd.material_resources as m_res -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' -#:import STD_INC kivymd.material_resources.STANDARD_INCREMENT - - size_hint_y: None - height: dp(48) - padding: dp(16), 0 - on_release: root.parent.parent.parent.parent.dismiss() # Horrible, but hey it works - MDLabel: - text: root.text - theme_text_color: 'Primary' - - - size_hint: None, None - width: root.width_mult * STD_INC - key_viewclass: 'viewclass' - key_size: 'height' - - - FloatLayout: - id: fl - MDMenu: - id: md_menu - data: root.items - width_mult: root.width_mult - size_hint: None, None - size: 0,0 - canvas.before: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: self.size - pos: self.pos -''') - - -class MDMenuItem(ButtonBehavior, BoxLayout): - text = StringProperty() - - -class MDMenu(RecycleView): - width_mult = NumericProperty(1) - - -class MDDropdownMenu(ThemableBehavior, BoxLayout): - items = ListProperty() - '''See :attr:`~kivy.garden.recycleview.RecycleView.data` - ''' - - width_mult = NumericProperty(1) - '''This number multiplied by the standard increment (56dp on mobile, - 64dp on desktop, determines the width of the menu items. - - If the resulting number were to be too big for the application Window, - the multiplier will be adjusted for the biggest possible one. - ''' - - max_height = NumericProperty() - '''The menu will grow no bigger than this number. - - Set to 0 for no limit. Defaults to 0. - ''' - - border_margin = NumericProperty(dp(4)) - '''Margin between Window border and menu - ''' - - ver_growth = OptionProperty(None, allownone=True, - options=['up', 'down']) - '''Where the menu will grow vertically to when opening - - Set to None to let the widget pick for you. Defaults to None. - ''' - - hor_growth = OptionProperty(None, allownone=True, - options=['left', 'right']) - '''Where the menu will grow horizontally to when opening - - Set to None to let the widget pick for you. Defaults to None. - ''' - - def open(self, *largs): - Window.add_widget(self) - Clock.schedule_once(lambda x: self.display_menu(largs[0]), -1) - - def display_menu(self, caller): - # We need to pick a starting point, see how big we need to be, - # and where to grow to. - - c = caller.to_window(caller.center_x, - caller.center_y) # Starting coords - - # ---ESTABLISH INITIAL TARGET SIZE ESTIMATE--- - target_width = self.width_mult * m_res.STANDARD_INCREMENT - # If we're wider than the Window... - if target_width > Window.width: - # ...reduce our multiplier to max allowed. - target_width = int( - Window.width / m_res.STANDARD_INCREMENT) * m_res.STANDARD_INCREMENT - - target_height = sum([dp(48) for i in self.items]) - # If we're over max_height... - if 0 < self.max_height < target_height: - target_height = self.max_height - - # ---ESTABLISH VERTICAL GROWTH DIRECTION--- - if self.ver_growth is not None: - ver_growth = self.ver_growth - else: - # If there's enough space below us: - if target_height <= c[1] - self.border_margin: - ver_growth = 'down' - # if there's enough space above us: - elif target_height < Window.height - c[1] - self.border_margin: - ver_growth = 'up' - # otherwise, let's pick the one with more space and adjust ourselves - else: - # if there's more space below us: - if c[1] >= Window.height - c[1]: - ver_growth = 'down' - target_height = c[1] - self.border_margin - # if there's more space above us: - else: - ver_growth = 'up' - target_height = Window.height - c[1] - self.border_margin - - if self.hor_growth is not None: - hor_growth = self.hor_growth - else: - # If there's enough space to the right: - if target_width <= Window.width - c[0] - self.border_margin: - hor_growth = 'right' - # if there's enough space to the left: - elif target_width < c[0] - self.border_margin: - hor_growth = 'left' - # otherwise, let's pick the one with more space and adjust ourselves - else: - # if there's more space to the right: - if Window.width - c[0] >= c[0]: - hor_growth = 'right' - target_width = Window.width - c[0] - self.border_margin - # if there's more space to the left: - else: - hor_growth = 'left' - target_width = c[0] - self.border_margin - - if ver_growth == 'down': - tar_y = c[1] - target_height - else: # should always be 'up' - tar_y = c[1] - - if hor_growth == 'right': - tar_x = c[0] - else: # should always be 'left' - tar_x = c[0] - target_width - anim = Animation(x=tar_x, y=tar_y, - width=target_width, height=target_height, - duration=.3, transition='out_quint') - menu = self.ids['md_menu'] - menu.pos = c - anim.start(menu) - - def on_touch_down(self, touch): - if not self.ids['md_menu'].collide_point(*touch.pos): - self.dismiss() - return True - super(MDDropdownMenu, self).on_touch_down(touch) - return True - - def on_touch_move(self, touch): - super(MDDropdownMenu, self).on_touch_move(touch) - return True - - def on_touch_up(self, touch): - super(MDDropdownMenu, self).on_touch_up(touch) - return True - - def dismiss(self): - Window.remove_widget(self) diff --git a/src/kivymd/navigationdrawer.py b/src/kivymd/navigationdrawer.py deleted file mode 100644 index 42aa9a62..00000000 --- a/src/kivymd/navigationdrawer.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.icon_definitions import md_icons -from kivymd.label import MDLabel -from kivymd.list import OneLineIconListItem, ILeftBody, BaseListItem -from kivymd.slidingpanel import SlidingPanel -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - canvas: - Color: - rgba: root.theme_cls.divider_color - Line: - points: self.x, self.y, self.x+self.width,self.y - - - _list: list - elevation: 0 - canvas: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: root.size - pos: root.pos - NavDrawerToolbar: - title: root.title - opposite_colors: False - title_theme_color: 'Secondary' - background_color: root.theme_cls.bg_light - elevation: 0 - ScrollView: - do_scroll_x: False - MDList: - id: ml - id: list - - - NDIconLabel: - id: _icon - font_style: 'Icon' - theme_text_color: 'Secondary' -''') - - -class NavigationDrawer(SlidingPanel, ThemableBehavior, ElevationBehavior): - title = StringProperty() - - _list = ObjectProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, BaseListItem): - self._list.add_widget(widget, index) - widget.bind(on_release=lambda x: self.toggle()) - else: - super(NavigationDrawer, self).add_widget(widget, index) - - def _get_main_animation(self, duration, t, x, is_closing): - a = super(NavigationDrawer, self)._get_main_animation(duration, t, x, - is_closing) - a &= Animation(elevation=0 if is_closing else 5, t=t, duration=duration) - return a - - -class NDIconLabel(ILeftBody, MDLabel): - pass - - -class NavigationDrawerIconButton(OneLineIconListItem): - icon = StringProperty() - - def on_icon(self, instance, value): - self.ids['_icon'].text = u"{}".format(md_icons[value]) diff --git a/src/kivymd/progressbar.py b/src/kivymd/progressbar.py deleted file mode 100644 index 6d3a2ca8..00000000 --- a/src/kivymd/progressbar.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import ListProperty, OptionProperty, BooleanProperty -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.progressbar import ProgressBar - - -Builder.load_string(''' -: - canvas: - Clear - Color: - rgba: self.theme_cls.divider_color - Rectangle: - size: (self.width , dp(4)) if self.orientation == 'horizontal' else (dp(4),self.height) - pos: (self.x, self.center_y - dp(4)) if self.orientation == 'horizontal' \ - else (self.center_x - dp(4),self.y) - - - Color: - rgba: self.theme_cls.primary_color - Rectangle: - size: (self.width*self.value_normalized, sp(4)) if self.orientation == 'horizontal' else (sp(4), \ - self.height*self.value_normalized) - pos: (self.width*(1-self.value_normalized)+self.x if self.reversed else self.x, self.center_y - dp(4)) \ - if self.orientation == 'horizontal' else \ - (self.center_x - dp(4),self.height*(1-self.value_normalized)+self.y if self.reversed else self.y) - -''') - - -class MDProgressBar(ThemableBehavior, ProgressBar): - reversed = BooleanProperty(False) - ''' Reverse the direction the progressbar moves. ''' - - orientation = OptionProperty('horizontal', options=['horizontal', 'vertical']) - ''' Orientation of progressbar''' - - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class ProgressBarApp(App): - theme_cls = ThemeManager() - - def build(self): - return Builder.load_string("""#:import MDSlider kivymd.slider.MDSlider -BoxLayout: - orientation:'vertical' - padding: '8dp' - MDSlider: - id:slider - min:0 - max:100 - value: 40 - - MDProgressBar: - value: slider.value - MDProgressBar: - reversed: True - value: slider.value - BoxLayout: - MDProgressBar: - orientation:"vertical" - reversed: True - value: slider.value - - MDProgressBar: - orientation:"vertical" - value: slider.value - -""") - - - ProgressBarApp().run() diff --git a/src/kivymd/ripplebehavior.py b/src/kivymd/ripplebehavior.py deleted file mode 100644 index 21dd3463..00000000 --- a/src/kivymd/ripplebehavior.py +++ /dev/null @@ -1,169 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.properties import ListProperty, NumericProperty, StringProperty, \ - BooleanProperty -from kivy.animation import Animation -from kivy.graphics import Color, Ellipse, StencilPush, StencilPop, \ - StencilUse, StencilUnUse, Rectangle - - -class CommonRipple(object): - ripple_rad = NumericProperty() - ripple_rad_default = NumericProperty(1) - ripple_post = ListProperty() - ripple_color = ListProperty() - ripple_alpha = NumericProperty(.5) - ripple_scale = NumericProperty(None) - ripple_duration_in_fast = NumericProperty(.3) - # FIXME: These speeds should be calculated based on widget size in dp - ripple_duration_in_slow = NumericProperty(2) - ripple_duration_out = NumericProperty(.3) - ripple_func_in = StringProperty('out_quad') - ripple_func_out = StringProperty('out_quad') - - doing_ripple = BooleanProperty(False) - finishing_ripple = BooleanProperty(False) - fading_out = BooleanProperty(False) - - def on_touch_down(self, touch): - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - - if not self.disabled: - if self.doing_ripple: - Animation.cancel_all(self, 'ripple_rad', 'ripple_color', - 'rect_color') - self.anim_complete() - self.ripple_rad = self.ripple_rad_default - self.ripple_pos = (touch.x, touch.y) - - if self.ripple_color != []: - pass - elif hasattr(self, 'theme_cls'): - self.ripple_color = self.theme_cls.ripple_color - else: - # If no theme, set Grey 300 - self.ripple_color = [0.8784313725490196, 0.8784313725490196, - 0.8784313725490196, self.ripple_alpha] - self.ripple_color[3] = self.ripple_alpha - - self.lay_canvas_instructions() - self.finish_rad = max(self.width, self.height) * self.ripple_scale - self.start_ripple() - return super(CommonRipple, self).on_touch_down(touch) - - def lay_canvas_instructions(self): - raise NotImplementedError - - def on_touch_move(self, touch, *args): - if not self.collide_point(touch.x, touch.y): - if not self.finishing_ripple and self.doing_ripple: - self.finish_ripple() - return super(CommonRipple, self).on_touch_move(touch, *args) - - def on_touch_up(self, touch): - if self.collide_point(touch.x, touch.y) and self.doing_ripple: - self.finish_ripple() - return super(CommonRipple, self).on_touch_up(touch) - - def start_ripple(self): - if not self.doing_ripple: - anim = Animation( - ripple_rad=self.finish_rad, - t='linear', - duration=self.ripple_duration_in_slow) - anim.bind(on_complete=self.fade_out) - self.doing_ripple = True - anim.start(self) - - def _set_ellipse(self, instance, value): - self.ellipse.size = (self.ripple_rad, self.ripple_rad) - - # Adjust ellipse pos here - - def _set_color(self, instance, value): - self.col_instruction.a = value[3] - - def finish_ripple(self): - if self.doing_ripple and not self.finishing_ripple: - Animation.cancel_all(self, 'ripple_rad') - anim = Animation(ripple_rad=self.finish_rad, - t=self.ripple_func_in, - duration=self.ripple_duration_in_fast) - anim.bind(on_complete=self.fade_out) - self.finishing_ripple = True - anim.start(self) - - def fade_out(self, *args): - rc = self.ripple_color - if not self.fading_out: - Animation.cancel_all(self, 'ripple_color') - anim = Animation(ripple_color=[rc[0], rc[1], rc[2], 0.], - t=self.ripple_func_out, - duration=self.ripple_duration_out) - anim.bind(on_complete=self.anim_complete) - self.fading_out = True - anim.start(self) - - def anim_complete(self, *args): - self.doing_ripple = False - self.finishing_ripple = False - self.fading_out = False - self.canvas.after.clear() - - -class RectangularRippleBehavior(CommonRipple): - ripple_scale = NumericProperty(2.75) - - def lay_canvas_instructions(self): - with self.canvas.after: - StencilPush() - Rectangle(pos=self.pos, size=self.size) - StencilUse() - self.col_instruction = Color(rgba=self.ripple_color) - self.ellipse = \ - Ellipse(size=(self.ripple_rad, self.ripple_rad), - pos=(self.ripple_pos[0] - self.ripple_rad / 2., - self.ripple_pos[1] - self.ripple_rad / 2.)) - StencilUnUse() - Rectangle(pos=self.pos, size=self.size) - StencilPop() - self.bind(ripple_color=self._set_color, - ripple_rad=self._set_ellipse) - - def _set_ellipse(self, instance, value): - super(RectangularRippleBehavior, self)._set_ellipse(instance, value) - self.ellipse.pos = (self.ripple_pos[0] - self.ripple_rad / 2., - self.ripple_pos[1] - self.ripple_rad / 2.) - - -class CircularRippleBehavior(CommonRipple): - ripple_scale = NumericProperty(1) - - def lay_canvas_instructions(self): - with self.canvas.after: - StencilPush() - self.stencil = Ellipse(size=(self.width * self.ripple_scale, - self.height * self.ripple_scale), - pos=(self.center_x - ( - self.width * self.ripple_scale) / 2, - self.center_y - ( - self.height * self.ripple_scale) / 2)) - StencilUse() - self.col_instruction = Color(rgba=self.ripple_color) - self.ellipse = Ellipse(size=(self.ripple_rad, self.ripple_rad), - pos=(self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.)) - StencilUnUse() - Ellipse(pos=self.pos, size=self.size) - StencilPop() - self.bind(ripple_color=self._set_color, - ripple_rad=self._set_ellipse) - - def _set_ellipse(self, instance, value): - super(CircularRippleBehavior, self)._set_ellipse(instance, value) - if self.ellipse.size[0] > self.width * .6 and not self.fading_out: - self.fade_out() - self.ellipse.pos = (self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.) diff --git a/src/kivymd/selectioncontrols.py b/src/kivymd/selectioncontrols.py deleted file mode 100644 index b918428a..00000000 --- a/src/kivymd/selectioncontrols.py +++ /dev/null @@ -1,240 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, NumericProperty -from kivy.uix.behaviors import ToggleButtonBehavior -from kivy.uix.label import Label -from kivy.uix.floatlayout import FloatLayout -from kivy.properties import AliasProperty, BooleanProperty -from kivy.metrics import dp, sp -from kivy.animation import Animation -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.icon_definitions import md_icons -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import RoundElevationBehavior -from kivymd.ripplebehavior import CircularRippleBehavior -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.widget import Widget - -Builder.load_string(''' -: - canvas: - Clear - Color: - rgba: self.color - Rectangle: - texture: self.texture - size: self.texture_size - pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.) - - text: self._radio_icon if self.group else self._checkbox_icon - font_name: 'Icons' - font_size: sp(24) - color: self.theme_cls.primary_color if self.active else self.theme_cls.secondary_text_color - halign: 'center' - valign: 'middle' - -: - color: 1, 1, 1, 1 - canvas: - Color: - rgba: self.color - Ellipse: - size: self.size - pos: self.pos - -: - canvas.before: - Color: - rgba: self._track_color_disabled if self.disabled else \ - (self._track_color_active if self.active else self._track_color_normal) - Ellipse: - size: dp(16), dp(16) - pos: self.x, self.center_y - dp(8) - angle_start: 180 - angle_end: 360 - Rectangle: - size: self.width - dp(16), dp(16) - pos: self.x + dp(8), self.center_y - dp(8) - Ellipse: - size: dp(16), dp(16) - pos: self.right - dp(16), self.center_y - dp(8) - angle_start: 0 - angle_end: 180 - on_release: thumb.trigger_action() - - Thumb: - id: thumb - size_hint: None, None - size: dp(24), dp(24) - pos: root._thumb_pos - color: root.thumb_color_disabled if root.disabled else \ - (root.thumb_color_down if root.active else root.thumb_color) - elevation: 4 if root.active else 2 - on_release: setattr(root, 'active', not root.active) -''') - - -class MDCheckbox(ThemableBehavior, CircularRippleBehavior, - ToggleButtonBehavior, Label): - active = BooleanProperty(False) - - _checkbox_icon = StringProperty( - u"{}".format(md_icons['square-o'])) - _radio_icon = StringProperty(u"{}".format(md_icons['circle-o'])) - _icon_active = StringProperty(u"{}".format(md_icons['check-square'])) - - def __init__(self, **kwargs): - super(MDCheckbox, self).__init__(**kwargs) - self.register_event_type('on_active') - self.check_anim_out = Animation(font_size=0, duration=.1, t='out_quad') - self.check_anim_in = Animation(font_size=sp(24), duration=.1, - t='out_quad') - self.check_anim_out.bind( - on_complete=lambda *x: self.check_anim_in.start(self)) - - def on_state(self, *args): - if self.state == 'down': - self.check_anim_in.cancel(self) - self.check_anim_out.start(self) - self._radio_icon = u"{}".format(md_icons['dot-circle']) - self._checkbox_icon = u"{}".format(md_icons['check-square']) - self.active = True - else: - self.check_anim_in.cancel(self) - self.check_anim_out.start(self) - self._radio_icon = u"{}".format(md_icons['circle-o']) - self._checkbox_icon = u"{}".format( - md_icons['square-o']) - self.active = False - - def on_active(self, instance, value): - self.state = 'down' if value else 'normal' - - -class Thumb(RoundElevationBehavior, CircularRippleBehavior, ButtonBehavior, - Widget): - ripple_scale = NumericProperty(2) - - def _set_ellipse(self, instance, value): - self.ellipse.size = (self.ripple_rad, self.ripple_rad) - if self.ellipse.size[0] > self.width * 1.5 and not self.fading_out: - self.fade_out() - self.ellipse.pos = (self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.) - self.stencil.pos = ( - self.center_x - (self.width * self.ripple_scale) / 2, - self.center_y - (self.height * self.ripple_scale) / 2) - - -class MDSwitch(ThemableBehavior, ButtonBehavior, FloatLayout): - active = BooleanProperty(False) - - _thumb_color = ListProperty(get_color_from_hex(colors['Grey']['50'])) - - def _get_thumb_color(self): - return self._thumb_color - - def _set_thumb_color(self, color, alpha=None): - if len(color) == 2: - self._thumb_color = get_color_from_hex(colors[color[0]][color[1]]) - if alpha: - self._thumb_color[3] = alpha - elif len(color) == 4: - self._thumb_color = color - - thumb_color = AliasProperty(_get_thumb_color, _set_thumb_color, - bind=['_thumb_color']) - - _thumb_color_down = ListProperty([1, 1, 1, 1]) - - def _get_thumb_color_down(self): - return self._thumb_color_down - - def _set_thumb_color_down(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_down[3] = alpha - else: - self._thumb_color_down[3] = 1 - elif len(color) == 4: - self._thumb_color_down = color - - thumb_color_down = AliasProperty(_get_thumb_color_down, - _set_thumb_color_down, - bind=['_thumb_color_down']) - - _thumb_color_disabled = ListProperty( - get_color_from_hex(colors['Grey']['400'])) - - def _get_thumb_color_disabled(self): - return self._thumb_color_disabled - - def _set_thumb_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_disabled[3] = alpha - elif len(color) == 4: - self._thumb_color_disabled = color - - thumb_color_down = AliasProperty(_get_thumb_color_disabled, - _set_thumb_color_disabled, - bind=['_thumb_color_disabled']) - - _track_color_active = ListProperty() - _track_color_normal = ListProperty() - _track_color_disabled = ListProperty() - _thumb_pos = ListProperty([0, 0]) - - def __init__(self, **kwargs): - super(MDSwitch, self).__init__(**kwargs) - self.theme_cls.bind(theme_style=self._set_colors, - primary_color=self._set_colors, - primary_palette=self._set_colors) - self._set_colors() - - def _set_colors(self, *args): - self._track_color_normal = self.theme_cls.disabled_hint_text_color - if self.theme_cls.theme_style == 'Dark': - self._track_color_active = self.theme_cls.primary_color - self._track_color_active[3] = .5 - self._track_color_disabled = get_color_from_hex('FFFFFF') - self._track_color_disabled[3] = .1 - self.thumb_color = get_color_from_hex(colors['Grey']['400']) - self.thumb_color_down = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self.thumb_color_disabled = get_color_from_hex( - colors['Grey']['800']) - else: - self._track_color_active = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self._track_color_active[3] = .5 - self._track_color_disabled = self.theme_cls.disabled_hint_text_color - self.thumb_color_down = self.theme_cls.primary_color - - def on_pos(self, *args): - if self.active: - self._thumb_pos = (self.right - dp(12), self.center_y - dp(12)) - else: - self._thumb_pos = (self.x - dp(12), self.center_y - dp(12)) - self.bind(active=self._update_thumb) - - def _update_thumb(self, *args): - if self.active: - Animation.cancel_all(self, '_thumb_pos') - anim = Animation( - _thumb_pos=(self.right - dp(12), self.center_y - dp(12)), - duration=.2, - t='out_quad') - else: - Animation.cancel_all(self, '_thumb_pos') - anim = Animation( - _thumb_pos=(self.x - dp(12), self.center_y - dp(12)), - duration=.2, - t='out_quad') - anim.start(self) diff --git a/src/kivymd/slider.py b/src/kivymd/slider.py deleted file mode 100644 index 1166bea7..00000000 --- a/src/kivymd/slider.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, NumericProperty,AliasProperty, BooleanProperty -from kivy.utils import get_color_from_hex -from kivy.metrics import dp, sp -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.slider import Slider - - -Builder.load_string(''' -#:import Thumb kivymd.selectioncontrols.Thumb - -: - id: slider - canvas: - Clear - Color: - rgba: self._track_color_disabled if self.disabled else (self._track_color_active if self.active \ - else self._track_color_normal) - Rectangle: - size: (self.width - self.padding*2 - self._offset[0], dp(4)) if self.orientation == 'horizontal' \ - else (dp(4),self.height - self.padding*2 - self._offset[1]) - pos: (self.x + self.padding + self._offset[0], self.center_y - dp(4)) \ - if self.orientation == 'horizontal' else (self.center_x - dp(4),self.y + self.padding + self._offset[1]) - - # If 0 draw circle - Color: - rgba: [0,0,0,0] if not self._is_off else (self._track_color_disabled if self.disabled \ - else (self._track_color_active if self.active else self._track_color_normal)) - Line: - width: 2 - circle: (self.x+self.padding+dp(3),self.center_y-dp(2),8 if self.active else 6 ) \ - if self.orientation == 'horizontal' else (self.center_x-dp(2),self.y+self.padding+dp(3),8 \ - if self.active else 6) - - Color: - rgba: [0,0,0,0] if self._is_off \ - else (self.thumb_color_down if not self.disabled else self._track_color_disabled) - Rectangle: - size: ((self.width-self.padding*2)*self.value_normalized, sp(4)) \ - if slider.orientation == 'horizontal' else (sp(4), (self.height-self.padding*2)*self.value_normalized) - pos: (self.x + self.padding, self.center_y - dp(4)) if self.orientation == 'horizontal' \ - else (self.center_x - dp(4),self.y + self.padding) - Thumb: - id: thumb - size_hint: None, None - size: (dp(12), dp(12)) if root.disabled else ((dp(24), dp(24)) if root.active else (dp(16),dp(16))) - pos: (slider.value_pos[0] - dp(8), slider.center_y - thumb.height/2 - dp(2)) \ - if slider.orientation == 'horizontal' \ - else (slider.center_x - thumb.width/2 - dp(2), slider.value_pos[1]-dp(8)) - color: [0,0,0,0] if slider._is_off else (root._track_color_disabled if root.disabled \ - else root.thumb_color_down) - elevation: 0 if slider._is_off else (4 if root.active else 2) - -''') - - -class MDSlider(ThemableBehavior, Slider): - # If the slider is clicked - active = BooleanProperty(False) - - # Show the "off" ring when set to minimum value - show_off = BooleanProperty(True) - - # Internal state of ring - _is_off = BooleanProperty(False) - - # Internal adjustment to reposition sliders for ring - _offset = ListProperty((0, 0)) - - _thumb_color = ListProperty(get_color_from_hex(colors['Grey']['50'])) - - def _get_thumb_color(self): - return self._thumb_color - - def _set_thumb_color(self, color, alpha=None): - if len(color) == 2: - self._thumb_color = get_color_from_hex(colors[color[0]][color[1]]) - if alpha: - self._thumb_color[3] = alpha - elif len(color) == 4: - self._thumb_color = color - - thumb_color = AliasProperty(_get_thumb_color, _set_thumb_color, - bind=['_thumb_color']) - - _thumb_color_down = ListProperty([1, 1, 1, 1]) - - def _get_thumb_color_down(self): - return self._thumb_color_down - - def _set_thumb_color_down(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_down[3] = alpha - else: - self._thumb_color_down[3] = 1 - elif len(color) == 4: - self._thumb_color_down = color - - thumb_color_down = AliasProperty(_get_thumb_color_down, - _set_thumb_color_down, - bind=['_thumb_color_down']) - - _thumb_color_disabled = ListProperty( - get_color_from_hex(colors['Grey']['400'])) - - def _get_thumb_color_disabled(self): - return self._thumb_color_disabled - - def _set_thumb_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_disabled[3] = alpha - elif len(color) == 4: - self._thumb_color_disabled = color - - thumb_color_down = AliasProperty(_get_thumb_color_disabled, - _set_thumb_color_disabled, - bind=['_thumb_color_disabled']) - - _track_color_active = ListProperty() - _track_color_normal = ListProperty() - _track_color_disabled = ListProperty() - _thumb_pos = ListProperty([0, 0]) - - def __init__(self, **kwargs): - super(MDSlider, self).__init__(**kwargs) - self.theme_cls.bind(theme_style=self._set_colors, - primary_color=self._set_colors, - primary_palette=self._set_colors) - self._set_colors() - - def _set_colors(self, *args): - if self.theme_cls.theme_style == 'Dark': - self._track_color_normal = get_color_from_hex('FFFFFF') - self._track_color_normal[3] = .3 - self._track_color_active = self._track_color_normal - self._track_color_disabled = self._track_color_normal - self.thumb_color = get_color_from_hex(colors['Grey']['400']) - self.thumb_color_down = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self.thumb_color_disabled = get_color_from_hex( - colors['Grey']['800']) - else: - self._track_color_normal = get_color_from_hex('000000') - self._track_color_normal[3] = 0.26 - self._track_color_active = get_color_from_hex('000000') - self._track_color_active[3] = 0.38 - self._track_color_disabled = get_color_from_hex('000000') - self._track_color_disabled[3] = 0.26 - self.thumb_color_down = self.theme_cls.primary_color - - def on_value_normalized(self, *args): - """ When the value == min set it to "off" state and make slider a ring """ - self._update_is_off() - - def on_show_off(self, *args): - self._update_is_off() - - def _update_is_off(self): - self._is_off = self.show_off and (self.value_normalized == 0) - - def on__is_off(self, *args): - self._update_offset() - - def on_active(self, *args): - self._update_offset() - - def _update_offset(self): - """ Offset is used to shift the sliders so the background color - shows through the off circle. - """ - d = 2 if self.active else 0 - self._offset = (dp(11+d), dp(11+d)) if self._is_off else (0, 0) - - def on_touch_down(self, touch): - if super(MDSlider, self).on_touch_down(touch): - self.active = True - - def on_touch_up(self,touch): - if super(MDSlider, self).on_touch_up(touch): - self.active = False -# thumb = self.ids['thumb'] -# if thumb.collide_point(*touch.pos): -# thumb.on_touch_down(touch) -# thumb.on_touch_up(touch) - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class SliderApp(App): - theme_cls = ThemeManager() - - def build(self): - return Builder.load_string(""" -BoxLayout: - orientation:'vertical' - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle disabled" - color: [0,0,0,1] - CheckBox: - on_press: slider.disabled = not slider.disabled - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle active" - color: [0,0,0,1] - CheckBox: - on_press: slider.active = not slider.active - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle show off" - color: [0,0,0,1] - CheckBox: - on_press: slider.show_off = not slider.show_off - - MDSlider: - id:slider - min:0 - max:100 - value: 40 - - MDSlider: - id:slider2 - orientation:"vertical" - min:0 - max:100 - value: 40 - -""") - - - SliderApp().run() diff --git a/src/kivymd/slidingpanel.py b/src/kivymd/slidingpanel.py deleted file mode 100644 index b818505a..00000000 --- a/src/kivymd/slidingpanel.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import OptionProperty, NumericProperty, StringProperty, \ - BooleanProperty, ListProperty -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.relativelayout import RelativeLayout - -Builder.load_string(""" -#: import Window kivy.core.window.Window - - orientation: 'vertical' - size_hint_x: None - width: dp(320) - x: -1 * self.width if self.side == 'left' else Window.width - - - canvas: - Color: - rgba: root.color - Rectangle: - size: root.size -""") - - -class PanelShadow(BoxLayout): - color = ListProperty([0, 0, 0, 0]) - - -class SlidingPanel(BoxLayout): - anim_length_close = NumericProperty(0.3) - anim_length_open = NumericProperty(0.3) - animation_t_open = StringProperty('out_sine') - animation_t_close = StringProperty('out_sine') - side = OptionProperty('left', options=['left', 'right']) - - _open = False - - def __init__(self, **kwargs): - super(SlidingPanel, self).__init__(**kwargs) - self.shadow = PanelShadow() - Clock.schedule_once(lambda x: Window.add_widget(self.shadow,89), 0) - Clock.schedule_once(lambda x: Window.add_widget(self,90), 0) - - def toggle(self): - Animation.stop_all(self, 'x') - Animation.stop_all(self.shadow, 'color') - if self._open: - if self.side == 'left': - target_x = -1 * self.width - else: - target_x = Window.width - - sh_anim = Animation(duration=self.anim_length_open, - t=self.animation_t_open, - color=[0, 0, 0, 0]) - sh_anim.start(self.shadow) - self._get_main_animation(duration=self.anim_length_close, - t=self.animation_t_close, - x=target_x, - is_closing=True).start(self) - self._open = False - else: - if self.side == 'left': - target_x = 0 - else: - target_x = Window.width - self.width - Animation(duration=self.anim_length_open, t=self.animation_t_open, - color=[0, 0, 0, 0.5]).start(self.shadow) - self._get_main_animation(duration=self.anim_length_open, - t=self.animation_t_open, - x=target_x, - is_closing=False).start(self) - self._open = True - - def _get_main_animation(self, duration, t, x, is_closing): - return Animation(duration=duration, t=t, x=x) - - def on_touch_down(self, touch): - # Prevents touch events from propagating to anything below the widget. - super(SlidingPanel, self).on_touch_down(touch) - if self.collide_point(*touch.pos) or self._open: - return True - - def on_touch_up(self, touch): - if not self.collide_point(touch.x, touch.y) and self._open: - self.toggle() - return True - super(SlidingPanel, self).on_touch_up(touch) diff --git a/src/kivymd/snackbar.py b/src/kivymd/snackbar.py deleted file mode 100644 index e0ac70e8..00000000 --- a/src/kivymd/snackbar.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -from collections import deque -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty, NumericProperty -from kivy.uix.relativelayout import RelativeLayout -from kivymd.material_resources import DEVICE_TYPE - -Builder.load_string(''' -#:import Window kivy.core.window.Window -#:import get_color_from_hex kivy.utils.get_color_from_hex -#:import MDFlatButton kivymd.button.MDFlatButton -#:import MDLabel kivymd.label.MDLabel -#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE -<_SnackbarWidget> - canvas: - Color: - rgb: get_color_from_hex('323232') - Rectangle: - size: self.size - size_hint_y: None - size_hint_x: 1 if DEVICE_TYPE == 'mobile' else None - height: dp(48) if _label.texture_size[1] < dp(30) else dp(80) - width: dp(24) + _label.width + _spacer.width + root.padding_right if root.button_text == '' else dp(24) + \ - _label.width + _spacer.width + _button.width + root.padding_right - top: 0 - x: 0 if DEVICE_TYPE == 'mobile' else Window.width/2 - self.width/2 - BoxLayout: - width: Window.width - root.padding_right - _spacer.width - dp(24) if DEVICE_TYPE == 'mobile' and \ - root.button_text == '' else Window.width - root.padding_right - _button.width - _spacer.width - dp(24) \ - if DEVICE_TYPE == 'mobile' else _label.texture_size[0] if (dp(568) - root.padding_right - _button.width - \ - _spacer.width - _label.texture_size[0] - dp(24)) >= 0 else (dp(568) - root.padding_right - _button.width - \ - _spacer.width - dp(24)) - size_hint_x: None - x: dp(24) - MDLabel: - id: _label - text: root.text - size: self.texture_size - BoxLayout: - id: _spacer - size_hint_x: None - x: _label.right - width: 0 - MDFlatButton: - id: _button - text: root.button_text - size_hint_x: None - x: _spacer.right if root.button_text != '' else root.right - center_y: root.height/2 - on_release: root.button_callback() -''') - - -class _SnackbarWidget(RelativeLayout): - text = StringProperty() - button_text = StringProperty() - button_callback = ObjectProperty() - duration = NumericProperty() - padding_right = NumericProperty(dp(24)) - - def __init__(self, text, duration, button_text='', button_callback=None, - **kwargs): - super(_SnackbarWidget, self).__init__(**kwargs) - self.text = text - self.button_text = button_text - self.button_callback = button_callback - self.duration = duration - self.ids['_label'].text_size = (None, None) - - def begin(self): - if self.button_text == '': - self.remove_widget(self.ids['_button']) - else: - self.ids['_spacer'].width = dp(16) if \ - DEVICE_TYPE == "mobile" else dp(40) - self.padding_right = dp(16) - Window.add_widget(self) - anim = Animation(y=0, duration=.3, t='out_quad') - anim.start(self) - Clock.schedule_once(lambda dt: self.die(), self.duration) - - def die(self): - anim = Animation(top=0, duration=.3, t='out_quad') - anim.bind(on_complete=lambda *args: _play_next(self)) - anim.bind(on_complete=lambda *args: Window.remove_widget(self)) - anim.start(self) - - -queue = deque() -playing = False - - -def make(text, button_text=None, button_callback=None, duration=3): - if button_text is not None and button_callback is not None: - queue.append(_SnackbarWidget(text=text, - button_text=button_text, - button_callback=button_callback, - duration=duration)) - else: - queue.append(_SnackbarWidget(text=text, - duration=duration)) - _play_next() - - -def _play_next(dying_widget=None): - global playing - if (dying_widget or not playing) and len(queue) > 0: - playing = True - queue.popleft().begin() - elif len(queue) == 0: - playing = False diff --git a/src/kivymd/spinner.py b/src/kivymd/spinner.py deleted file mode 100644 index 238062db..00000000 --- a/src/kivymd/spinner.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.widget import Widget -from kivy.properties import NumericProperty, ListProperty, BooleanProperty -from kivy.animation import Animation -from kivymd.theming import ThemableBehavior -from kivy.clock import Clock - -Builder.load_string(''' -: - canvas.before: - PushMatrix - Rotate: - angle: self._rotation_angle - origin: self.center - canvas: - Color: - rgba: self.color - a: self._alpha - Line: - circle: self.center_x, self.center_y, self.width / 2, \ - self._angle_start, self._angle_end - cap: 'square' - width: dp(2) - canvas.after: - PopMatrix - -''') - - -class MDSpinner(ThemableBehavior, Widget): - """:class:`MDSpinner` is an implementation of the circular progress - indicator in Google's Material Design. - - It can be used either as an indeterminate indicator that loops while - the user waits for something to happen, or as a determinate indicator. - - Set :attr:`determinate` to **True** to activate determinate mode, and - :attr:`determinate_time` to set the duration of the animation. - """ - - determinate = BooleanProperty(False) - """:attr:`determinate` is a :class:`~kivy.properties.BooleanProperty` and - defaults to False - """ - - determinate_time = NumericProperty(2) - """:attr:`determinate_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to 2 - """ - - active = BooleanProperty(True) - """Use :attr:`active` to start or stop the spinner. - - :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and - defaults to True - """ - - color = ListProperty([]) - """:attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to 'self.theme_cls.primary_color' - """ - - _alpha = NumericProperty(0) - _rotation_angle = NumericProperty(360) - _angle_start = NumericProperty(0) - _angle_end = NumericProperty(8) - - def __init__(self, **kwargs): - super(MDSpinner, self).__init__(**kwargs) - Clock.schedule_interval(self._update_color, 5) - self.color = self.theme_cls.primary_color - self._alpha_anim_in = Animation(_alpha=1, duration=.8, t='out_quad') - self._alpha_anim_out = Animation(_alpha=0, duration=.3, t='out_quad') - self._alpha_anim_out.bind(on_complete=self._reset) - - if self.determinate: - self._start_determinate() - else: - self._start_loop() - - def _update_color(self, *args): - self.color = self.theme_cls.primary_color - - def _start_determinate(self, *args): - self._alpha_anim_in.start(self) - - _rot_anim = Animation(_rotation_angle=0, - duration=self.determinate_time * .7, - t='out_quad') - _rot_anim.start(self) - - _angle_start_anim = Animation(_angle_end=360, - duration=self.determinate_time, - t='in_out_quad') - _angle_start_anim.bind(on_complete=lambda *x: \ - self._alpha_anim_out.start(self)) - - _angle_start_anim.start(self) - - def _start_loop(self, *args): - if self._alpha == 0: - _rot_anim = Animation(_rotation_angle=0, - duration=2, - t='linear') - _rot_anim.start(self) - - self._alpha = 1 - self._alpha_anim_in.start(self) - _angle_start_anim = Animation(_angle_end=self._angle_end + 270, - duration=.6, - t='in_out_cubic') - _angle_start_anim.bind(on_complete=self._anim_back) - _angle_start_anim.start(self) - - def _anim_back(self, *args): - _angle_back_anim = Animation(_angle_start=self._angle_end - 8, - duration=.6, - t='in_out_cubic') - _angle_back_anim.bind(on_complete=self._start_loop) - - _angle_back_anim.start(self) - - def on__rotation_angle(self, *args): - if self._rotation_angle == 0: - self._rotation_angle = 360 - if not self.determinate: - _rot_anim = Animation(_rotation_angle=0, - duration=2) - _rot_anim.start(self) - - def _reset(self, *args): - Animation.cancel_all(self, '_angle_start', '_rotation_angle', - '_angle_end', '_alpha') - self._angle_start = 0 - self._angle_end = 8 - self._rotation_angle = 360 - self._alpha = 0 - self.active = False - - def on_active(self, *args): - if not self.active: - self._reset() - else: - if self.determinate: - self._start_determinate() - else: - self._start_loop() diff --git a/src/kivymd/tabs.py b/src/kivymd/tabs.py deleted file mode 100644 index c09f21c2..00000000 --- a/src/kivymd/tabs.py +++ /dev/null @@ -1,303 +0,0 @@ -# Created on Jul 8, 2016 -# -# The default kivy tab implementation seems like a stupid design to me. The -# ScreenManager is much better. -# -# @author: jrm - -from kivy.properties import StringProperty, DictProperty, ListProperty, \ - ObjectProperty, OptionProperty, BoundedNumericProperty -from kivy.uix.screenmanager import Screen -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.uix.boxlayout import BoxLayout -from kivymd.theming import ThemableBehavior -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.button import MDFlatButton - -Builder.load_string(""" -: - id: panel - orientation: 'vertical' if panel.tab_orientation in ['top','bottom'] else 'horizontal' - ScrollView: - id: scroll_view - size_hint_y: None - height: panel._tab_display_height[panel.tab_display_mode] - MDTabBar: - id: tab_bar - size_hint_y: None - height: panel._tab_display_height[panel.tab_display_mode] - background_color: panel.tab_color or panel.theme_cls.primary_color - canvas: - # Draw bottom border - Color: - rgba: (panel.tab_border_color or panel.tab_color or panel.theme_cls.primary_dark) - Rectangle: - size: (self.width,dp(2)) - ScreenManager: - id: tab_manager - current: root.current - screens: root.tabs - - -: - canvas: - Color: - rgba: self.panel.tab_color or self.panel.theme_cls.primary_color - Rectangle: - size: self.size - pos: self.pos - - # Draw indicator - Color: - rgba: (self.panel.tab_indicator_color or self.panel.theme_cls.accent_color) if self.tab \ - and self.tab.manager and self.tab.manager.current==self.tab.name else (self.panel.tab_border_color \ - or self.panel.tab_color or self.panel.theme_cls.primary_dark) - Rectangle: - size: (self.width,dp(2)) - pos: self.pos - - size_hint: (None,None) #(1, None) if self.panel.tab_width_mode=='fixed' else (None,None) - width: (_label.texture_size[0] + dp(16)) - padding: (dp(12), 0) - theme_text_color: 'Custom' - text_color: (self.panel.tab_text_color_active or app.theme_cls.bg_light if app.theme_cls.theme_style == "Light" \ - else app.theme_cls.opposite_bg_light) if self.tab and self.tab.manager \ - and self.tab.manager.current==self.tab.name else (self.panel.tab_text_color \ - or self.panel.theme_cls.primary_light) - on_press: - self.tab.dispatch('on_tab_press') - # self.tab.manager.current = self.tab.name - on_release: self.tab.dispatch('on_tab_release') - on_touch_down: self.tab.dispatch('on_tab_touch_down',*args) - on_touch_move: self.tab.dispatch('on_tab_touch_move',*args) - on_touch_up: self.tab.dispatch('on_tab_touch_up',*args) - - - MDLabel: - id: _label - text: root.tab.text if root.panel.tab_display_mode == 'text' else u"{}".format(md_icons[root.tab.icon]) - font_style: 'Button' if root.panel.tab_display_mode == 'text' else 'Icon' - size_hint_x: None# if root.panel.tab_width_mode=='fixed' else 1 - text_size: (None, root.height) - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - valign: 'middle' - halign: 'center' - opposite_colors: root.opposite_colors -""") - - -class MDTabBar(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - pass - - -class MDTabHeader(MDFlatButton): - """ Internal widget for headers based on MDFlatButton""" - - width = BoundedNumericProperty(dp(None), min=dp(72), max=dp(264), errorhandler=lambda x: dp(72)) - tab = ObjectProperty(None) - panel = ObjectProperty(None) - - -class MDTab(Screen): - """ A tab is simply a screen with meta information - that defines the content that goes in the tab header. - """ - __events__ = ('on_tab_touch_down', 'on_tab_touch_move', 'on_tab_touch_up', 'on_tab_press', 'on_tab_release') - - # Tab header text - text = StringProperty("") - - # Tab header icon - icon = StringProperty("circle") - - # Tab dropdown menu items - menu_items = ListProperty() - - # Tab dropdown menu (if you want to customize it) - menu = ObjectProperty(None) - - def __init__(self, **kwargs): - super(MDTab, self).__init__(**kwargs) - self.index = 0 - self.parent_widget = None - self.register_event_type('on_tab_touch_down') - self.register_event_type('on_tab_touch_move') - self.register_event_type('on_tab_touch_up') - self.register_event_type('on_tab_press') - self.register_event_type('on_tab_release') - - def on_leave(self, *args): - self.parent_widget.ids.tab_manager.transition.direction = self.parent_widget.prev_dir - - def on_tab_touch_down(self, *args): - pass - - def on_tab_touch_move(self, *args): - pass - - def on_tab_touch_up(self, *args): - pass - - def on_tab_press(self, *args): - par = self.parent_widget - if par.previous_tab is not self: - par.prev_dir = str(par.ids.tab_manager.transition.direction) - if par.previous_tab.index > self.index: - par.ids.tab_manager.transition.direction = "right" - elif par.previous_tab.index < self.index: - par.ids.tab_manager.transition.direction = "left" - par.ids.tab_manager.current = self.name - par.previous_tab = self - - def on_tab_release(self, *args): - pass - - def __repr__(self): - return "".format(self.name, self.text) - - -class MDTabbedPanel(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - """ A tab panel that is implemented by delegating all tabs - to a ScreenManager. - """ - # If tabs should fill space - tab_width_mode = OptionProperty('stacked', options=['stacked', 'fixed']) - - # Where the tabs go - tab_orientation = OptionProperty('top', options=['top']) # ,'left','bottom','right']) - - # How tabs are displayed - tab_display_mode = OptionProperty('text', options=['text', 'icons']) # ,'both']) - _tab_display_height = DictProperty({'text': dp(46), 'icons': dp(46), 'both': dp(72)}) - - # Tab background color (leave empty for theme color) - tab_color = ListProperty([]) - - # Tab text color in normal state (leave empty for theme color) - tab_text_color = ListProperty([]) - - # Tab text color in active state (leave empty for theme color) - tab_text_color_active = ListProperty([]) - - # Tab indicator color (leave empty for theme color) - tab_indicator_color = ListProperty([]) - - # Tab bar bottom border color (leave empty for theme color) - tab_border_color = ListProperty([]) - - # List of all the tabs so you can dynamically change them - tabs = ListProperty([]) - - # Current tab name - current = StringProperty(None) - - def __init__(self, **kwargs): - super(MDTabbedPanel, self).__init__(**kwargs) - self.previous_tab = None - self.prev_dir = None - self.index = 0 - self._refresh_tabs() - - def on_tab_width_mode(self, *args): - self._refresh_tabs() - - def on_tab_display_mode(self, *args): - self._refresh_tabs() - - def _refresh_tabs(self): - """ Refresh all tabs """ - # if fixed width, use a box layout - if not self.ids: - return - tab_bar = self.ids.tab_bar - tab_bar.clear_widgets() - tab_manager = self.ids.tab_manager - for tab in tab_manager.screens: - tab_header = MDTabHeader(tab=tab, - panel=self, - height=tab_bar.height, - ) - tab_bar.add_widget(tab_header) - - def add_widget(self, widget, **kwargs): - """ Add tabs to the screen or the layout. - :param widget: The widget to add. - """ - d = {} - if isinstance(widget, MDTab): - self.index += 1 - if self.index == 1: - self.previous_tab = widget - widget.index = self.index - widget.parent_widget = self - self.ids.tab_manager.add_widget(widget) - self._refresh_tabs() - else: - super(MDTabbedPanel, self).add_widget(widget) - - def remove_widget(self, widget): - """ Remove tabs from the screen or the layout. - :param widget: The widget to remove. - """ - self.index -= 1 - if isinstance(widget, MDTab): - self.ids.tab_manager.remove_widget(widget) - self._refresh_tabs() - else: - super(MDTabbedPanel, self).remove_widget(widget) - - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class TabsApp(App): - theme_cls = ThemeManager() - - def build(self): - from kivy.core.window import Window - Window.size = (540, 720) - # self.theme_cls.theme_style = 'Dark' - - return Builder.load_string(""" -#:import Toolbar kivymd.toolbar.Toolbar -BoxLayout: - orientation:'vertical' - Toolbar: - id: toolbar - title: 'Page title' - background_color: app.theme_cls.primary_color - left_action_items: [['menu', lambda x: '']] - right_action_items: [['search', lambda x: ''],['more-vert',lambda x:'']] - MDTabbedPanel: - id: tab_mgr - tab_display_mode:'icons' - - MDTab: - name: 'music' - text: "Music" # Why are these not set!!! - icon: "playlist-audio" - MDLabel: - font_style: 'Body1' - theme_text_color: 'Primary' - text: "Here is my music list :)" - halign: 'center' - MDTab: - name: 'movies' - text: 'Movies' - icon: "movie" - - MDLabel: - font_style: 'Body1' - theme_text_color: 'Primary' - text: "Show movies here :)" - halign: 'center' - - -""") - - - TabsApp().run() diff --git a/src/kivymd/textfields.py b/src/kivymd/textfields.py deleted file mode 100644 index 18de10e6..00000000 --- a/src/kivymd/textfields.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.textinput import TextInput -from kivy.properties import ObjectProperty, NumericProperty, StringProperty, \ - ListProperty, BooleanProperty -from kivy.metrics import sp, dp -from kivy.animation import Animation -from kivymd.label import MDLabel -from kivymd.theming import ThemableBehavior -from kivy.clock import Clock - -Builder.load_string(''' -: - canvas.before: - Clear - Color: - rgba: self.line_color_normal - Line: - id: "the_line" - points: self.x, self.y + dp(8), self.x + self.width, self.y + dp(8) - width: 1 - dash_length: dp(3) - dash_offset: 2 if self.disabled else 0 - Color: - rgba: self._current_line_color - Rectangle: - size: self._line_width, dp(2) - pos: self.center_x - (self._line_width / 2), self.y + dp(8) - Color: - rgba: self._current_error_color - Rectangle: - texture: self._msg_lbl.texture - size: self._msg_lbl.texture_size - pos: self.x, self.y - dp(8) - Color: - rgba: (self._current_line_color if self.focus and not self.cursor_blink \ - else (0, 0, 0, 0)) - Rectangle: - pos: [int(x) for x in self.cursor_pos] - size: 1, -self.line_height - Color: - #rgba: self._hint_txt_color if not self.text and not self.focus\ - #else (self.line_color_focus if not self.text or self.focus\ - #else self.line_color_normal) - rgba: self._current_hint_text_color - Rectangle: - texture: self._hint_lbl.texture - size: self._hint_lbl.texture_size - pos: self.x, self.y + self._hint_y - Color: - rgba: self.disabled_foreground_color if self.disabled else \ - (self.hint_text_color if not self.text and not self.focus else \ - self.foreground_color) - - font_name: 'Roboto' - foreground_color: app.theme_cls.text_color - font_size: sp(16) - bold: False - padding: 0, dp(16), 0, dp(10) - multiline: False - size_hint_y: None - height: dp(48) -''') - - -class SingleLineTextField(ThemableBehavior, TextInput): - line_color_normal = ListProperty() - line_color_focus = ListProperty() - error_color = ListProperty() - error = BooleanProperty(False) - message = StringProperty("") - message_mode = StringProperty("none") - mode = message_mode - - _hint_txt_color = ListProperty() - _hint_lbl = ObjectProperty() - _hint_lbl_font_size = NumericProperty(sp(16)) - _hint_y = NumericProperty(dp(10)) - _error_label = ObjectProperty() - _line_width = NumericProperty(0) - _hint_txt = StringProperty('') - _current_line_color = line_color_focus - _current_error_color = ListProperty([0.0, 0.0, 0.0, 0.0]) - _current_hint_text_color = _hint_txt_color - - def __init__(self, **kwargs): - Clock.schedule_interval(self._update_color, 5) - self._msg_lbl = MDLabel(font_style='Caption', - theme_text_color='Error', - halign='left', - valign='middle', - text=self.message) - - self._hint_lbl = MDLabel(font_style='Subhead', - halign='left', - valign='middle') - super(SingleLineTextField, self).__init__(**kwargs) - self.line_color_normal = self.theme_cls.divider_color - self.line_color_focus = list(self.theme_cls.primary_color) - self.base_line_color_focus = list(self.theme_cls.primary_color) - self.error_color = self.theme_cls.error_color - - self._hint_txt_color = self.theme_cls.disabled_hint_text_color - self.hint_text_color = (1, 1, 1, 0) - self.cursor_color = self.theme_cls.primary_color - self.bind(message=self._set_msg, - hint_text=self._set_hint, - _hint_lbl_font_size=self._hint_lbl.setter('font_size'), - message_mode=self._set_mode) - self.hint_anim_in = Animation(_hint_y=dp(34), - _hint_lbl_font_size=sp(12), duration=.2, - t='out_quad') - - self.hint_anim_out = Animation(_hint_y=dp(10), - _hint_lbl_font_size=sp(16), duration=.2, - t='out_quad') - - def _update_color(self, *args): - self.line_color_normal = self.theme_cls.divider_color - self.base_line_color_focus = list(self.theme_cls.primary_color) - if not self.focus and not self.error: - self.line_color_focus = self.theme_cls.primary_color - Animation(duration=.2, _current_hint_text_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.mode == "persistent": - Animation(duration=.1, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.focus and not self.error: - self.cursor_color = self.theme_cls.primary_color - - def on_hint_text_color(self, instance, color): - self._hint_txt_color = self.theme_cls.disabled_hint_text_color - self.hint_text_color = (1, 1, 1, 0) - - def on_width(self, instance, width): - if self.focus and instance is not None or self.error and instance is not None: - self._line_width = width - self.anim = Animation(_line_width=width, duration=.2, t='out_quad') - self._msg_lbl.width = self.width - self._hint_lbl.width = self.width - - def on_pos(self, *args): - self.hint_anim_in = Animation(_hint_y=dp(34), - _hint_lbl_font_size=sp(12), duration=.2, - t='out_quad') - self.hint_anim_out = Animation(_hint_y=dp(10), - _hint_lbl_font_size=sp(16), duration=.2, - t='out_quad') - - def on_focus(self, *args): - if self.focus: - Animation.cancel_all(self, '_line_width', '_hint_y', - '_hint_lbl_font_size') - if len(self.text) == 0: - self.hint_anim_in.start(self) - if self.error: - Animation(duration=.2, _current_hint_text_color=self.error_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=self.error_color).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - else: - pass - elif not self.error: - self.on_width(None, self.width) - self.anim.start(self) - Animation(duration=.2, _current_hint_text_color=self.line_color_focus).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - if self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - else: - pass - else: - Animation.cancel_all(self, '_line_width', '_hint_y', - '_hint_lbl_font_size') - if len(self.text) == 0: - self.hint_anim_out.start(self) - if not self.error: - self.line_color_focus = self.base_line_color_focus - Animation(duration=.2, _current_line_color=self.line_color_focus, - _current_hint_text_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - - self.on_width(None, 0) - self.anim.start(self) - elif self.error: - Animation(duration=.2, _current_line_color=self.error_color, - _current_hint_text_color=self.error_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=self.error_color).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - - def _set_hint(self, instance, text): - self._hint_lbl.text = text - - def _set_msg(self, instance, text): - self._msg_lbl.text = text - self.message = text - - def _set_mode(self, instance, text): - self.mode = text - if self.mode == "persistent": - Animation(duration=.1, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) diff --git a/src/kivymd/theme_picker.py b/src/kivymd/theme_picker.py deleted file mode 100644 index e5104ce6..00000000 --- a/src/kivymd/theme_picker.py +++ /dev/null @@ -1,422 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.boxlayout import BoxLayout -from kivymd.button import MDFlatButton, MDIconButton -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivy.properties import ObjectProperty, ListProperty -from kivymd.label import MDLabel -from kivy.metrics import dp -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors - -Builder.load_string(""" -#:import SingleLineTextField kivymd.textfields.SingleLineTextField -#:import MDTabbedPanel kivymd.tabs.MDTabbedPanel -#:import MDTab kivymd.tabs.MDTab -: - size_hint: (None, None) - size: dp(260), dp(120)+dp(290) - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgb: app.theme_cls.primary_color - Rectangle: - size: dp(260), dp(120) - pos: root.pos[0], root.pos[1] + root.height-dp(120) - Color: - rgb: app.theme_cls.bg_normal - Rectangle: - size: dp(260), dp(290) - pos: root.pos[0], root.pos[1] + root.height-(dp(120)+dp(290)) - - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(10) - text: "Close" - on_release: root.dismiss() - MDLabel: - font_style: "Headline" - text: "Change theme" - size_hint: (None, None) - size: dp(160), dp(50) - pos_hint: {'center_x': 0.5, 'center_y': 0.9} - MDTabbedPanel: - size_hint: (None, None) - size: dp(260), root.height-dp(135) - pos_hint: {'center_x': 0.5, 'center_y': 0.475} - id: tab_panel - tab_display_mode:'text' - - MDTab: - name: 'color' - text: "Theme Color" - BoxLayout: - spacing: dp(4) - size_hint: (None, None) - size: dp(270), root.height # -dp(120) - pos_hint: {'center_x': 0.532, 'center_y': 0.89} - orientation: 'vertical' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': 0.5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Red') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Red' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Pink') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Pink' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Purple') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Purple' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('DeepPurple') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'DeepPurple' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Indigo') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Indigo' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Blue') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Blue' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('LightBlue') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'LightBlue' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Cyan') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Cyan' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Teal') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Teal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Green') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Green' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('LightGreen') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'LightGreen' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Lime') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Lime' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - orientation: 'horizontal' - halign: 'center' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Yellow') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Yellow' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Amber') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Amber' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Orange') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Orange' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('DeepOrange') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'DeepOrange' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - #pos: self.pos - orientation: 'horizontal' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Brown') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Brown' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Grey') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Grey' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - #pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('BlueGrey') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'BlueGrey' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - size_hint: (None, None) - canvas: - Color: - rgba: app.theme_cls.bg_normal - Ellipse: - size: self.size - pos: self.pos - disabled: True - - MDTab: - name: 'style' - text: "Theme Style" - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .3, 'center_y': 0.5} - size: self.size - pos: self.pos - halign: 'center' - spacing: dp(10) - BoxLayout: - halign: 'center' - size_hint: (None, None) - size: dp(100), dp(100) - pos: self.pos - pos_hint: {'center_x': .3, 'center_y': 0.5} - MDIconButton: - size: dp(100), dp(100) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: 1, 1, 1, 1 - Ellipse: - size: self.size - pos: self.pos - Color: - rgba: 0, 0, 0, 1 - Line: - width: 1. - circle: (self.center_x, self.center_y, 50) - on_release: app.theme_cls.theme_style = 'Light' - BoxLayout: - halign: 'center' - size_hint: (None, None) - size: dp(100), dp(100) - MDIconButton: - size: dp(100), dp(100) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: 0, 0, 0, 1 - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.theme_style = 'Dark' -""") - - -class MDThemePicker(ThemableBehavior, FloatLayout, ModalView, ElevationBehavior): - # background_color = ListProperty([0, 0, 0, 0]) - time = ObjectProperty() - - def __init__(self, **kwargs): - super(MDThemePicker, self).__init__(**kwargs) - - def rgb_hex(self, col): - return get_color_from_hex(colors[col][self.theme_cls.accent_hue]) - - -if __name__ == "__main__": - from kivy.app import App - from kivymd.theming import ThemeManager - - class ThemePickerApp(App): - theme_cls = ThemeManager() - - def build(self): - main_widget = Builder.load_string(""" -#:import MDRaisedButton kivymd.button.MDRaisedButton -#:import MDThemePicker kivymd.theme_picker.MDThemePicker -FloatLayout: - MDRaisedButton: - size_hint: None, None - pos_hint: {'center_x': .5, 'center_y': .5} - size: 3 * dp(48), dp(48) - center_x: self.parent.center_x - text: 'Open theme picker' - on_release: MDThemePicker().open() - opposite_colors: True -""") - return main_widget - - ThemePickerApp().run() diff --git a/src/kivymd/theming.py b/src/kivymd/theming.py deleted file mode 100644 index 3172ee58..00000000 --- a/src/kivymd/theming.py +++ /dev/null @@ -1,350 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.app import App -from kivy.core.text import LabelBase -from kivy.core.window import Window -from kivy.clock import Clock -from kivy.metrics import dp -from kivy.properties import OptionProperty, AliasProperty, ObjectProperty, \ - StringProperty, ListProperty, BooleanProperty -from kivy.uix.widget import Widget -from kivy.utils import get_color_from_hex -from kivy.atlas import Atlas -from kivymd.color_definitions import colors -from kivymd.material_resources import FONTS, DEVICE_TYPE -from kivymd import images_path - -for font in FONTS: - LabelBase.register(**font) - - -class ThemeManager(Widget): - primary_palette = OptionProperty( - 'Blue', - options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown', - 'LightBlue', - 'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange', - 'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber', - 'DeepPurple', 'Lime']) - - primary_hue = OptionProperty( - '500', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - primary_light_hue = OptionProperty( - '200', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - primary_dark_hue = OptionProperty( - '700', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - def _get_primary_color(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_hue]) - - primary_color = AliasProperty(_get_primary_color, - bind=('primary_palette', 'primary_hue')) - - def _get_primary_light(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_light_hue]) - - primary_light = AliasProperty( - _get_primary_light, bind=('primary_palette', 'primary_light_hue')) - - def _get_primary_dark(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_dark_hue]) - - primary_dark = AliasProperty(_get_primary_dark, - bind=('primary_palette', 'primary_dark_hue')) - - accent_palette = OptionProperty( - 'Amber', - options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown', - 'LightBlue', - 'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange', - 'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber', - 'DeepPurple', 'Lime']) - - accent_hue = OptionProperty( - '500', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - accent_light_hue = OptionProperty( - '200', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - accent_dark_hue = OptionProperty( - '700', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - def _get_accent_color(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_hue]) - - accent_color = AliasProperty(_get_accent_color, - bind=['accent_palette', 'accent_hue']) - - def _get_accent_light(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_light_hue]) - - accent_light = AliasProperty(_get_accent_light, - bind=['accent_palette', 'accent_light_hue']) - - def _get_accent_dark(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_dark_hue]) - - accent_dark = AliasProperty(_get_accent_dark, - bind=['accent_palette', 'accent_dark_hue']) - - theme_style = OptionProperty('Light', options=['Light', 'Dark']) - - def _get_theme_style(self, opposite): - if opposite: - return 'Light' if self.theme_style == 'Dark' else 'Dark' - else: - return self.theme_style - - def _get_bg_darkest(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['StatusBar']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['StatusBar']) - - bg_darkest = AliasProperty(_get_bg_darkest, bind=['theme_style']) - - def _get_op_bg_darkest(self): - return self._get_bg_darkest(True) - - opposite_bg_darkest = AliasProperty(_get_op_bg_darkest, - bind=['theme_style']) - - def _get_bg_dark(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['AppBar']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['AppBar']) - - bg_dark = AliasProperty(_get_bg_dark, bind=['theme_style']) - - def _get_op_bg_dark(self): - return self._get_bg_dark(True) - - opposite_bg_dark = AliasProperty(_get_op_bg_dark, bind=['theme_style']) - - def _get_bg_normal(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['Background']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['Background']) - - bg_normal = AliasProperty(_get_bg_normal, bind=['theme_style']) - - def _get_op_bg_normal(self): - return self._get_bg_normal(True) - - opposite_bg_normal = AliasProperty(_get_op_bg_normal, bind=['theme_style']) - - def _get_bg_light(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['CardsDialogs']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['CardsDialogs']) - - bg_light = AliasProperty(_get_bg_light, bind=['theme_style']) - - def _get_op_bg_light(self): - return self._get_bg_light(True) - - opposite_bg_light = AliasProperty(_get_op_bg_light, bind=['theme_style']) - - def _get_divider_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .12 - return color - - divider_color = AliasProperty(_get_divider_color, bind=['theme_style']) - - def _get_op_divider_color(self): - return self._get_divider_color(True) - - opposite_divider_color = AliasProperty(_get_op_divider_color, - bind=['theme_style']) - - def _get_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .87 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - return color - - text_color = AliasProperty(_get_text_color, bind=['theme_style']) - - def _get_op_text_color(self): - return self._get_text_color(True) - - opposite_text_color = AliasProperty(_get_op_text_color, - bind=['theme_style']) - - def _get_secondary_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .54 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .70 - return color - - secondary_text_color = AliasProperty(_get_secondary_text_color, - bind=['theme_style']) - - def _get_op_secondary_text_color(self): - return self._get_secondary_text_color(True) - - opposite_secondary_text_color = AliasProperty(_get_op_secondary_text_color, - bind=['theme_style']) - - def _get_icon_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .54 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - return color - - icon_color = AliasProperty(_get_icon_color, - bind=['theme_style']) - - def _get_op_icon_color(self): - return self._get_icon_color(True) - - opposite_icon_color = AliasProperty(_get_op_icon_color, - bind=['theme_style']) - - def _get_disabled_hint_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .26 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .30 - return color - - disabled_hint_text_color = AliasProperty(_get_disabled_hint_text_color, - bind=['theme_style']) - - def _get_op_disabled_hint_text_color(self): - return self._get_disabled_hint_text_color(True) - - opposite_disabled_hint_text_color = AliasProperty( - _get_op_disabled_hint_text_color, bind=['theme_style']) - - # Hardcoded because muh standard - def _get_error_color(self): - return get_color_from_hex(colors['Red']['A700']) - - error_color = AliasProperty(_get_error_color) - - def _get_ripple_color(self): - return self._ripple_color - - def _set_ripple_color(self, value): - self._ripple_color = value - - _ripple_color = ListProperty(get_color_from_hex(colors['Grey']['400'])) - ripple_color = AliasProperty(_get_ripple_color, - _set_ripple_color, - bind=['_ripple_color']) - - def _determine_device_orientation(self, _, window_size): - if window_size[0] > window_size[1]: - self.device_orientation = 'landscape' - elif window_size[1] >= window_size[0]: - self.device_orientation = 'portrait' - - device_orientation = StringProperty('') - - def _get_standard_increment(self): - if DEVICE_TYPE == 'mobile': - if self.device_orientation == 'landscape': - return dp(48) - else: - return dp(56) - else: - return dp(64) - - standard_increment = AliasProperty(_get_standard_increment, - bind=['device_orientation']) - - def _get_horizontal_margins(self): - if DEVICE_TYPE == 'mobile': - return dp(16) - else: - return dp(24) - - horizontal_margins = AliasProperty(_get_horizontal_margins) - - def on_theme_style(self, instance, value): - if hasattr(App.get_running_app(), 'theme_cls') and \ - App.get_running_app().theme_cls == self: - self.set_clearcolor_by_theme_style(value) - - def set_clearcolor_by_theme_style(self, theme_style): - if theme_style == 'Light': - Window.clearcolor = get_color_from_hex( - colors['Light']['Background']) - elif theme_style == 'Dark': - Window.clearcolor = get_color_from_hex( - colors['Dark']['Background']) - - def __init__(self, **kwargs): - super(ThemeManager, self).__init__(**kwargs) - self.rec_shadow = Atlas('{}rec_shadow.atlas'.format(images_path)) - self.rec_st_shadow = Atlas('{}rec_st_shadow.atlas'.format(images_path)) - self.quad_shadow = Atlas('{}quad_shadow.atlas'.format(images_path)) - self.round_shadow = Atlas('{}round_shadow.atlas'.format(images_path)) - Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style)) - self._determine_device_orientation(None, Window.size) - Window.bind(size=self._determine_device_orientation) - - -class ThemableBehavior(object): - theme_cls = ObjectProperty(None) - opposite_colors = BooleanProperty(False) - - def __init__(self, **kwargs): - if self.theme_cls is not None: - pass - elif hasattr(App.get_running_app(), 'theme_cls'): - self.theme_cls = App.get_running_app().theme_cls - else: - self.theme_cls = ThemeManager() - super(ThemableBehavior, self).__init__(**kwargs) diff --git a/src/kivymd/time_picker.py b/src/kivymd/time_picker.py deleted file mode 100644 index 6de6fc20..00000000 --- a/src/kivymd/time_picker.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivy.uix.floatlayout import FloatLayout -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivy.properties import ObjectProperty, ListProperty - -Builder.load_string(""" -#:import MDFlatButton kivymd.button.MDFlatButton -#:import CircularTimePicker kivymd.vendor.circularTimePicker.CircularTimePicker -#:import dp kivy.metrics.dp -: - size_hint: (None, None) - size: [dp(270), dp(335)+dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(520), dp(325)] - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgba: self.theme_cls.bg_light - Rectangle: - size: [dp(270), dp(335)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(250), root.height] - pos: [root.pos[0], root.pos[1] + root.height - dp(335) - dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [root.pos[0]+dp(270), root.pos[1]] - Color: - rgba: self.theme_cls.primary_color - Rectangle: - size: [dp(270), dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(270), root.height] - pos: [root.pos[0], root.pos[1] + root.height - dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [root.pos[0], root.pos[1]] - Color: - rgba: self.theme_cls.bg_dark - Ellipse: - size: [dp(220), dp(220)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(195), dp(195)] - pos: root.pos[0]+dp(270)/2-dp(220)/2, root.pos[1] + root.height - (dp(335)/2+dp(95)) - dp(220)/2 + dp(35) - #Color: - #rgba: (1, 0, 0, 1) - #Line: - #width: 4 - #points: dp(270)/2, root.height, dp(270)/2, 0 - CircularTimePicker: - id: time_picker - pos: (dp(270)/2)-(self.width/2), root.height-self.height - size_hint: [.8, .8] - #if root.theme_cls.device_orientation == 'portrait' else [0.35, 0.9] - pos_hint: {'center_x': 0.5, 'center_y': 0.585} - #if root.theme_cls.device_orientation == 'portrait' else {'center_x': 0.75, 'center_y': 0.7} - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72)*2, root.pos[1] + dp(10) - text: "Cancel" - on_release: root.close_cancel() - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(10) - text: "OK" - on_release: root.close_ok() -""") - - -class MDTimePicker(ThemableBehavior, FloatLayout, ModalView, ElevationBehavior): - # background_color = ListProperty((0, 0, 0, 0)) - time = ObjectProperty() - - def __init__(self, **kwargs): - super(MDTimePicker, self).__init__(**kwargs) - self.current_time = self.ids.time_picker.time - - def set_time(self, time): - try: - self.ids.time_picker.set_time(time) - except AttributeError: - raise TypeError("MDTimePicker._set_time must receive a datetime object, not a \"" + - type(time).__name__ + "\"") - - def close_cancel(self): - self.dismiss() - - def close_ok(self): - self.current_time = self.ids.time_picker.time - self.time = self.current_time - self.dismiss() diff --git a/src/kivymd/toolbar.py b/src/kivymd/toolbar.py deleted file mode 100644 index fc7b146c..00000000 --- a/src/kivymd/toolbar.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ListProperty, StringProperty, OptionProperty -from kivy.uix.boxlayout import BoxLayout -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.button import MDIconButton -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior - -Builder.load_string(''' -#:import m_res kivymd.material_resources - - size_hint_y: None - height: root.theme_cls.standard_increment - background_color: root.background_color - padding: [root.theme_cls.horizontal_margins - dp(12), 0] - opposite_colors: True - elevation: 6 - BoxLayout: - id: left_actions - orientation: 'horizontal' - size_hint_x: None - padding: [0, (self.height - dp(48))/2] - BoxLayout: - padding: dp(12), 0 - MDLabel: - font_style: 'Title' - opposite_colors: root.opposite_colors - theme_text_color: root.title_theme_color - text_color: root.title_color - text: root.title - shorten: True - shorten_from: 'right' - BoxLayout: - id: right_actions - orientation: 'horizontal' - size_hint_x: None - padding: [0, (self.height - dp(48))/2] -''') - - -class Toolbar(ThemableBehavior, ElevationBehavior, BackgroundColorBehavior, - BoxLayout): - left_action_items = ListProperty() - """The icons on the left of the Toolbar. - - To add one, append a list like the following: - - ['icon_name', callback] - - where 'icon_name' is a string that corresponds to an icon definition and - callback is the function called on a touch release event. - """ - - right_action_items = ListProperty() - """The icons on the left of the Toolbar. - - Works the same way as :attr:`left_action_items` - """ - - title = StringProperty() - """The text displayed on the Toolbar.""" - - title_theme_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - - title_color = ListProperty(None, allownone=True) - - background_color = ListProperty([0, 0, 0, 1]) - - def __init__(self, **kwargs): - super(Toolbar, self).__init__(**kwargs) - Clock.schedule_once( - lambda x: self.on_left_action_items(0, self.left_action_items)) - Clock.schedule_once( - lambda x: self.on_right_action_items(0, - self.right_action_items)) - - def on_left_action_items(self, instance, value): - self.update_action_bar(self.ids['left_actions'], value) - - def on_right_action_items(self, instance, value): - self.update_action_bar(self.ids['right_actions'], value) - - def update_action_bar(self, action_bar, action_bar_items): - action_bar.clear_widgets() - new_width = 0 - for item in action_bar_items: - new_width += dp(48) - action_bar.add_widget(MDIconButton(icon=item[0], - on_release=item[1], - opposite_colors=True, - text_color=self.title_color, - theme_text_color=self.title_theme_color)) - action_bar.width = new_width diff --git a/src/kivymd/vendor/__init__.py b/src/kivymd/vendor/__init__.py deleted file mode 100644 index 9bad5790..00000000 --- a/src/kivymd/vendor/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/src/kivymd/vendor/circleLayout/LICENSE b/src/kivymd/vendor/circleLayout/LICENSE deleted file mode 100644 index 9d6e5b59..00000000 --- a/src/kivymd/vendor/circleLayout/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Davide Depau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/src/kivymd/vendor/circleLayout/README.md b/src/kivymd/vendor/circleLayout/README.md deleted file mode 100644 index 6cf54bbe..00000000 --- a/src/kivymd/vendor/circleLayout/README.md +++ /dev/null @@ -1,21 +0,0 @@ -CircularLayout -============== - -CircularLayout is a special layout that places widgets around a circle. - -See the widget's documentation and the example for more information. - -![Screenshot](screenshot.png) - -size_hint ---------- - -size_hint_x is used as an angle-quota hint (widget with higher -size_hint_x will be farther from each other, and viceversa), while -size_hint_y is used as a widget size hint (widgets with a higher size -hint will be bigger).size_hint_x cannot be None. - -Widgets are all squares, unless you set size_hint_y to None (in that -case you'll be able to specify your own size), and their size is the -difference between the outer and the inner circle's radii. To make the -widgets bigger you can just decrease inner_radius_hint. \ No newline at end of file diff --git a/src/kivymd/vendor/circleLayout/__init__.py b/src/kivymd/vendor/circleLayout/__init__.py deleted file mode 100644 index 9d62c99c..00000000 --- a/src/kivymd/vendor/circleLayout/__init__.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -CircularLayout -============== - -CircularLayout is a special layout that places widgets around a circle. - -size_hint ---------- - -size_hint_x is used as an angle-quota hint (widget with higher -size_hint_x will be farther from each other, and vice versa), while -size_hint_y is used as a widget size hint (widgets with a higher size -hint will be bigger).size_hint_x cannot be None. - -Widgets are all squares, unless you set size_hint_y to None (in that -case you'll be able to specify your own size), and their size is the -difference between the outer and the inner circle's radii. To make the -widgets bigger you can just decrease inner_radius_hint. -""" - -from kivy.uix.layout import Layout -from kivy.properties import NumericProperty, ReferenceListProperty, OptionProperty, \ - BoundedNumericProperty, VariableListProperty, AliasProperty -from math import sin, cos, pi, radians - -__all__ = ('CircularLayout') - -try: - xrange(1, 2) -except NameError: - def xrange(first, second, third=None): - if third: - return range(first, second, third) - else: - return range(first, second) - - -class CircularLayout(Layout): - ''' - Circular layout class. See module documentation for more information. - ''' - - padding = VariableListProperty([0, 0, 0, 0]) - '''Padding between the layout box and it's children: [padding_left, - padding_top, padding_right, padding_bottom]. - - padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. - - .. version changed:: 1.7.0 - Replaced NumericProperty with VariableListProperty. - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and - defaults to [0, 0, 0, 0]. - ''' - - start_angle = NumericProperty(0) - '''Angle (in degrees) at which the first widget will be placed. - Start counting angles from the X axis, going counterclockwise. - - :attr:`start_angle` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0 (start from the right). - ''' - - circle_quota = BoundedNumericProperty(360, min=0, max=360) - '''Size (in degrees) of the part of the circumference that will actually - be used to place widgets. - - :attr:`circle_quota` is a :class:`~kivy.properties.BoundedNumericProperty` - and defaults to 360 (all the circumference). - ''' - - direction = OptionProperty("ccw", options=("cw", "ccw")) - '''Direction of widgets in the circle. - - :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and - defaults to 'ccw'. Can be 'ccw' (counterclockwise) or 'cw' (clockwise). - ''' - - outer_radius_hint = NumericProperty(1) - '''Sets the size of the outer circle. A number greater than 1 will make the - widgets larger than the actual widget, a number smaller than 1 will leave - a gap. - - :attr:`outer_radius_hint` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - ''' - - inner_radius_hint = NumericProperty(.6) - '''Sets the size of the inner circle. A number greater than - :attr:`outer_radius_hint` will cause glitches. The closest it is to - :attr:`outer_radius_hint`, the smallest will be the widget in the layout. - - :attr:`outer_radius_hint` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - ''' - - radius_hint = ReferenceListProperty(inner_radius_hint, outer_radius_hint) - '''Combined :attr:`outer_radius_hint` and :attr:`inner_radius_hint` in a list - for convenience. See their documentation for more details. - - :attr:`radius_hint` is a :class:`~kivy.properties.ReferenceListProperty`. - ''' - - def _get_delta_radii(self): - radius = min(self.width-self.padding[0]-self.padding[2], self.height-self.padding[1]-self.padding[3]) / 2. - outer_r = radius * self.outer_radius_hint - inner_r = radius * self.inner_radius_hint - return outer_r - inner_r - delta_radii = AliasProperty(_get_delta_radii, None, bind=("radius_hint", "padding", "size")) - - def __init__(self, **kwargs): - super(CircularLayout, self).__init__(**kwargs) - - self.bind( - start_angle=self._trigger_layout, - parent=self._trigger_layout, - # padding=self._trigger_layout, - children=self._trigger_layout, - size=self._trigger_layout, - radius_hint=self._trigger_layout, - pos=self._trigger_layout) - - def do_layout(self, *largs): - # optimize layout by preventing looking at the same attribute in a loop - len_children = len(self.children) - if len_children == 0: - return - selfcx = self.center_x - selfcy = self.center_y - direction = self.direction - cquota = radians(self.circle_quota) - start_angle_r = radians(self.start_angle) - padding_left = self.padding[0] - padding_top = self.padding[1] - padding_right = self.padding[2] - padding_bottom = self.padding[3] - padding_x = padding_left + padding_right - padding_y = padding_top + padding_bottom - - radius = min(self.width-padding_x, self.height-padding_y) / 2. - outer_r = radius * self.outer_radius_hint - inner_r = radius * self.inner_radius_hint - middle_r = radius * sum(self.radius_hint) / 2. - delta_r = outer_r - inner_r - - stretch_weight_angle = 0. - for w in self.children: - sha = w.size_hint_x - if sha is None: - raise ValueError("size_hint_x cannot be None in a CircularLayout") - else: - stretch_weight_angle += sha - - sign = +1. - angle_offset = start_angle_r - if direction == 'cw': - angle_offset = 2 * pi - start_angle_r - sign = -1. - - for c in reversed(self.children): - sha = c.size_hint_x - shs = c.size_hint_y - - angle_quota = cquota / stretch_weight_angle * sha - angle = angle_offset + (sign * angle_quota / 2) - angle_offset += sign * angle_quota - - # kived: looking it up, yes. x = cos(angle) * radius + centerx; y = sin(angle) * radius + centery - ccx = cos(angle) * middle_r + selfcx + padding_left - padding_right - ccy = sin(angle) * middle_r + selfcy + padding_bottom - padding_top - - c.center_x = ccx - c.center_y = ccy - if shs: - s = delta_r * shs - c.width = s - c.height = s - -if __name__ == "__main__": - from kivy.app import App - from kivy.uix.button import Button - - class CircLayoutApp(App): - def build(self): - cly = CircularLayout(direction="cw", start_angle=-75, inner_radius_hint=.7, padding="20dp") - - for i in xrange(1, 13): - cly.add_widget(Button(text=str(i), font_size="30dp")) - - return cly - - CircLayoutApp().run() diff --git a/src/kivymd/vendor/circularTimePicker/LICENSE b/src/kivymd/vendor/circularTimePicker/LICENSE deleted file mode 100644 index 9d6e5b59..00000000 --- a/src/kivymd/vendor/circularTimePicker/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Davide Depau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/src/kivymd/vendor/circularTimePicker/README.md b/src/kivymd/vendor/circularTimePicker/README.md deleted file mode 100644 index 20ac2de9..00000000 --- a/src/kivymd/vendor/circularTimePicker/README.md +++ /dev/null @@ -1,43 +0,0 @@ -Circular Date & Time Picker for Kivy -==================================== - -(currently only time, date coming soon) - -Based on [CircularLayout](https://github.com/kivy-garden/garden.circularlayout). -The main aim is to provide a date and time selector similar to the -one found in Android KitKat+. - -![Screenshot](screenshot.png) - -Simple usage ------------- - -Import the widget with - -```python -from kivy.garden.circulardatetimepicker import CircularTimePicker -``` - -then use it! That's it! - -```python -c = CircularTimePicker() -c.bind(time=self.set_time) -root.add_widget(c) -``` - -in Kv language: - -``` -: - BoxLayout: - orientation: "vertical" - - CircularTimePicker - - Button: - text: "Dismiss" - size_hint_y: None - height: "40dp" - on_release: root.dismiss() -``` \ No newline at end of file diff --git a/src/kivymd/vendor/circularTimePicker/__init__.py b/src/kivymd/vendor/circularTimePicker/__init__.py deleted file mode 100644 index fbc73954..00000000 --- a/src/kivymd/vendor/circularTimePicker/__init__.py +++ /dev/null @@ -1,770 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -Circular Date & Time Picker for Kivy -==================================== - -(currently only time, date coming soon) - -Based on [CircularLayout](https://github.com/kivy-garden/garden.circularlayout). -The main aim is to provide a date and time selector similar to the -one found in Android KitKat+. - -Simple usage ------------- - -Import the widget with - -```python -from kivy.garden.circulardatetimepicker import CircularTimePicker -``` - -then use it! That's it! - -```python -c = CircularTimePicker() -c.bind(time=self.set_time) -root.add_widget(c) -``` - -in Kv language: - -``` -: - BoxLayout: - orientation: "vertical" - - CircularTimePicker - - Button: - text: "Dismiss" - size_hint_y: None - height: "40dp" - on_release: root.dismiss() -``` -""" - -from kivy.animation import Animation -from kivy.clock import Clock -from kivymd.vendor.circleLayout import CircularLayout -from kivy.graphics import Line, Color, Ellipse -from kivy.lang import Builder -from kivy.properties import NumericProperty, BoundedNumericProperty, \ - ObjectProperty, StringProperty, DictProperty, \ - ListProperty, OptionProperty, BooleanProperty, \ - ReferenceListProperty, AliasProperty -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.label import Label -from kivy.metrics import dp -from kivymd.theming import ThemableBehavior -from math import atan, pi, radians, sin, cos -import sys -import datetime -if sys.version_info[0] > 2: - def xrange(first=None, second=None, third=None): - if third: - return range(first, second, third) - else: - return range(first, second) - - -def map_number(x, in_min, in_max, out_min, out_max): - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min - - -def rgb_to_hex(*color): - tor = "#" - for col in color: - tor += "{:>02}".format(hex(int(col * 255))[2:]) - return tor - - -Builder.load_string(""" - -: - text_size: self.size - valign: "middle" - halign: "center" - font_size: self.height * self.size_factor - -: - canvas.before: - PushMatrix - Scale: - origin: self.center_x + self.padding[0] - self.padding[2], self.center_y + self.padding[3] - self.padding[1] - x: self.scale - y: self.scale - - canvas.after: - PopMatrix - -: - orientation: "vertical" - spacing: "20dp" - - FloatLayout: - anchor_x: "center" - anchor_y: "center" - size_hint_y: 1./3 - size_hint_x: 1 - size: root.size - pos: root.pos - - GridLayout: - cols: 2 - spacing: "10dp" - size_hint_x: None - width: self.minimum_width - pos_hint: {'center_x': .5, 'center_y': .5} - - Label: - id: timelabel - text: root.time_text - markup: True - halign: "right" - valign: "middle" - # text_size: self.size - size_hint_x: None #.6 - width: self.texture_size[0] - font_size: self.height * .75 - - Label: - id: ampmlabel - text: root.ampm_text - markup: True - halign: "left" - valign: "middle" - # text_size: self.size - size_hint_x: None #.4 - width: self.texture_size[0] - font_size: self.height * .3 - - FloatLayout: - id: picker_container - #size_hint_y: 2./3 - _bound: {} -""") - - -class Number(Label): - """The class used to show the numbers in the selector. - """ - - size_factor = NumericProperty(.5) - """Font size scale. - - :attr:`size_factor` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0.5. - """ - - -class CircularNumberPicker(CircularLayout): - """A circular number picker based on CircularLayout. A selector will - help you pick a number. You can also set :attr:`multiples_of` to make - it show only some numbers and use the space in between for the other - numbers. - """ - - min = NumericProperty(0) - """The first value of the range. - - :attr:`min` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - max = NumericProperty(0) - """The last value of the range. Note that it behaves like xrange, so - the actual last displayed value will be :attr:`max` - 1. - - :attr:`max` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - range = ReferenceListProperty(min, max) - """Packs :attr:`min` and :attr:`max` into a list for convenience. See - their documentation for further information. - - :attr:`range` is a :class:`~kivy.properties.ReferenceListProperty`. - """ - - multiples_of = NumericProperty(1) - """Only show numbers that are multiples of this number. The other numbers - will be selectable, but won't have their own label. - - :attr:`multiples_of` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - """ - - # selector_color = ListProperty([.337, .439, .490]) - selector_color = ListProperty([1, 1, 1]) - """Color of the number selector. RGB. - - :attr:`selector_color` is a :class:`~kivy.properties.ListProperty` and - defaults to [.337, .439, .490] (material green). - """ - - color = ListProperty([0, 0, 0]) - """Color of the number labels and of the center dot. RGB. - - :attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to [1, 1, 1] (white). - """ - - selector_alpha = BoundedNumericProperty(.3, min=0, max=1) - """Alpha value for the transparent parts of the selector. - - :attr:`selector_alpha` is a :class:`~kivy.properties.BoundedNumericProperty` and - defaults to 0.3 (min=0, max=1). - """ - - selected = NumericProperty(None) - """Currently selected number. - - :attr:`selected` is a :class:`~kivy.properties.NumericProperty` and - defaults to :attr:`min`. - """ - - number_size_factor = NumericProperty(.5) - """Font size scale factor fot the :class:`Number`s. - - :attr:`number_size_factor` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0.5. - """ - - number_format_string = StringProperty("{}") - """String that will be formatted with the selected number as the first argument. - Can be anything supported by :meth:`str.format` (es. "{:02d}"). - - :attr:`number_format_string` is a :class:`~kivy.properties.StringProperty` and - defaults to "{}". - """ - - scale = NumericProperty(1) - """Canvas scale factor. Used in :class:`CircularTimePicker` transitions. - - :attr:`scale` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - """ - - _selection_circle = ObjectProperty(None) - _selection_line = ObjectProperty(None) - _selection_dot = ObjectProperty(None) - _selection_dot_color = ObjectProperty(None) - _selection_color = ObjectProperty(None) - _center_dot = ObjectProperty(None) - _center_color = ObjectProperty(None) - - def _get_items(self): - return self.max - self.min - - items = AliasProperty(_get_items, None) - - def _get_shown_items(self): - sh = 0 - for i in xrange(*self.range): - if i % self.multiples_of == 0: - sh += 1 - return sh - - shown_items = AliasProperty(_get_shown_items, None) - - def __init__(self, **kw): - self._trigger_genitems = Clock.create_trigger(self._genitems, -1) - self.bind(min=self._trigger_genitems, - max=self._trigger_genitems, - multiples_of=self._trigger_genitems) - super(CircularNumberPicker, self).__init__(**kw) - self.selected = self.min - self.bind(selected=self.on_selected, - pos=self.on_selected, - size=self.on_selected) - - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sx, sy = self.pos_for_number(self.selected) - epos = [i - (self.delta_radii * self.number_size_factor) for i in (sx, sy)] - esize = [self.delta_radii * self.number_size_factor * 2] * 2 - dsize = [i * .3 for i in esize] - dpos = [i + esize[0] / 2. - dsize[0] / 2. for i in epos] - csize = [i * .05 for i in esize] - cpos = [i - csize[0] / 2. for i in (cx, cy)] - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - color = list(self.selector_color) - - with self.canvas: - self._selection_color = Color(*(color + [self.selector_alpha])) - self._selection_circle = Ellipse(pos=epos, size=esize) - self._selection_line = Line(points=[cx, cy, sx, sy], width=dp(1.25)) - self._selection_dot_color = Color(*(color + [dot_alpha])) - self._selection_dot = Ellipse(pos=dpos, size=dsize) - self._center_color = Color(*self.color) - self._center_dot = Ellipse(pos=cpos, size=csize) - - self.bind(selector_color=lambda ign, u: setattr(self._selection_color, "rgba", u + [self.selector_alpha])) - self.bind(selector_color=lambda ign, u: setattr(self._selection_dot_color, "rgb", u)) - self.bind(selector_color=lambda ign, u: self.dot_is_none()) - self.bind(color=lambda ign, u: setattr(self._center_color, "rgb", u)) - Clock.schedule_once(self._genitems) - Clock.schedule_once(self.on_selected) # Just to make sure pos/size are set - - def dot_is_none(self, *args): - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - if self._selection_dot_color: - self._selection_dot_color.a = dot_alpha - - def _genitems(self, *a): - self.clear_widgets() - for i in xrange(*self.range): - if i % self.multiples_of != 0: - continue - n = Number(text=self.number_format_string.format(i), size_factor=self.number_size_factor, color=self.color) - self.bind(color=n.setter("color")) - self.add_widget(n) - - def on_touch_down(self, touch): - if not self.collide_point(*touch.pos): - return - touch.grab(self) - self.selected = self.number_at_pos(*touch.pos) - if self.selected == 60: - self.selected = 0 - - def on_touch_move(self, touch): - if touch.grab_current is not self: - return super(CircularNumberPicker, self).on_touch_move(touch) - self.selected = self.number_at_pos(*touch.pos) - if self.selected == 60: - self.selected = 0 - - def on_touch_up(self, touch): - if touch.grab_current is not self: - return super(CircularNumberPicker, self).on_touch_up(touch) - touch.ungrab(self) - - def on_selected(self, *a): - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sx, sy = self.pos_for_number(self.selected) - epos = [i - (self.delta_radii * self.number_size_factor) for i in (sx, sy)] - esize = [self.delta_radii * self.number_size_factor * 2] * 2 - dsize = [i * .3 for i in esize] - dpos = [i + esize[0] / 2. - dsize[0] / 2. for i in epos] - csize = [i * .05 for i in esize] - cpos = [i - csize[0] / 2. for i in (cx, cy)] - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - - if self._selection_circle: - self._selection_circle.pos = epos - self._selection_circle.size = esize - if self._selection_line: - self._selection_line.points = [cx, cy, sx, sy] - if self._selection_dot: - self._selection_dot.pos = dpos - self._selection_dot.size = dsize - if self._selection_dot_color: - self._selection_dot_color.a = dot_alpha - if self._center_dot: - self._center_dot.pos = cpos - self._center_dot.size = csize - - def pos_for_number(self, n): - """Returns the center x, y coordinates for a given number. - """ - - if self.items == 0: - return 0, 0 - radius = min(self.width - self.padding[0] - self.padding[2], - self.height - self.padding[1] - self.padding[3]) / 2. - middle_r = radius * sum(self.radius_hint) / 2. - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sign = +1. - angle_offset = radians(self.start_angle) - if self.direction == 'cw': - angle_offset = 2 * pi - angle_offset - sign = -1. - quota = 2 * pi / self.items - mult_quota = 2 * pi / self.shown_items - angle = angle_offset + n * sign * quota - - if self.items == self.shown_items: - angle += quota / 2 - else: - angle -= mult_quota / 2 - - # kived: looking it up, yes. x = cos(angle) * radius + centerx; y = sin(angle) * radius + centery - x = cos(angle) * middle_r + cx - y = sin(angle) * middle_r + cy - - return x, y - - def number_at_pos(self, x, y): - """Returns the number at a given x, y position. The number is found - using the widget's center as a starting point for angle calculations. - - Not thoroughly tested, may yield wrong results. - """ - if self.items == 0: - return self.min - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - lx = x - cx - ly = y - cy - quota = 2 * pi / self.items - mult_quota = 2 * pi / self.shown_items - if lx == 0 and ly > 0: - angle = pi / 2 - elif lx == 0 and ly < 0: - angle = 3 * pi / 2 - else: - angle = atan(ly / lx) - if lx < 0 < ly: - angle += pi - if lx > 0 > ly: - angle += 2 * pi - if lx < 0 and ly < 0: - angle += pi - angle += radians(self.start_angle) - if self.direction == "cw": - angle = 2 * pi - angle - if mult_quota != quota: - angle -= mult_quota / 2 - if angle < 0: - angle += 2 * pi - elif angle > 2 * pi: - angle -= 2 * pi - - return int(angle / quota) + self.min - - -class CircularMinutePicker(CircularNumberPicker): - """:class:`CircularNumberPicker` implementation for minutes. - """ - - def __init__(self, **kw): - super(CircularMinutePicker, self).__init__(**kw) - self.min = 0 - self.max = 60 - self.multiples_of = 5 - self.number_format_string = "{:02d}" - self.direction = "cw" - self.bind(shown_items=self._update_start_angle) - Clock.schedule_once(self._update_start_angle) - Clock.schedule_once(self.on_selected) - - def _update_start_angle(self, *a): - self.start_angle = -(360. / self.shown_items / 2) - 90 - - -class CircularHourPicker(CircularNumberPicker): - """:class:`CircularNumberPicker` implementation for hours. - """ - - # military = BooleanProperty(False) - - def __init__(self, **kw): - super(CircularHourPicker, self).__init__(**kw) - self.min = 1 - self.max = 13 - # 25 if self.military else 13 - # self.inner_radius_hint = .8 if self.military else .6 - self.multiples_of = 1 - self.number_format_string = "{}" - self.direction = "cw" - self.bind(shown_items=self._update_start_angle) - # self.bind(military=lambda v: setattr(self, "max", 25 if v else 13)) - # self.bind(military=lambda v: setattr(self, "inner_radius_hint", .8 if self.military else .6)) - # Clock.schedule_once(self._genitems) - Clock.schedule_once(self._update_start_angle) - Clock.schedule_once(self.on_selected) - - def _update_start_angle(self, *a): - self.start_angle = (360. / self.shown_items / 2) - 90 - - -class CircularTimePicker(BoxLayout, ThemableBehavior): - """Widget that makes use of :class:`CircularHourPicker` and - :class:`CircularMinutePicker` to create a user-friendly, animated - time picker like the one seen on Android. - - See module documentation for more details. - """ - - primary_dark = ListProperty([1, 1, 1]) - - hours = NumericProperty(0) - """The hours, in military format (0-23). - - :attr:`hours` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0 (12am). - """ - - minutes = NumericProperty(0) - """The minutes. - - :attr:`minutes` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - time_list = ReferenceListProperty(hours, minutes) - """Packs :attr:`hours` and :attr:`minutes` in a list for convenience. - - :attr:`time_list` is a :class:`~kivy.properties.ReferenceListProperty`. - """ - - # military = BooleanProperty(False) - time_format = StringProperty( - "[color={hours_color}][ref=hours]{hours}[/ref][/color][color={primary_dark}][ref=colon]:[/ref][/color]\ -[color={minutes_color}][ref=minutes]{minutes:02d}[/ref][/color]") - """String that will be formatted with the time and shown in the time label. - Can be anything supported by :meth:`str.format`. Make sure you don't - remove the refs. See the default for the arguments passed to format. - :attr:`time_format` is a :class:`~kivy.properties.StringProperty` and - defaults to "[color={hours_color}][ref=hours]{hours}[/ref][/color]:[color={minutes_color}][ref=minutes]\ - {minutes:02d}[/ref][/color]". - """ - - ampm_format = StringProperty( - "[color={am_color}][ref=am]AM[/ref][/color]\n[color={pm_color}][ref=pm]PM[/ref][/color]") - """String that will be formatted and shown in the AM/PM label. - Can be anything supported by :meth:`str.format`. Make sure you don't - remove the refs. See the default for the arguments passed to format. - - :attr:`ampm_format` is a :class:`~kivy.properties.StringProperty` and - defaults to "[color={am_color}][ref=am]AM[/ref][/color]\n[color={pm_color}][ref=pm]PM[/ref][/color]". - """ - - picker = OptionProperty("hours", options=("minutes", "hours")) - """Currently shown time picker. Can be one of "minutes", "hours". - - :attr:`picker` is a :class:`~kivy.properties.OptionProperty` and - defaults to "hours". - """ - - # selector_color = ListProperty([.337, .439, .490]) - selector_color = ListProperty([0, 0, 0]) - """Color of the number selector and of the highlighted text. RGB. - - :attr:`selector_color` is a :class:`~kivy.properties.ListProperty` and - defaults to [.337, .439, .490] (material green). - """ - - color = ListProperty([1, 1, 1]) - """Color of the number labels and of the center dot. RGB. - - :attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to [1, 1, 1] (white). - """ - - selector_alpha = BoundedNumericProperty(.3, min=0, max=1) - """Alpha value for the transparent parts of the selector. - - :attr:`selector_alpha` is a :class:`~kivy.properties.BoundedNumericProperty` and - defaults to 0.3 (min=0, max=1). - """ - - _am = BooleanProperty(True) - _h_picker = ObjectProperty(None) - _m_picker = ObjectProperty(None) - _bound = DictProperty({}) - - def _get_time(self): - try: - return datetime.time(*self.time_list) - except ValueError: - self.time_list = [self.hours, 0] - return datetime.time(*self.time_list) - - def set_time(self, dt): - if dt.hour >= 12: - dt.strftime("%I:%M") - self._am = False - self.time_list = [dt.hour, dt.minute] - - time = AliasProperty(_get_time, set_time, bind=("time_list",)) - """Selected time as a datetime.time object. - - :attr:`time` is an :class:`~kivy.properties.AliasProperty`. - """ - - def _get_picker(self): - if self.picker == "hours": - return self._h_picker - return self._m_picker - - _picker = AliasProperty(_get_picker, None) - - def _get_time_text(self): - hc = rgb_to_hex(0, 0, 0) if self.picker == "hours" else rgb_to_hex(*self.primary_dark) - mc = rgb_to_hex(0, 0, 0) if self.picker == "minutes" else rgb_to_hex(*self.primary_dark) - h = self.hours == 0 and 12 or self.hours <= 12 and self.hours or self.hours - 12 - m = self.minutes - primary_dark = rgb_to_hex(*self.primary_dark) - return self.time_format.format(hours_color=hc, - minutes_color=mc, - hours=h, - minutes=m, - primary_dark=primary_dark) - time_text = AliasProperty(_get_time_text, None, bind=("hours", "minutes", "time_format", "picker")) - - def _get_ampm_text(self, *args): - amc = rgb_to_hex(0, 0, 0) if self._am else rgb_to_hex(*self.primary_dark) - pmc = rgb_to_hex(0, 0, 0) if not self._am else rgb_to_hex(*self.primary_dark) - return self.ampm_format.format(am_color=amc, - pm_color=pmc) - - ampm_text = AliasProperty(_get_ampm_text, None, bind=("hours", "ampm_format", "_am")) - - def __init__(self, **kw): - super(CircularTimePicker, self).__init__(**kw) - self.selector_color = self.theme_cls.primary_color[0], self.theme_cls.primary_color[1], \ - self.theme_cls.primary_color[2] - self.color = self.theme_cls.text_color - self.primary_dark = self.theme_cls.primary_dark[0] / 2, self.theme_cls.primary_dark[1] / 2, \ - self.theme_cls.primary_dark[2] / 2 - self.on_ampm() - if self.hours >= 12: - self._am = False - self.bind(time_list=self.on_time_list, - picker=self._switch_picker, - _am=self.on_ampm, - primary_dark=self._get_ampm_text) - self._h_picker = CircularHourPicker() - self.h_picker_touch = False - self._m_picker = CircularMinutePicker() - self.animating = False - Clock.schedule_once(self.on_selected) - Clock.schedule_once(self.on_time_list) - Clock.schedule_once(self._init_later) - Clock.schedule_once(lambda *a: self._switch_picker(noanim=True)) - - def _init_later(self, *args): - self.ids.timelabel.bind(on_ref_press=self.on_ref_press) - self.ids.ampmlabel.bind(on_ref_press=self.on_ref_press) - - def on_ref_press(self, ign, ref): - if not self.animating: - if ref == "hours": - self.picker = "hours" - elif ref == "minutes": - self.picker = "minutes" - if ref == "am": - self._am = True - elif ref == "pm": - self._am = False - - def on_selected(self, *a): - if not self._picker: - return - if self.picker == "hours": - hours = self._picker.selected if self._am else self._picker.selected + 12 - if hours == 24 and not self._am: - hours = 12 - elif hours == 12 and self._am: - hours = 0 - self.hours = hours - elif self.picker == "minutes": - self.minutes = self._picker.selected - - def on_time_list(self, *a): - if not self._picker: - return - self._h_picker.selected = self.hours == 0 and 12 or self._am and self.hours or self.hours - 12 - self._m_picker.selected = self.minutes - self.on_selected() - - def on_ampm(self, *a): - if self._am: - self.hours = self.hours if self.hours < 12 else self.hours - 12 - else: - self.hours = self.hours if self.hours >= 12 else self.hours + 12 - - def is_animating(self, *args): - self.animating = True - - def is_not_animating(self, *args): - self.animating = False - - def on_touch_down(self, touch): - if not self._h_picker.collide_point(*touch.pos): - self.h_picker_touch = False - else: - self.h_picker_touch = True - super(CircularTimePicker, self).on_touch_down(touch) - - def on_touch_up(self, touch): - try: - if not self.h_picker_touch: - return - if not self.animating: - if touch.grab_current is not self: - if self.picker == "hours": - self.picker = "minutes" - except AttributeError: - pass - super(CircularTimePicker, self).on_touch_up(touch) - - def _switch_picker(self, *a, **kw): - noanim = "noanim" in kw - if noanim: - noanim = kw["noanim"] - - try: - container = self.ids.picker_container - except (AttributeError, NameError): - Clock.schedule_once(lambda *a: self._switch_picker(noanim=noanim)) - - if self.picker == "hours": - picker = self._h_picker - prevpicker = self._m_picker - elif self.picker == "minutes": - picker = self._m_picker - prevpicker = self._h_picker - - if len(self._bound) > 0: - prevpicker.unbind(selected=self.on_selected) - self.unbind(**self._bound) - picker.bind(selected=self.on_selected) - self._bound = {"selector_color": picker.setter("selector_color"), - "color": picker.setter("color"), - "selector_alpha": picker.setter("selector_alpha")} - self.bind(**self._bound) - - if len(container._bound) > 0: - container.unbind(**container._bound) - container._bound = {"size": picker.setter("size"), - "pos": picker.setter("pos")} - container.bind(**container._bound) - - picker.pos = container.pos - picker.size = container.size - picker.selector_color = self.selector_color - picker.color = self.color - picker.selector_alpha = self.selector_alpha - if noanim: - if prevpicker in container.children: - container.remove_widget(prevpicker) - if picker.parent: - picker.parent.remove_widget(picker) - container.add_widget(picker) - else: - self.is_animating() - if prevpicker in container.children: - anim = Animation(scale=1.5, d=.5, t="in_back") & Animation(opacity=0, d=.5, t="in_cubic") - anim.start(prevpicker) - Clock.schedule_once(lambda *y: container.remove_widget(prevpicker), .5) # .31) - picker.scale = 1.5 - picker.opacity = 0 - if picker.parent: - picker.parent.remove_widget(picker) - container.add_widget(picker) - anim = Animation(scale=1, d=.5, t="out_back") & Animation(opacity=1, d=.5, t="out_cubic") - anim.bind(on_complete=self.is_not_animating) - Clock.schedule_once(lambda *y: anim.start(picker), .3) - - -if __name__ == "__main__": - from kivy.base import runTouchApp - - c = CircularTimePicker() - runTouchApp(c) diff --git a/src/main.py b/src/main.py index 969dbe56..22ea7c3e 100644 --- a/src/main.py +++ b/src/main.py @@ -1,8 +1,8 @@ """This module is for thread start.""" -from bitmessagemain import main import state if __name__ == '__main__': state.kivy = True - print("Kivy Loading......") + print("Kivy Loading for PyBitmessage......") + from bitmessagemain import main main() diff --git a/src/navigationdrawer/__init__.py b/src/navigationdrawer/__init__.py deleted file mode 100644 index a8fa5ce7..00000000 --- a/src/navigationdrawer/__init__.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.icon_definitions import md_icons -from kivymd.label import MDLabel -from kivymd.list import OneLineIconListItem, ILeftBody, BaseListItem -from kivymd.slidingpanel import SlidingPanel -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - canvas: - Color: - rgba: root.parent.parent.theme_cls.divider_color - Line: - points: self.x, self.y, self.x+self.width,self.y - - - widget_list: widget_list - elevation: 0 - canvas: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: root.size - pos: root.pos - BoxLayout: - size_hint: (1, .4) - NavDrawerToolbar: - padding: 10, 10 - canvas.after: - Color: - rgba: (1, 1, 1, 1) - RoundedRectangle: - size: (self.size[1]-dp(14), self.size[1]-dp(14)) - pos: (self.pos[0]+(self.size[0]-self.size[1])/2, self.pos[1]+dp(7)) - source: root.image_source - radius: [self.size[1]-(self.size[1]/2)] - - ScrollView: - do_scroll_x: False - MDList: - id: ml - id: widget_list - - - NDIconLabel: - id: _icon - font_style: 'Icon' - theme_text_color: 'Secondary' -''') - - -class NavigationDrawer(SlidingPanel, ThemableBehavior, ElevationBehavior): - image_source = StringProperty() - widget_list = ObjectProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, BaseListItem): - self.widget_list.add_widget(widget, index) - widget.bind(on_release=lambda x: self.toggle()) - else: - super(NavigationDrawer, self).add_widget(widget, index) - - def _get_main_animation(self, duration, t, x, is_closing): - a = super(NavigationDrawer, self)._get_main_animation(duration, t, x, - is_closing) - a &= Animation(elevation=0 if is_closing else 5, t=t, duration=duration) - return a - - -class NDIconLabel(ILeftBody, MDLabel): - pass - - -class NavigationDrawerIconButton(OneLineIconListItem): - icon = StringProperty() - - def on_icon(self, instance, value): - self.ids['_icon'].text = u"{}".format(md_icons[value]) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 9ceb856b..02e5db8f 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -18,7 +18,9 @@ class BMNetworkThread(threading.Thread, StoppableThread): def run(self): try: while not self._stopped and state.shutdown == 0: + print("I am running in run method which calls a loop for BMConnectionPool line19..................................") BMConnectionPool().loop() + print("I am running in run method which calls a loop for BMConnectionPool line 21..................................") except Exception as e: excQueue.put((self.name, e)) raise diff --git a/src/paths.py b/src/paths.py index 325fcd8b..86190363 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,10 +1,11 @@ from os import environ, path import sys import re +import os from datetime import datetime - +from kivy.utils import platform # When using py2exe or py2app, the variable frozen is added to the sys -# namespace. This can be used to setup a different code path for +# namespace. This can be used to setup a different code path for # binary distributions vs source distributions. frozen = getattr(sys,'frozen', None) @@ -22,6 +23,10 @@ def lookupExeFolder(): return exeFolder def lookupAppdataFolder(): + + print("HIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", platform) + import traceback + print(traceback.print_tb) APPNAME = "PyBitmessage" if "BITMESSAGE_HOME" in environ: dataFolder = environ["BITMESSAGE_HOME"] @@ -37,6 +42,10 @@ def lookupAppdataFolder(): else: print stringToLog sys.exit() + elif platform == 'android': + # dataFolder = path.join(os.path.dirname(os.path.abspath("__file__")), "PyBitmessage") + '/' + dataFolder = path.join('/sdcard/', 'DCIM/', APPNAME) + '/' + print("YOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", dataFolder) elif 'win32' in sys.platform or 'win64' in sys.platform: dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep @@ -60,13 +69,13 @@ def lookupAppdataFolder(): pass dataFolder = dataFolder + '/' return dataFolder - + def codePath(): if frozen == "macosx_app": codePath = environ.get("RESOURCEPATH") elif frozen: # windows codePath = sys._MEIPASS - else: + else: codePath = path.dirname(__file__) return codePath @@ -87,7 +96,7 @@ def tail(f, lines=20): blocks.append(f.read(BLOCK_SIZE)) else: # file too small, start from begining - f.seek(0,0) + f.seek(0, 0) # only read what was not read blocks.append(f.read(block_end_byte)) lines_found = blocks[-1].count('\n') @@ -111,4 +120,4 @@ def lastCommit(): ) except (IOError, AttributeError, TypeError): pass - return result + return result \ No newline at end of file diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py index 7f21c6b8..c5a21ac3 100644 --- a/src/plugins/menu_qrcode.py +++ b/src/plugins/menu_qrcode.py @@ -37,7 +37,7 @@ class Image(qrcode.image.base.BaseImage): QtCore.Qt.black) -class QRCodeDialog(QtGui.QDialog): +class QRCodeDialog(QtGui.QDialog): """The dialog""" def __init__(self, parent): super(QRCodeDialog, self).__init__(parent) diff --git a/src/proofofwork.py b/src/proofofwork.py index bb16951c..5a36edf3 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -19,6 +19,8 @@ import state import tr from bmconfigparser import BMConfigParser from debug import logger +from kivy.utils import platform + bitmsglib = 'bitmsghash.so' bmpow = None @@ -228,6 +230,7 @@ def buildCPoW(): call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash"), '-f', 'Makefile.bsd']) else: # GNU make + print("I am in buildCPoW hurray.......................................", os.path.join(paths.codePath(), "bitmsghash")) call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")]) if os.path.exists(os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so")): init() @@ -292,8 +295,7 @@ def init(): global bitmsglib, bmpow openclpow.initCL() - - if sys.platform == "win32": + if "win32" == sys.platform: if ctypes.sizeof(ctypes.c_voidp) == 4: bitmsglib = 'bitmsghash32.dll' else: @@ -319,6 +321,14 @@ def init(): except: logger.error("C PoW test fail.", exc_info=True) bso = None + elif platform == "android": + print(sys.platform) + try: + bso = ctypes.CDLL('libbitmsghash.so') + except Exception as e: + bso = None + print(e) + else: try: bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 115bdc08..ed86dbeb 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -10,7 +10,7 @@ import sys import ctypes OpenSSL = None - +from kivy.utils import platform class CipherName: def __init__(self, name, pointer, blocksize): @@ -70,7 +70,9 @@ class _OpenSSL: """ Build the wrapper """ + print("I am on openssl ctypes loading...............................................") self._lib = ctypes.CDLL(library) + print(library, "library12library12library12library12library12library12library12") self._version, self._hexversion, self._cflags = get_version(self._lib) self._libreSSL = self._version.startswith("LibreSSL") @@ -531,6 +533,10 @@ def loadOpenSSL(): libdir.extend(['libcrypto.dylib', '/usr/local/opt/openssl/lib/libcrypto.dylib']) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append('libeay32.dll') + elif platform == "android": + libdir.append('libcrypto1.0.2p.so') + libdir.append('libssl1.0.2p.so') + else: libdir.append('libcrypto.so') libdir.append('libssl.so') @@ -542,6 +548,7 @@ def loadOpenSSL(): libdir.append(find_library('libeay32')) for library in libdir: try: + print(library, "librarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrary") OpenSSL = _OpenSSL(library) return except: diff --git a/src/semaphores.py b/src/semaphores.py new file mode 100644 index 00000000..04120fe7 --- /dev/null +++ b/src/semaphores.py @@ -0,0 +1,3 @@ +from threading import Semaphore + +kivyuisignaler = Semaphore(0) \ No newline at end of file diff --git a/src/shared.py b/src/shared.py index 6d03bcca..b197b631 100644 --- a/src/shared.py +++ b/src/shared.py @@ -9,7 +9,7 @@ import hashlib import subprocess from binascii import hexlify from pyelliptic import arithmetic - +from kivy.utils import platform # Project imports. import state import highlevelcrypto @@ -116,21 +116,30 @@ def decodeWalletImportFormat(WIFstring): def reloadMyAddressHashes(): logger.debug('reloading keys from keys.dat file') + print("SHARED 146 begins.....................................................................") + myECCryptorObjects.clear() myAddressesByHash.clear() myAddressesByTag.clear() # myPrivateKeys.clear() + print("SHARED 152 begins.....................................................................") keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') hasEnabledKeys = False + print("SHARED 156 begins.....................................................................") + print(BMConfigParser().addresses()) for addressInKeysFile in BMConfigParser().addresses(): + print("SHARED 158 begins.....................................................................") isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') + print("SHARED 160 begins.....................................................................") if isEnabled: + print("SHARED 161 begins.....................................................................") hasEnabledKeys = True # status _, addressVersionNumber, streamNumber, hash = \ decodeAddress(addressInKeysFile) if addressVersionNumber in (2, 3, 4): + print("SHARED 166 begins.....................................................................") # Returns a simple 32 bytes of information encoded # in 64 Hex characters, or null if there was an error. privEncryptionKey = hexlify(decodeWalletImportFormat( @@ -149,13 +158,17 @@ def reloadMyAddressHashes(): myAddressesByTag[tag] = addressInKeysFile else: + print("SHARED 185 begins.....................................................................") logger.error( 'Error in reloadMyAddressHashes: Can\'t handle' ' address versions other than 2, 3, or 4.\n' ) + print("SHARED 187 begins.....................................................................") - if not keyfileSecure: - fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + if not platform == "android": + if not keyfileSecure: + fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + print("SHARED 196 begins.....................................................................") def reloadBroadcastSendersForWhichImWatching(): diff --git a/src/singleinstance.py b/src/singleinstance.py index c2def912..a495bea0 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -11,6 +11,7 @@ except ImportError: pass + class singleinstance: """ Implements a single instance application by creating a lock file @@ -28,7 +29,7 @@ class singleinstance: self.lockfile = os.path.normpath( os.path.join(state.appdata, 'singleton%s.lock' % flavor_id)) - if state.enableGUI and not self.daemon and not state.curses: + if state.enableGUI and not state.kivy and not self.daemon and not state.curses: # Tells the already running (if any) application to get focus. import bitmessageqt bitmessageqt.init() diff --git a/src/state.py b/src/state.py index 2cbc3a7c..b86c3bf6 100644 --- a/src/state.py +++ b/src/state.py @@ -69,3 +69,7 @@ testmode = False kivy = False association = '' + +kivyapp = None + +navinstance = None \ No newline at end of file diff --git a/src/tr.py b/src/tr.py index 8b41167f..6f26e75d 100644 --- a/src/tr.py +++ b/src/tr.py @@ -25,9 +25,13 @@ def translateText(context, text, n = None): try: from PyQt4 import QtCore, QtGui except Exception as err: - print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' - print 'Error message:', err - os._exit(0) + try: + if state.kivy: + pass + except Exception as err: + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' + print 'Error message:', err + os._exit(0) if n is None: return QtGui.QApplication.translate(context, text) else: From 5db1c3971cc932464c025c112466236f36cb06f9 Mon Sep 17 00:00:00 2001 From: surbhi Date: Mon, 13 May 2019 17:01:33 +0530 Subject: [PATCH 007/306] Fix code quality checks and refactor with Inbox loading --- src/bitmessagekivy/kivy_helper_search.py | 2 +- src/bitmessagekivy/main.kv | 28 ++- src/bitmessagekivy/mpybit.py | 306 ++++++++--------------- 3 files changed, 116 insertions(+), 220 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 6758f554..cbf00fb4 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -12,7 +12,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' else: - sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read + sqlStatementBase = '''SELECT folder, msgid, toaddress, message, fromaddress, subject, received, read FROM inbox ''' sqlStatementParts = [] sqlArguments = [] diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index dc74450d..8f167298 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -266,12 +266,14 @@ NavigationLayout: spacing: 15 BoxLayout: orientation: 'vertical' - TextInput: + MDTextField: id: ti hint_text: 'type or select sender address' size_hint_y: None height: 100 multiline: False + required: True + helper_text_mode: "on_error" BoxLayout: size_hint_y: None @@ -288,7 +290,7 @@ NavigationLayout: txt_input: txt_input rv: rv size : (890, 60) - size_hint: 1,2 + size_hint: 1,1 MyTextInput: id: txt_input size_hint_y: None @@ -296,29 +298,32 @@ NavigationLayout: hint_text: 'type or search recipients address starting with BM-' RV: id: rv - TextInput: + MDTextField: id: subject hint_text: 'subject' - size_hint_y: None + required: True height: 100 + size_hint_y: None multiline: False - TextInput: + helper_text_mode: "on_error" + + MDTextField: id: body + multiline: True hint_text: 'body' size_hint_y: None - height: 100 - multiline:True - size_hint: 1,2 + required: True + helper_text_mode: "on_error" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 + size_hint: .8, .3 text: 'send' on_press: root.send() BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 + size_hint: .8, .3 text: 'reset' on_press: app.root.ids.scr_mngr.current = 'random' @@ -441,7 +446,8 @@ NavigationLayout: multiline: True hint_text: "Label" helper_text: "Label (not shown to anyone except you)" - helper_text_mode: "persistent" + required: True + helper_text_mode: "on_error" MDRaisedButton: text: 'next' size_hint_y: 0.13 diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a6a29ead..05bc3186 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -49,42 +49,55 @@ from kivy.core.window import Window userAddress = '' + class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() - # print("priiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnnnttttttttttthethingsss.................", ) class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) - # if state.association == '': - # state.association = 'BM-2cTuPpAPbu44sbkfVJN2F99sXGJoeNpDBh' - # print(self.get_address_via_split(state.association)) + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts.""" - print("generateaddressgenerateaddressgenerateaddressgenerateaddressgenerateaddress", BMConfigParser().addresses()) - if BMConfigParser().addresses(): - data = [{'text': "surbhi cis222222", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "peter surda", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "uber", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "ola", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "glitch", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "github", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "kivy", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "andrew", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + """Clock Schdule for method sent accounts.""" + self.inboxaccounts() + print(dt) + + def inboxaccounts(self): + """Load inbox accounts.""" + account = state.association + self.loadMessagelist(account, 'All', '') + + def loadMessagelist(self, account, where="", what=""): + """Load Sent list for Sent messages.""" + xAddress = 'toaddress' + data = [] + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "inbox", where, what, False) + if queryreturn: + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + data.append({'text': mail[2].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[2]) > 10 else mail[2] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text }) for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/kivymd_logo.png')) + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) else: - self.manager.current = 'login' + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) class MyAddress(Screen): @@ -95,25 +108,23 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - pass - # if BMConfigParser().AddressSuccessful(): - # data = [{'text': "me", 'secondary_text': "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyTfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyVfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWySfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyHfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyJfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyKfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyMnBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyOkBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyWuBdY2FbgyuCb7abFZ49JYxSzUhNFe"}] - # for item in data: - # meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - # meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - # self.ids.ml.add_widget(meny) - # else: - # self.manager.current = 'login' - + if BMConfigParser().addresses(): + data = [] + for address in BMConfigParser().addresses(): + data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) + for item in data: + meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no address is created by user!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) class AddressBook(Screen): @@ -124,7 +135,6 @@ class AddressBook(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - # sqlExecute("DELETE FROM addressbook WHERE label='' ") data = sqlQuery("SELECT label, address from addressbook") if data: for item in data: @@ -140,16 +150,16 @@ class AddressBook(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) - print("chek iniiiiiiiiiiiiiittttttttttttttttttttttttttttttttt", self) - # self.ids.ml.clear_widgets() def refreshs(self, *args): state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) + class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): ''' Adds selection and focus behaviour to the view. ''' + pass class SelectableLabel(RecycleDataViewBehavior, Label): @@ -191,51 +201,32 @@ class DropDownWidget(BoxLayout): def send(self): """Send message from one address to another.""" fromAddress = str(self.ids.ti.text) - # For now we are using static address i.e we are not using recipent field value. - # toAddress = str(self.ids.txt_input.text) - # print("hiiiiiiiiiiiiiiiiii i am hereeeeeeeeeeeeeeeeeeeeee..............") - # print("hiiiiiiiiiseeeee to addresssssssssss..........................", self.ids) - # print("ssssssssssseeeeeeeeeeeeeeeeeeetheeeeeeeeeeetexttinput....data...", self.ids.txt_input.text) - # toAddress = "BM-2cVJ8Bb9CM5XTEjZK1CZ9pFhm7jNA1rsa6" - # print("every thng is good for the day..................", str(self.ids.txt_input.text)) toAddress = str(self.ids.txt_input.text) - print("alllllllllllllllllllllllllllsss wel ends wellllllllllllllll", ) subject = str(self.ids.subject.text) message = str(self.ids.body.text) - print("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR") encoding = 3 print("message: ", self.ids.body.text) sendMessageToPeople = True - print("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS") if sendMessageToPeople: - print("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT") - print("did_addresssssssssssssssss_existsssssssssssssssssssss.........buyyyyy", toAddress) - if toAddress != '': - print("UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU") + if toAddress != '' and subject and message: from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) - print("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV") if status == 'success': from addresses import * toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' - print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") if addressVersionNumber > 4 or addressVersionNumber <= 1: print("addressVersionNumber > 4 or addressVersionNumber <= 1") if streamNumber > 1 or streamNumber == 0: print("streamNumber > 1 or streamNumber == 0") if statusIconColor == 'red': print("shared.statusIconColor == 'red'") - print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') - print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - print("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY") t = () - print("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', @@ -253,26 +244,38 @@ class DropDownWidget(BoxLayout): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) - print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) - print("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") - print("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD") print("sqlExecute successfully #######################") self.ids.body.text = '' self.ids.ti.text = '' self.ids.subject.text = '' self.ids.txt_input.text = '' - # self.manager.current - # self.ids.scr_mngr.current = 'add_sucess' self.parent.parent.current = 'sent' - # print("whattttttttttttttttisdebuggerbtnssssssssss........................", self.ids) self.ids.btn.text = 'select' self.ids.ti.text = '' - print("sssssssssssuvvvvvvvvvvvvvvvvvtttttttttttttttttt...............") return None + else: + msg = 'Enter a valid recipients address' + self.address_error_message(msg) + elif not toAddress: + msg = 'Enter a recipients address' + self.address_error_message(msg) + + def address_error_message(self, msg): + self.box = FloatLayout() + self.lab = (Label(text=msg, font_size=25, + size_hint=(None, None), pos_hint={'x': .25, 'y': .6})) + self.box.add_widget(self.lab) + self.but = (Button(text="dismiss", size_hint=(None, None), + width=200, height=50, pos_hint={'x': .3, 'y': 0})) + self.box.add_widget(self.but) + self.main_pop = Popup(title="Error", content=self.box, + size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) + self.but.bind(on_press=self.main_pop.dismiss) + self.main_pop.open() class MyTextInput(TextInput): @@ -297,8 +300,8 @@ class MyTextInput(TextInput): self.parent.parent.parent.parent.ids.rv.data = display_data # ensure the size is okay if len(matches) <= 10: - self.parent.height = (250 + (len(matches)*20)) - else: + self.parent.height = (250 + (len(matches) * 20)) + else: self.parent.height = 400 def keyboard_on_key_down(self, window, keycode, text, modifiers): @@ -311,6 +314,7 @@ class MyTextInput(TextInput): class Payment(Screen): pass + class Login(Screen): pass @@ -330,7 +334,7 @@ class NetworkStat(Screen): """Clock Schdule for method inbox accounts.""" import network.stats import shared - from network import objectracker + from network import objectracker self.text_variable_1 = '{0} :: {1}'.format('Total Connections', str(len(network.stats.connectedHostsList()))) self.text_variable_2 = 'Processed {0} per-to-per messages'.format(str(shared.numberOfMessagesProcessed)) self.text_variable_3 = 'Processed {0} brodcast messages'.format(str(shared.numberOfBroadcastsProcessed)) @@ -355,39 +359,16 @@ class Random(Screen): eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - queues.addressGeneratorQueue.put(( - 'createRandomAddress', - 4, streamNumberForAddress, - label, 1, "", eighteenByteRipe, - nonceTrialsPerByte, - payloadLengthExtraBytes) - ) - self.manager.current = 'add_sucess' - print("whhhheeeeeeee55566666666666666666666..................", self) - print("what is the screeen forrrrrrrrrrrrrrrrr...............", self.ids) - self.ids.label.text = '' - # print("whatttttt99999999999999999999999999999999999988888888......", self.parent.parent) - # print("go.....more...parenxccccccccccccccccccccccc555559955555555555", self.parent.parent.parent) - # print("ssssshooooocxvxcvxcvoooouuuuuuuuuuuuuuuuuueeeettttttttteeeeeeeeeee............... ", ContentNavigationDrawer().ids.btn) - # print("spiiiiinnnxcvxcxc99999999999999999999999999999999999999tttt..........", ContentNavigationDrawer().ids.btn.text) - # print("text_dirrrrrrrrrrrrrrrrrrrrrr9999999999999999fgdg.............................", dir(ContentNavigationDrawer().ids.btn)) - # print("ttttttttttttttiiiiiiiiilllllllllllllllttttleeeeeeeee9999999999999999999", ContentNavigationDrawer().ids.btn.text) - # prnit("55555557777777777777777888888888888888888jjjjjjjjjj", ContentNavigationDrawer().ids.btn.text) - # print("what account is associated..............................", state.association) - # print("pppppppppp999999999666666666663333333333333333333333..............", BMConfigParser().addresses()) - # print("whatssssssssssssssssssssssstheva,lllllllllllleeeeeeeee...........") - # print("wh.....................8888888899999999999999999999999999", queues.addressGeneratorQueue.get()) - - # print("ljjkkkkkkkkkkkkkkkkkkk666666666666666666666666666666666", self.parent.parent.parent.parent.parent) - # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] - # if BMConfigParser().addresses(): - # print("iiiinnnnnnnnnnnnnnnnnnnnnnnnnnsssssssssssiiiiiiiiiideeeeeeeee") - # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] - # return BMConfigParser().addresses()[0] - # print("iiiiiiiiiiiiiihhhhhhhhhhhhhhhhh5555555555555555555....", ContentNavigationDrawer()) - # print("khhhhhhhhhhhhhyaaaaaaaaaaaaaaaa5555555555555555...............", ContentNavigationDrawer().ids) - # print("it is sccccccccccccefssssfulllllll............................", ContentNavigationDrawer().ids.btn.text) - # ids.btn.text + if self.ids.label.text: + queues.addressGeneratorQueue.put(( + 'createRandomAddress', + 4, streamNumberForAddress, + label, 1, "", eighteenByteRipe, + nonceTrialsPerByte, + payloadLengthExtraBytes) + ) + self.manager.current = 'add_sucess' + self.ids.label.text = '' class AddressSuccessful(Screen): @@ -397,90 +378,53 @@ class AddressSuccessful(Screen): class NavigationLayout(): pass + class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" data = ListProperty() def __init__(self, *args, **kwargs): super(Sent, self).__init__(*args, **kwargs) - # print("I amuuuuuupfatgd vale should get..................... .", ContentNavigationDrawer().ids.btn.text) - # print("yyyyyyuuuuuuuuuuuuuuuuuoooooooooouuuyyyyyyyyyyyy...............", ContentNavigationDrawer().ids.btn.values) - # print("ccchekkkkkkkkkccccccccccclre..................................................", ContentNavigationDrawer().ids.btn) - # print("llllllllllleeeeetttttttttttttttttttttheeeeeeeeemmmmmmcheccccccccccckkk........", dir(ContentNavigationDrawer().ids.btn)) - # print("llllllllllllllllllllllllllleeeeeeeeeeeeeeeeeeeeeeeexfgcgcgvcgvcvgbeeechhhhhhhhhhheck", state.association) if state.association == '': - # state.association = Navigatocoming inside thew methoddddddddddddddddddds1buildrss().ids.btn.text - print("uuuuuuuuuuuuuuuuuuuuuuuuu999999999999999999999999999999") - print("lllllllllllllllllllllllllllllll55555555556666666666", BMConfigParser().addresses()) if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - print("kkkkkkkkkkkkkkkkkkkkkkkkkkkk6666666666888888888888888888...................", state.association) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method sent accounts.""" - print("oooooooooooooooooooooooooooo999999999999999999999000000000") self.sentaccounts() print(dt) def sentaccounts(self): """Load sent accounts.""" - print("mmmmmmmmmmmmmmmmmmmmmmmm44444444444444444455555555555__........") account = state.association - print("zzzzzzzzzzzzzzzzzzzzzzz99999999999999999999999999999999999", account) self.loadSent(account, 'All', '') def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" - # print("uuuuuuuuuuuuuuuuyyyyyyyyyrrrrrrrrrrrinside_loadSent..........") xAddress = 'fromaddress' data = [] - # print("check--------thre.................somethiong.......cvmnvb mvn xmnvcxv.") queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - print("qqqqqqqq77777777777777777777777777777777555hhhhhhhhhhhhhhhfffffff....", queryreturn) if queryreturn: - # for mail in sqlQuery("SELECT toaddress, subject, message FROM addressbook a, sent s WHERE a.address = s.fromaddress and s.fromaddress = 'BM-2cUz6dniZHjFTqv6j2es2wBSe3NydZdk4R';"): for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - print("whatttttttttttttttttttttttttttisssssssssssssssssssssssserrrrrrrrrrrrror") - print("nowwwwwwwwww9999999999999999999999999999999..................", third_text) - # print("sssssssssssssssseeeeeeeeeeeeeeeeeeeeeeeeeeeepprob.....", mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2]) - # data.append({'text': mail[0].strip(), 'secondary_text': mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) - # data.append({'text': '', 'secondary_text': mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) data.append({'text': mail[0].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 }) - print("kyaaaaaaaaaaaaaaaaaaaaaaaaaayhaaaaaaaaaaaaerorrrrrrrrrr") - # self.data = [{ - # 'data_index': i, - # 'index': 1, - # 'height': 48, - # 'text': row[2], - # } - # for i, row in enumerate(queryreturn) - # ] - print("show 6666666666666666666eeeeeee555555555555555daaaaaaaaaaa.......", data) for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) - print("uyyyyyyyyyyyyyyyyyyyyyyyyyuuuuuuuuuggg558888888888gggggggoooooooooooooooooooooooooooooooooooooooo....") - # print("ufffffffffffffffffffffffff6666666666666ffffyyyyyyyyyyyyyyyyyyyyyyyyypp.......", self.data) else: - # self.data = [{ - # 'data_index': 1, - # 'index': 1, - # 'height': 48, - # 'text': "yet no message for this account!!!!!!!!!!!!!"} - # ] content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) + class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): @@ -512,20 +456,13 @@ class Page(Screen): class Create(Screen): def __init__(self, **kwargs): super(Create, self).__init__(**kwargs) - # from kivy.core.window import Window - print("cheeeeeeeeeeeehn888888888888888888888888gggkkkkkkkthe windowwwwwwwwwwwwwwww", Window.size) - # print("take the onlyyyyyyyyyyyyyyyyyyyyyyyyyyyy x axssssssssssssssssssssssswindow", Window.size[0]) - # print("realllllllllllyyyyyyyyyyyyy yyyyyyyyyyyoooooouuuuuuu wwwwwwaaaaaaaaaaaannnnnnnnnntttt", Window._get_width) - # print("mmmmmmmmmmmmmminnnnnnnnnnnnnnnn and mmmmmmmmaaaaaaaaxxxxxxxesssssssss", Window.minimum_height, Window.minimum_width) - # print("dir in windowwwwwwwwwkkkkkkkkkkkww of the mobile screen", dir(Window)) - # print("cheeeeeeeeeeeeeeeeeckkkkkkkkkkkkkkkk width and heightttttttttttttttttttt", Window.width, window.height) widget_1 = DropDownWidget() from helper_sql import * widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] - # widget_1.ids.txt_input.word_list = ['how to use python', 'how to use kivy', 'how to use django', 'BM-2cTik2JBHAS92U633LPY', 'BM-2cUYmQofWjTQeUitL7'] widget_1.ids.txt_input.starting_no = 2 self.add_widget(widget_1) + class AddressSuccessful(Screen): pass @@ -540,10 +477,9 @@ class NavigateApp(App): obj_1 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - # user_address = StringProperty('jai') + sentmail = NumericProperty(0) scr_size = Window.size[0] - - title = "KivyMD" + title = "PyBitmessage" count = 0 menu_items = [ {'viewclass': 'MDMenuItem', @@ -563,9 +499,6 @@ class NavigateApp(App): ] def build(self): - print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllllllrrrrrrrrrrahut......') - print('chreckoooooooooooooooo........................', self.variable_1) - print("dsssssssssssoddddddddd77777777777777777777eeeeeeeeetheroot", dir(self)) import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) @@ -595,17 +528,7 @@ class NavigateApp(App): "That's pretty awesome right!", size_hint_y=None, valign='top') - print("9063 I am pressed...............................................................") content.bind(texture_size=content.setter('size')) - print("9064 I am pressed...............................................................") - # self.dialog = MDDialog(content=content, - # size_hint=(.8, None), - # height=dp(200), - # auto_dismiss=False) - print("9065 I am pressed...............................................................") - # self.dialog.add_action_button("Dismiss", - # action=lambda *x: self.dialog.dismiss()) - print("966 I am pressed...............................................................") self.dialog.open() @staticmethod @@ -622,31 +545,16 @@ class NavigateApp(App): return [address[:16] + '..' for address in BMConfigParser().addresses()] else: return "valuesdemo" - # return [BMConfigParser().get(address, 'label')[:12] + '..' for address in BMConfigParser().sections()[1:]] - # return BMConfigParser().addresses() def getCurrentAccountData(self, text): """Get Current Address Account Data.""" - print("self tttttttttttttttttttttteeeeeeeeeexfgvbcvgfcgfdgfdgfgxxxxxxxxtttttttttzzzzzzzz ", text) state.association = text - # print("eeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrorrrrrrrrrrrrrrrrrr", self.root) - # print("iiiiiiiiiiiiiidddddddddddddddddeeeeeeeessssssssssssssssss55......", self.root.ids) self.root.ids.sc1.clear_widgets() self.root.ids.sc4.clear_widgets() self.root.ids.sc5.clear_widgets() - # print("resffffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuurrrrrrrrrrrrr......") self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) - # print("again aaaaddddddddddddddddddinggggggggggggggggguuuuuuuuuuuuuuuu1 ........") - - # self.root.ids.toolbar.title = BMConfigParser().get( - # state.association, 'label') + '({})'.format(state.association) - # print("what theyyyyyyyyyyyyyyyyyyyy areeeeeeeeeeeee printing11........", self.root.ids.toolbar.title) - # Inbox() - # Sent() - # Trash() - # print("finish gamneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!") def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" @@ -669,9 +577,6 @@ class NavigateApp(App): p.open() def getDefaultAccData(self): - print("coming inside thew methodddddddddddddddddddsdcassdfs1") - print("combbbbbbbbbbbbggggffffffdfgdgfffffffgggggggggggggggggggllllllloooo", BMConfigParser().addresses()) - # return BMConfigParser.addresses[0] if BMConfigParser().addresses(): return BMConfigParser().addresses()[0] return 'Select Address' @@ -684,19 +589,13 @@ class GrashofPopup(Popup): self.size_hint_x = 0.9 def savecontact(self): - print("show the addedes addess in databaseeeeeeeeeeeeeeeeee............................") - print("1110 I am pressed...............................................................") label = self.ids.label.text - print("2210 I am pressed...............................................................") address = self.ids.address.text - print("3310 I am pressed...............................................................") if label and address: state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - # self.parent.children[1].ids.sc11.clear_widgets() - # self.parent.children[1].ids.sc11.add_widget(AddressBook()) def show_error_message(self): content = MDLabel(font_style='Body1', @@ -743,18 +642,9 @@ class NavigationDrawerTwoLineListItem( Binds Controller.current_account property. """ pass - # self.controller = App.get_running_app().controller - # self.controller.bind( - # current_account=lambda _, value: self.on_current_account(value)) def on_current_account(self, account): pass - # e.g. deleting the last account, would set - # Controller.current_account to None - # if account is None: - # return - # address = "0x" + account.address.encode("hex") - # self.address_property = address def _update_specific_text_color(self, instance, value): pass From 1873722783ad2d0b1059ea39f380e928fe178814 Mon Sep 17 00:00:00 2001 From: surbhi Date: Tue, 28 May 2019 16:42:51 +0530 Subject: [PATCH 008/306] Added Enhancement for Sent Screen and also manage KivyMD with virtual env --- src/bitmessagekivy/main.kv | 45 ++++++++++++++++++-- src/bitmessagekivy/mpybit.py | 77 +++++++++++++++++++++++++++++------ src/images/avatar.png | Bin 0 -> 27865 bytes src/images/drawer_logo1.png | Bin 0 -> 2041 bytes src/state.py | 10 ++++- 5 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 src/images/avatar.png create mode 100644 src/images/drawer_logo1.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 8f167298..62d3cbe3 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -51,6 +51,7 @@ text: app.getDefaultAccData() values: app.variable_1 on_text:app.getCurrentAccountData(self.text) + on_press: app.limit_spinner() NavigationDrawerIconButton: icon: 'email-open' text: "Inbox" @@ -60,7 +61,7 @@ icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' - badge_text: "2" + badge_text: "0" NavigationDrawerIconButton: icon: 'message-draw' text: "Draft" @@ -127,7 +128,9 @@ NavigationLayout: BoxLayout: orientation: 'vertical' Toolbar: - id: toolbar.. + id: toolbar + opacity: 1 if app.addressexist() else 0 + disabled: False if app.addressexist() else True md_bg_color: app.theme_cls.primary_color background_palette: 'Primary' background_hue: '500' @@ -172,6 +175,8 @@ NavigationLayout: id:sc12 NetworkStat: id:sc13 + SentDetail: + id:sc14 : name: 'inbox' @@ -388,6 +393,7 @@ NavigationLayout: id: grp_chkbox_1 group: 'test' active: True + allow_no_selection: False MDLabel: font_style: 'Caption' theme_text_color: 'Primary' @@ -400,6 +406,7 @@ NavigationLayout: MDCheckbox: id: grp_chkbox_1 group: 'test' + allow_no_selection: False MDLabel: font_style: 'Caption' theme_text_color: 'Primary' @@ -445,7 +452,6 @@ NavigationLayout: id: label multiline: True hint_text: "Label" - helper_text: "Label (not shown to anyone except you)" required: True helper_text_mode: "on_error" MDRaisedButton: @@ -640,4 +646,35 @@ NavigationLayout: AnchorLayout: MDRaisedButton: size_hint: .8, .6 - text: root.text_variable_5 \ No newline at end of file + text: root.text_variable_5 + +: + name: 'sentdetail' + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(400) + padding: dp(32) + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: root.subject + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "To: " + root.to_addr + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "From: " + root.from_addr + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.message + halign: 'left' + bold: True \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 05bc3186..7273aeee 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -45,9 +45,7 @@ from semaphores import kivyuisignaler from kivy.uix.button import Button import kivy_helper_search from kivy.core.window import Window - - -userAddress = '' +from functools import partial class Navigatorss(MDNavigationDrawer): @@ -108,9 +106,9 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses(): + if BMConfigParser().addresses() or state.kivyapp.variable_1: data = [] - for address in BMConfigParser().addresses(): + for address in state.kivyapp.variable_1: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) @@ -125,6 +123,10 @@ class MyAddress(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) + try: + self.manager.current = 'login' + except Exception as e: + pass class AddressBook(Screen): @@ -259,10 +261,11 @@ class DropDownWidget(BoxLayout): return None else: msg = 'Enter a valid recipients address' - self.address_error_message(msg) elif not toAddress: - msg = 'Enter a recipients address' - self.address_error_message(msg) + msg = 'Please fill the form' + else: + msg = 'Please fill the form' + self.address_error_message(msg) def address_error_message(self, msg): self.box = FloatLayout() @@ -369,6 +372,10 @@ class Random(Screen): ) self.manager.current = 'add_sucess' self.ids.label.text = '' + self.parent.parent.parent.parent.ids.toolbar.opacity = 1 + self.parent.parent.parent.parent.ids.toolbar.disabled = False + self.parent.parent.parent.parent.ids.sc10.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) class AddressSuccessful(Screen): @@ -409,10 +416,11 @@ class Sent(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[0].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 }) + data.append({'text': mail[0].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, 'lastactiontime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -424,6 +432,16 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) + def sent_detail(self, lastsenttime, *args): + state.sentMailTime = lastsenttime + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(SentDetail()) + src_mng_obj.current = 'sentdetail' + class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" @@ -475,9 +493,10 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() + # obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - sentmail = NumericProperty(0) + total_sentmail = str(state.totalSentMail) scr_size = Window.size[0] title = "PyBitmessage" count = 0 @@ -504,6 +523,7 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() + # self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() @@ -535,7 +555,6 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": - # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -581,6 +600,19 @@ class NavigateApp(App): return BMConfigParser().addresses()[0] return 'Select Address' + def addressexist(self): + if BMConfigParser().addresses(): + return True + return False + + def prnttttttttttttt(self): + pass + + def limit_spinner(self): + max = 2.8 + spinner_obj =ContentNavigationDrawer().ids.btn + spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -650,4 +682,25 @@ class NavigationDrawerTwoLineListItem( pass def _set_active(self, active, list): - pass \ No newline at end of file + pass + + +class SentDetail(Screen): + """SentDetail Screen uses to show the detail of mails.""" + to_addr = StringProperty() + from_addr = StringProperty() + subject = StringProperty() + message = StringProperty() + + def __init__(self, *args, **kwargs): + super(SentDetail, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method SentDetail mails.""" + data = sqlQuery("select toaddress, fromaddress, subject, message from sent where lastactiontime = {};".format(state.sentMailTime)) + if data: + self.to_addr = data[0][0] + self.from_addr = data[0][1] + self.subject = data[0][2].upper() + self.message = data[0][3] \ No newline at end of file diff --git a/src/images/avatar.png b/src/images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..b006bfa2a69bcfce8d50e0ef220452aaf490ee8f GIT binary patch literal 27865 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 IM6N<$g4k)%&;S4c literal 0 HcmV?d00001 diff --git a/src/images/drawer_logo1.png b/src/images/drawer_logo1.png new file mode 100644 index 0000000000000000000000000000000000000000..4152cc40edce2815f0acd9ec48d233dff917ece3 GIT binary patch literal 2041 zcmV)-76pvCA*me!29MAo7ZEa+u#oN zQvd)5OG!jQRCt{2o#~dNAP|KGj0?myny76S^ZpMxnyob;Cex_E;rsML}7X zk&%&+k&%&+k&%&+k&%&+kp^;-Ly|aazr{>SJUcuC)Cz#o-PL+=Zv6@b5Vvf1A%tOo znra_A+qK_Kgra>zFrbAnA*8fVc@nMtihom`5yaqoaY6#it6j&cezr+SIC#IGEg=}W zUY@M|zF*6OJp0k+3_xmoi9)^8{=|T9m~HO_jazJD1u(ZM{2K6qi6F$;wetM68MxYp z{|neNC&^lKCX$-d{UhL$6B2^l<6geOwh{yQz--NV4&B0+$ej82gUlpm+dC0xPPG)h zGZN1C;)Ly_(p+|aw5}`UvivlGn4K$>rN`V~t9Qo1tbk8W4Be75#-;|yQjXA44mFWME_E;=eFuLiGr(6ZbKM3Jt1981aH3$feq= zM`(GRX&=(jT?GlZ<3_|6y19acoX9d}i0c&SaNy3rnIXtr3 zs!2E!&tPuus!7O5ib z+tbRihRPDY#WP5*AK@ST9oT+p2URCzZV~>fI~}JyA$O_N z9fen&5J1kEbf;SqD^JLcI$<3M$K&@_a*JxHPYBT1vB(S3gbZ;+{T! z{|`b@7itJ2WV@%&Ekzv&0by-ZJa-heAVeAcbpLr&K?_0v3+m~w92-3d0elZ${HEBf zN9cTel$%FLg@J!FY*r)`X~Xxo>ZQ8rLWr(|-n55vrFjR;?Rzx%;Fq!HnB)e{XbYtV`Ceh|+phOUH8g!i1%_mfas z5dsv^2ch&L#FZ7jpSjeF5WoX_2qdr-{^WwNQqWDb|4$f2$szXrxh}$b z3%xE#=!RiaX4$Pu5{B@b!YyA3Ph=U-M|dxDHNQwb{qpk=E+uLoOFKfwcB@{5Bd6Ro zA`A}G@2)hVu(?87!s)bQ#R-upheldLC~7j4l@K-J0Ocg)ogmhN5bgv5%1DT(PpGI( zh%&JyXQU%UXTilkWh2Cy=<24D5yGqRsz_21qJVkznKpz7UPaD>vJoN}Ttp@3%S71K z{3e71Fth8q>L;&2c*lYmoXe|Q75mL$)(Uz{5u%O@64+vesa@2$zf`%|c?oX?9bxws zhUvvV<#FOHUgUZP!p>ZT+`3nJIeGispQj|=!i4D2yHHj(p?j=<{DUM#kA)B-k~OYf zo%TO*vTjvehC~p;)QRM&-ux~BggBHJ&l)8}kA8)~WL-AYNcUk5G$6cBS>52?q;0?Q z+HU1cRkRkpU==Qh+^1p^1Od2Kr=lI)lc?XV_@(ENsLklvai5H;s2-|C#`^aY*aaUeZ}( z+IZUoIj>k0bT#tTdV0BSl81i(phvV#WJ;uDx*r-rrC!cxUpLoVc&?I6y1Cv+GjDsK z?gj|$yzPN Date: Fri, 31 May 2019 19:47:03 +0530 Subject: [PATCH 009/306] Remove unused print statement --- src/alice.png | Bin 0 -> 669 bytes src/bitmessagekivy/uikivysignaler.py | 4 ++-- src/bob.png | Bin 0 -> 640 bytes src/class_singleWorker.py | 1 - src/dave.png | Bin 0 -> 650 bytes src/debug.py | 1 - src/depends.py | 3 --- src/eve.png | Bin 0 -> 651 bytes src/helper_startup.py | 1 - src/image.svg | Bin 0 -> 704 bytes src/images/black_cross.png | Bin 0 -> 5201 bytes src/images/left_arrow.png | Bin 0 -> 2444 bytes src/images/red.png | Bin 0 -> 57642 bytes src/images/search_mail.png | Bin 0 -> 10555 bytes src/images/text_images/!.png | Bin 0 -> 5035 bytes src/images/text_images/0.png | Bin 0 -> 7321 bytes src/images/text_images/1.png | Bin 0 -> 5027 bytes src/images/text_images/2.png | Bin 0 -> 6916 bytes src/images/text_images/3.png | Bin 0 -> 7265 bytes src/images/text_images/4.png | Bin 0 -> 5891 bytes src/images/text_images/5.png | Bin 0 -> 6831 bytes src/images/text_images/6.png | Bin 0 -> 7644 bytes src/images/text_images/7.png | Bin 0 -> 5941 bytes src/images/text_images/8.png | Bin 0 -> 7777 bytes src/images/text_images/9.png | Bin 0 -> 7733 bytes src/images/transparent.png | Bin 0 -> 24650 bytes src/images/white.png | Bin 0 -> 82182 bytes src/network/networkthread.py | 2 -- src/paths.py | 2 -- src/proofofwork.py | 3 --- src/pyelliptic/openssl.py | 3 --- src/shared.py | 11 --------- src/suravata.py | 32 +++++++++++++++++++++++++++ 33 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 src/alice.png create mode 100644 src/bob.png create mode 100644 src/dave.png create mode 100644 src/eve.png create mode 100644 src/image.svg create mode 100644 src/images/black_cross.png create mode 100644 src/images/left_arrow.png create mode 100644 src/images/red.png create mode 100644 src/images/search_mail.png create mode 100644 src/images/text_images/!.png create mode 100644 src/images/text_images/0.png create mode 100644 src/images/text_images/1.png create mode 100644 src/images/text_images/2.png create mode 100644 src/images/text_images/3.png create mode 100644 src/images/text_images/4.png create mode 100644 src/images/text_images/5.png create mode 100644 src/images/text_images/6.png create mode 100644 src/images/text_images/7.png create mode 100644 src/images/text_images/8.png create mode 100644 src/images/text_images/9.png create mode 100644 src/images/transparent.png create mode 100644 src/images/white.png create mode 100644 src/suravata.py diff --git a/src/alice.png b/src/alice.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6c6a928b708897009c3b211e6825d252fc3389 GIT binary patch literal 669 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic4M^IBzMRCsz?9+Q8b-XjVE4hJ7M zv9>6(m~tGv^iO$F`XbNoFM1l<^lEQT>)2s;ApVyWBZq{5fkFZZI~-_ea0FsT#%3U9 zW@2OE0b!7WISZv6^=i*wc^;j+Lq!@W0MX@e0HO=71EPyV0-_6MESe&iu`opzzO}cx zzuN}S&)=F@$A11i8{A@;3cRi(s3>Svx&4OsnX7Enet+M7YeORr*K*w80EGZt7TuXR z9q~z1uu#%jj&{Mb_je=EaQ!{E3SP5U-~OJ?+#H{Qh%8`4p+**J+(2R!t_T)4$chf= pdbz|LV=x1!0kp`%jL{DZ+Q9Jf(;5h43330 z7d1>T#;$t6Y4)&3uw47X13_<>HOxPjT;^~%(9poh*bKzXOl&MXAj}~F!U6^g2_Oto z;D}9;fC1Txn3>vSW85aZaeHg}_48RXnMu5qSqgMIvh%UK42L3z1IT`aD}n_A#E%XK zHcS^1e0@=R;q@!}Hn$62S?4dAUt4cx@S_z=fI$o-Csb`788xMtXRTj3KY!c92|2*P zC*LfP%TZ$}(Ogw&nqdPduwha#3m`F!;`==>*bbIT>~CJUvm2PQ7(8A5T-G@yGywp< C&zlec literal 0 HcmV?d00001 diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 33542a73..55ecc63a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -52,7 +52,6 @@ class singleWorker(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="singleWorker") self.initStop() proofofwork.init() - print("I am in single worker 52.....................................................") def stopThread(self): """Signal through the queue that the thread should be stopped""" diff --git a/src/dave.png b/src/dave.png new file mode 100644 index 0000000000000000000000000000000000000000..e8d7bd0b004741caf27eb657dbe0a66e72a8f2eb GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic4M^IBzMRCsz!d1|;uunK>+RKpyoVJ;Tn-BS zbXk1Gr97I|-Gg;sB-gfdtqtK-e+RKpyoVJ8Tn`HT zbXk1GrF=hE-vq9r4iQbhGa(83Rl8MBRx#AS%w$nWa5&J=;0VNwjLb}IAk4x8!Wv8@ueDm&3YGweepB6;gR*&<~0SwgM6ufIvX%Q2D!=9_OFJM>8|)fPMlSQiBZy*}#&Q&)e#8{y}{9@5P}a zEv9%nn_?Fz#@vZ_?J*#(mA1& zU-YVp_xv7_FaGVPnp#ak^qMIq&Qx&!9+}rjQ0aQxvk~jS*}mi?FW&zinKwI~tu{n; zB^^&^BX1|QzJGL3zRWk`YmkvXi`Y#v+VWWOG&l5b)xNva@BE#(SwBm)>i*pNPGu9= z>+dmn>6;m(mvxp=-_&{V0obsi9_Js$-_Ebf`gtnW%}r7^w)^*he6GKxye31mb!(v? zm!{U;;Onbn^3}gJ@<5|p>U_iN?_v3M%nU%8O6FKoi_bTX&adYuZAeY2#9zCm_QY$> z_p0CdJN$ZnvX}CyjeI}mqZ^BrN#$PkJO6jQ#?+uOz2tG_Wjo1+|DwnFf8*bskBzT0 z^jb`p^L23@U+qr6^M8(CoS$rF>)*QEGa2m!wBIYYH~r4viJSFvo@I=euTtvPg7-&< m80AvCK*+Jx+yUnU0nkrlDpx$5Kw1 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 literal 0 HcmV?d00001 diff --git a/src/images/search_mail.png b/src/images/search_mail.png new file mode 100644 index 0000000000000000000000000000000000000000..7b38e9b40e3f57aeb8d27ac00f77cb1a3cc151c6 GIT binary patch literal 10555 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/!.png b/src/images/text_images/!.png new file mode 100644 index 0000000000000000000000000000000000000000..bac2f2461db6556140398a6cd73595b7e30d603a GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/0.png b/src/images/text_images/0.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8b63e3a79f5359fe81085211f5bd2cb84aa784 GIT binary patch literal 7321 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 SCbXY#0Ha%`H>-6WBmWD_4en|H literal 0 HcmV?d00001 diff --git a/src/images/text_images/2.png b/src/images/text_images/2.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf202e95b89b345d8363939a8ba195b05cfb542 GIT binary patch literal 6916 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 KMNUMnLSTX>U6tto literal 0 HcmV?d00001 diff --git a/src/images/text_images/3.png b/src/images/text_images/3.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d612dd8b00cd754006110d0365087fdb3b32a5 GIT binary patch literal 7265 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ñU+Fza+h~R5vpg8_LIVMa5TU~B_MS$~w*1qN_?($zvY%RD*Nq|uP0|UrN3ZDTv z(Cn0g;-{LQ^BS>jY4`1M5HHP6Ai!^+sq;2jK*Gn8a7 zzT6~1N?@280ZlMFrJ`Waof@}*UY%?*kA5@pZJXQqm`|}XX@<_)7w!^8IlMeO9Olo+ zV0+yuL}t4miuV{LTG{Qu$^l`Ebgm0TN?oi0C$^1H9KbPe?N?k-FxXuCvYR--{nZ(c zBtzlj#0%$)xT)TF>`QahJrkPs{qTPR&;e#{%RuKlypLMqGrUsL%tSf&>lL@GH%GG1 zeoL?d2bO^Y-#-^P7o;fPZ54T8lAsP5RvbAs?azCW`ylOk_Hul>`2Gd7dN}%U(lUaA z;_a?q4Zd*8oO9QIVBXM%W&G`@NkjnSc88^kCtZiim~Zn(ckAsYvgrRuLR1N^(9D1g za;C33YzXCm?{yC~Iv5xJM4`7U-tKzO@jq~F@3h^%DFTmKauy}{#pV*iA^wauF30kB zdTFe{|&MDJ_KWO$Ar9e`rECPIYWy@Pv1iELwx4f z`IW)$X59 znGE zE%w_++WE$>P=Q>U6=HH>g30nq^;g}8@^p6C$ncZee2)0qn@;|5U_~2tEI75Dc1nvk z7V?m)J;to-<`mpFZJ_@Xxmw@(u&+Mz2IKw3$|Ao65tFN75{L17F_(K8yEjQ_L7;6^CIp1+!zjbOy>nX=yemXP$m-BmEeEl91hv4;Bl zWuTEnFAf*qXU_(nkcIkUbWN|8Si|dN3rx>U1Mbrqk50(LT9YXMjAmyPd@CZ6`{X2V z<1ukh9M8g{{(F9ETVok2;}-fGc{Lrt`MgkaUJ|S`!q*_@~*%Dm^i4oUhTzvH}{>Kslsk5Bw;$wbBmsl z#^AVNI=l1uViI2Pkceo3nJ;ahD2<}z=ht>A&7NzLIneY%p=w>=&5tO6u9m)Lt%hyb F{{ionjlKW? literal 0 HcmV?d00001 diff --git a/src/images/text_images/6.png b/src/images/text_images/6.png new file mode 100644 index 0000000000000000000000000000000000000000..e385a954ba4c14f366fe1ce4c8c848d5351207d3 GIT binary patch literal 7644 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 E2Ua8%FaQ7m literal 0 HcmV?d00001 diff --git a/src/images/text_images/7.png b/src/images/text_images/7.png new file mode 100644 index 0000000000000000000000000000000000000000..55fc4f77d428bb159e85a6516fc53ddea20c8c3a GIT binary patch literal 5941 zcmZXYcRXAF_s7lJp*A&ws#R2L#4f6$YOmTY^-)Q!+Iz&_rM0Tm-a)OJv9&Q`?;WG4 zU4#VRe7@hu@2}q<_ul{R`<&PFbG6XKy%62BV zUtJl)6L3P5Z{&?TSyDzvShWW9AYG$MvOGlsmORVnPPzAj30=KSbh81ol-h|4cbk=w z6LLXvq%n|B>oaz>RdNz%k5XN}Qt~fw6Z(yNbb7^DWkc2Go#E_E=;39E7DXANLcqsF z6j>_1rNQ{AU#|_S_=c6lDVamhzo-T-%0=wWDKZ$JI#1JlCV$L8K^BoCMx7!}PBsG4 z;VDL*t*Lq9)H6=H_qi3^l#CHiY)0#h>6!h?E8iz)|DyPu&>+#bL8V(O>@`Fg(UTX8 zeZt?k1JL%C-EkZs?_`Dvb?DN&-c*~@Bvj=8_HU&(Hli+UKv8fS`lC38sEdZQN?%3z}GB~c%` zlzuVsq~Dh2O7z=Khgs)a!l9A0E9Ookoa%v0&FIA2d$0DpYbmxm*m)G~e_+UmsrE}V z9km8FD?lF9H`^ImHmuC{1@Ez`lQVXoRS(2OUJB^Oj?O6jKq-Q@})S+g5Yb^`OaCSPwW*uQB&KHHNI5;_NiMbA{) zy(Jt5hJ2yaL!Z#@tQ(mgh`K4yfX##BF4di@FWYmwt+m4;Noj&p!R3q60-8@3A8jG~ zI@_JXkEFZE_O@F-K{wTMVLf+_E42+;Zf9F4%U@+{Afpb|=a+`#a-t^733AJGIYgW) znDg|aAC<1<7&N2^Py0oo9j4m-WgN)jIgz|~i(`xm`dQ6x@1K2(yhn81bYQ7p;ba*BkNv7c4Bczr=v)g^fkQ>z;Fj6Sgul5TB?s=3>2~ae9w?dy|s39mrX06YN zEdiVGFI1Wc18jEytm8ZVs-~V*%+~rObKbr~plC4IpgiK)*--*K`v$5R^4J zXT;LASCi4j0$MiKj{!QRhN{XB4&8-_4K7F8)FT_A@tt5@spm8w67OBXu&X3bdP{b7 zyW|V|t8g`KB6a*y9%|9rn8`TNe}a3FI$a{W&rV3*7!lq3nKXU&(IDxAkFx{$oS@Wc z-U*Ur`yM1snR{_jGKf3e;!|GY2Z2nl9P`=cHV?~&V}nqAYS?5JG6Cjc!q`8)v>jO# z1V{2%4`30gBbUFea^n0w#tN>be+SQNumtUtKFXte&S$XF~e{Nq}ElgkYer&St~=Fk1g zVUrXe*|RA%W%O7)hmxuTl)1>Oi&n*7Hopk`i{pQ|>JA`4DLQ0#;P`UBbn;xL%6INK zV1pxzc>KaZ=*1%U_sIrsiHyqibjv=BKh8>`_6zQ`q4_$=xXnvS5~&h?TG(Zws(&JMJIWW*~#>u>8Dakk{qW0N`TEW%`gMfr$IkY^nE!BWDcwN27jr7 z`)n0Wt?rblKGvONEMb)Z*oJOZ_%_*6X{>VMm17TSh$ItJH)CFs{^7?x&I55;l!3HE-?Jg`gWgA7)Owx0&a5G zg&M58IU4BZ+hmzLbGV{Nuz2z6qV{3@N>U{;J6Rc5bI?t?H9^}kr7xCNk)myzVIQZ5 z)!J0EmjoEdelU(!_Mxc}4bb_U=@8l!L_RwwI&-_|gNVNm7QI4 z@+ZI^k|5lej!vlT?GZurn5BhCPL#nnx8xTpR*4cfeJJAPbH49hq9H3cf=5*jSvpBd z*WwW~pr6z{&8Wi;E}z7sbnBb*C!L&08x05{1txYpN*Fb}ezc|=MbN~m&c(eXB4xK{ zCfj)ep%=?@mAQ~$2HzFE84!3g`tmr}TkHrvgPfm}rE0tG>CCL7anY7?i!Qs=V@rS; zCC+YNw{w$;$v%W`Py2`5`aZ6{)?U4SoB{$DjPF*9a)?#AC9mC;TdVfHdlaWE2u0V~ z5HH`BwVlgElt4ehMey&4&EO99r}8WY%>Ka}$oFG?xnjB&2A=XHw!|HCpY5 zM3yH+IrJ{g?3j+YxAwPxomaJPW&ZduQ&;>?2taxu%h5E{-f8g`bYyxlpco?6$5Xr| z1$eABin<)ACLUqvRqz@iLY&st9|l4Anjhp)CP*j-2`I8i2#IyM5IKW*lYHB5C)}pW zw?Ms<0X@qTAn=mw#pI{! zCG#sr%i;xY$!y)`tE5q(D{aqBZdMTFxS8XBu8pu?h9;z5%uF>lxXFuosutqCJx+7e z9=M%E7zHTa%LWm*?VWpFm!YW}PM`XS?wkTYqhqx~YJ*arWO4+%C(K3`V?07=JoS#FKpY{7J7IdZH{Y2mIgPmJ+aBS)HNqi(60h&C?|1=f8$LWJCBJ2{IcP`3Pn}r zu>M`ho3YF}`LLWEQ|HAGyu*4>LfhDgiI|vqRMPm9;}~j+Tz2!Eh6jsjONc!%u6^*TQr-6`x94;>f%H^FWu_2g95K}DOA)LRh{x%CE(?;)e%WSbj@T|IG&cx%APy@li zfoEIvWcbVm-QCOFk_j(+wh5H4)_ttFn}VCark|iiR+7B!RaZ$0OUG4N$EpPB}(a9=s)TH`;iF0Z8$r2_T6itX!c-nxEh6Bw(aNzeg z!%gt}sJW&DQ^n8ksR!X!`US28ou28)L8Ws^SKPurj@@{Gw8s@v)vt1Am6nSD?)N6Z zQt80&6AIr6e<;YL<9l!j;)L|OX{_8LCmkJdf55bZ`w$tPOrN|=Np1Cevg&yP6k-AP zalExVmfd9{2sjb>eh!W28~VCpVbNuVA5aKz4QxawM}|8W2Y~;Bbzj(|+VCy4e4Vu2 zd92ok{o$o>uDC2GlX^{XI$j2%+wN_6$GTWw30K_3=k=?cHe_}6nQ!u4V4wu7r#+P6 znLb&eb>)bbUJHYlx;CDcaxxEa1=J859Iji~Vl+US@3t-5V1folTn;|@ljM(JcdJ*D6q6VUucP<)s~_=&nlpO*{Ln3zX!Ii1?Ovw5}tNKi-45 z7Zyb?Usx@pI={l<6WchWGr{J_fZmDJ&O7WYXH1#U*JoDiS4k-$|7_k;j6K57kV>6j zvai$zR9^9nfue1B8O@lk8^fW~9_O?PP@V|2}huiv9 z-ro?fyIjl~zXZ1DG`N}KnuQ3)$YplG(%U}rH1 z_NzzF2LDu5*tKr=z~~}ld5jwM@R!g9mnAeEB!H_IwES5>K~Q`jVWMPGT%8*n888OY zh{ao^pQ8vvu=Ua=CUQCK|61Hx z+Hs=pX4SFfjo~B**{|O{M6(w~rj7(#yq@2U;^#(sEYU#CoETWW4%4@GsNT!I5*-xl z40=O!_zQ{h872jnjRvYL&j}N<0&jYhVtF%`9C`W{*MXwslgYbD*rOQ3_V=d2F7BOW z4KS*o2XH6W_10FeTe-egkNArvAAmN(yXWkr~OwUc?FU%ng05S!q?dR2{`Y={>I-h{SL@FpS{odrhj)bqFf*20S!Da zGe(v9zJALD-AtiTZXHX%__#i^uYOrd`2fF%6_C>`Um+>(e;3-F2UBKDS<34HXkGpW z-`~Hu8~^gGUMj2X3_I`p`WYeNI90y5G9l=0>6>uB$Bf;##7hr3bAH69vf92VbIy0ZJNKD8Gw+@G z&HR>o=d#(CC2)Z;{y#~~=R{hZV~qcGyYw=3d8oWxzb&t5TSI(e;&Y&!QX;JAmnM$J9AuM%4YOyn2nCc7dWAx%ggNlFT(W_0W^gtO{k8 zUjyPwlLJF#%;LH-sO9>qQ8u29jy9K&%CowI*Q!Mx*OU1g1trxK={T-18W?R5AE@?9 z$+|YV4Z34nUQIhyyTSMRTzo^qp(3s>8aQnb9dyRA3pQ1*2yePZ9)vD0+}Ofn=Uvz5 z=1cT!m5Bs#RpB;>Pv@BO+RA96^NFii5Hn_g!XXgE{b>?I>I|*Ua@5r#ue#y7p32*< z(fo!)m#@imz(OJ*S{;5%OGHY=q6Md>^Cr>X+8dTg9wj)nL#Gs~o$i+Q2T#%jrHwYYqAikapj+ptAtY z%;tIupeep3_Zw*GYBB`yS=iRWx<@0ZtBfu_qMkF&sGjLWZI`U#sBMscN7H=E&?*~c zNbaPf9xE4oXIWy}xl))O^U(e7CioVk?>%1~z(0mjR4piRV6=aTwF71A`MRjFj+g7T@QHkG0A}NUM_=|(Y0qM*X_tZOD#x;NC4k;-8xcJE&X6C{8M1(V zMplhWu_~zN_He5TX^^8~dWLHA(hVMQ4_)k);FMc`%L76)-WD49sdI^Njs zh`vLxtI3dSfKeYs;i^^dAx5fT84UA`aHz)-tweCPiPMYa69i!!M`LP#ttSCS+^ zx0@L2lKF_%A*haZzLQ=gYOWgWI!~Edtzy>e1>Y8X#H5zWP`!6HXGfp&31eVQwojmv zchcp`__2NDj`GG#?&}B7vsH9r>jU1JqpbQ}`G$0o1lSE@T|OIhyNxJ(;^2+f`?{1v zrTh+2c5sC;BDmC0)s+Lp5 z>dkQaUKM-q`pkfG@#LHq=mayMSuhtLkwRs6i=<-dGKv*J2!P8&#RbUi#S%2Nfkg(A zYbgySt&0m$jmQDwdv90QP`|Kihh)NZfeL*EEW-)I*)|Z$NN3y4<1y+WYg&b}*>$EB z*rXrZ>WVy_?{@VYkcd;Ic(Fu*YCW=@BDYUH=Q93%odfb4lDc-u=bPp!&}|K$7NUXT zlQPS9Z9r1W&Wb*ls%032C>Kwec|+y})KyoG`N;pp@c{BklJGc58RhHxL!@&F2u1Z# zD`c!E`8r3uOLJN&3~a5tI?+Ol*;=WBc$nxatojZL;Z9sD@_b z6?#+=%3Hq3BOezs(nnJeLMC-|YEuQ*Kq#74(S|sP%exZO+H{g6>MZS7o`AUjxm7I2 zdVg|(>ai~E$}i5@1i@x+v@H%|g6sOo7vq5fUM!2cLsEp)!LK$}E#Jkf=c`cXs^$fB zlY^=rh(3sXh97&E#P@n#UzHsPNkrN-z~u(2unig;@4BuZK)EM6;g7tQPcUi_`&_R> zE)`2&L8xkiEU{_>Z7ULm*Bv*#Jp1xKofc6a%8Y}g40EdBs4I(FH-*=!BP!Pqd_<`j zTSdGsO465=6$eSw8PKHD)rGw3S}1%(De%6_b;dzRLgG>_D5{5SbotaDO4?-8sZb5g z$d}8DJo0fFagam^nNA&&E43K+h0vL>b5k`NasP|P zLB{M3oBg4aR+qh^vn@l%ahy)Q&~lM`JB9(xmL80_=s>} zTtOTinE8N>?RwRSR#%pyJf$5vp>_#X=Rv$L7_eM*y;M55{Q5w0x`@_GPB~1>+d7{|w;Z zU4Vmk1?KDk>^_D6O_=~}H^lGw@K#{aYT(6Hz|$*$1ssf^?923{Ov#*UC=TL`ufxP4-~;;t@7)VHc`h(*yL{!0bb((l1@2r7-0~u@Xibk( zJ$t$dFY;QRiE}!zIhQ9!{YxsS59jLUF?Sm9iKBos59F&u*?8o2;Kxq^KYI??+6{I9 zhR)js#I=GX(zoJ#Y!H{~RTdxO3bpej;Is39-#r)@DsBIKGnNkn-+dIgdI7L?o7ryD z-LuF8Le0|IAZ*U%N$O$&sgP1ukE(UeP;lD*z*kQJcHF-Hx)-ehzH}#W_bYmyI;jmH z&(wS(k86G_O|{Y*K&(8zX$*CMue}$z^3-O80|54#4qSUC@YnC;&VWGOt0D5KobtHp zmtw;CVx>G+ zc|27*zHLJCSMLN)d0Vq>aN#|B0iQoHdtOzc2bH(kBEV=Q-89f$?p7C?9>7)NL;C@L zbY!tIUSAK~^9u0zGGNI%VCh=kLpx96e+TUh9JdE>*sj3%arx`{PVu*t{-#Pb%%fK$m*NH1W0L(wY@0tX__0IrbzZY1! z!H~x#^a*g*+kr2h1ne@&uYLgd?jyjZcLy1V2!bC4lgFCQ%r2l*S!yj9=LjVZa^&v7 z>7K%|bRBTke*=Gcn^`z0NC5og8Q@*t=Z}~8;$w#cGpCG}KF38(#1$PklbD={Q8wyqrfJ(@BzzgCy!jF%HthnFrEWkC85L z;mzDAE&|si^rbt1HJj+=?KCkRx1mgOZRXW6I+`B4%BW&#E-Ku(eixEc_oe5(dI7ND zjr?_~Dz1rNy$QJX3BR)6J(pg7+j-ac@3@wyA_&FnR0ejM$lnB{pql{Sf4tiE$naIO zj@Z4LcC-;gK9>F<$3YI?jh^?e#lWj;i`AF%#aldhNdi2-5?H$#*n#+_;@&&@l|LxF zI;M0sh_)bI9-r$(KHYIqzAo%Fou1e9K1Lo;3`_u6yoO%pjEVdqOP}%wftQVSk(SNu z98O$1Y*JhXUp4mFfu8q?<<+%AKwaI}ZuYx=x5uevnUWtnC`z? zM;^W|A(=IWp7+@|%d6L8tmH|GO|I#6Bdlg9g%D^#+k;}A{rIvYer zjDryImPasd-yMtB=j-S9d9rxL2EO}A2yuv}d1@R)o2BRgY)T!f0zPir6K7Y~4ikJ< zt*2{nBD4fajDryIq{pB-X%4qTR&LB+pR5PlJa|b0%$(}yhJJFnU-^T=$2dp{%$uF=N-m3cPIjzDtX?a!1;&M%NpqdS3O2Ae-L;% zk2joWc_GNncQGLVmIr)5^)kSut73G@}!cQLuT>OrF*DhHH{NM@T_C>%8 zD|_eF-!x?caQq(pO~&~L026X<9{0d&z}Y|L#<^U+s8j9h$V=Ru%lT=SI#d)c1G^~S z1itcazLic9tlYq#{#~^RSiO<&JhJN~9{k&XM!wZX#`7zI-?<)mYcqXP8&qD-C-OL- z<}C{*M}V!-K714So4fe`B0@4_5|6xBfyHZp^M1~SLq*erF=Spo=Zu3;jTslzGLj@6 z$0*7-fds&p?*cBq&Hr)ps`0CZz-iY3%hv1r&J_n3G~R@coLRkCMQAEcD7gL^;ItnB z4=icACBUkUz?bg?F1RuMmZ8pmlriYMQILcUQa7qtB12fVKY29&1X>fg=M~_SHx=KD zE24*5p2f1MYA#jIhp(bcD&GNrCh9ZCmvz_tanc;%f6f8UIkdNXqD~udX$ynSr}9?4 zf}{sl@Acg_VV@m&#Qcz5n{G)DFRcQ;a69nOQl6IkLFfF4JhZ4yKt!WV4JyK0{n!<& zU?X%iHR%5+6GpxaN#7g#+Nv zf_>(A;EGe-U#N23tG4p4>uR+@DEW%;b>i$pc%ZOoAg>P0KLEJweXu^eRrKEXE3ea3 zWKz-`tOJl| z@Qg95i&!0OdH9RwrN8ax!n1F3;do{R&Bd+4w!(;XHvztJFYuj5=j`P9S?%^Np@xi%=0@DJG z--LulRje{JqpF1i;2R`RcX!{gl|L}J%0oEJs|f7|brb#?@CJ_!wkM1$zT-;Upj**v z5fGix?c#lmc53~3_=!Wn2R#PTKi&`gW>q=$3)M00cFyX_i~(1?9q|o!@>-c|tIPrSaecqlt zAW1F1jl9TXLM_i?$;Yy^igWU@%!{;(r`Df`pYO5n?YAH1Ze8E{ZF$o7kEQ;r{Q4~n zzgkFbEjK=olD>HBD!+}qO9P2<5DU)$96O8l8#j*tzkEJ_{WhoqWJ~|=i?sF%9JZTZ z`E5(PCa4$(vEaa+=^Ier`)avw@=;bt9qwA}7jrqx|ejn>Zo#RKHrb)Jh4pgIH9(!O}y!SkV?_dagb+L(DP0hSKhbL^PG@Y}1QxvERYj{I zO}b+}65}8ie*G4|8Fucp?8kJ9)bA4qnKT}_*z>#Ww=M*_s4vbCI-@e=IYBu4zr>c)LgwBgRCg=pDRHa27=&D;yHLhh|q+L9<{yhAR zFYpHdsn~u9xMn`z=#5&xEf2-d|L4a7XCF*&BLF+zzjxMD;AbBN4xB-+-v(8H#+(!2-%G#bM8Ea{z(3vZE`Jcxt_do}K?wNH!~BIP zAIzEx{Nilj{KMUOb#Qgu?o)stewc44;fsft@=s7lq!IVU%E>QX4}AAg+V7MxaR|8d z6yT>HO~06As#k_-g&98%xZp_Oj`Q<<9e1P)eDU^dJ!;*9$m`-DY|iDz*|(HwS+*gn zfUrfxv8dCOH!nYFJaF^5e(#8=xP1}d)ZyM&`Bpt@y*BJL5jg80;DV!i_DvpK{$N_Y zibx^T^ELqiN)i%d;fZ;$<}DAXMnC|*!NE^HTKtV4HRr1;oh=wjK80eC*WwqvSHvu{{<{t-}Lu4g5|Z-UW|iy@>f2@zwJ>r zwj1J~Gnl$v`NFY&3-GaD^n@d%I7HLD$YX-5D+((>CYPFN=9YPpcJb8u%i=$GEB_{W zKVZXF;DQ^)CfeCJK)Qbhj~^Xd#!(RCAUXJrTY*2k0k}JGAz8DDZ=!wwYw7b@FW}&& zU6U+DKnkrQReG>`b<}TlZW`fg%Tj{@JkpMQ-i!U^jFP`QBU26LGZwum?u zb(->4#ZQ?4d~P0(oR@86Q*qlu;P39{-zSM6qZ9!FN^tpR3QX+!U!L-SW&}j=GpF!i z-Z_W*?TV5YTebl=JP%y80C;+N_4Tz3sh(6PTA&62vBeou4Jn{v*;Wu+{Z;al#{=)* zhri)>(wySKMHwSq9`w8E1>okF_=`_9#0lESYlDL_d;|o@AtW{xsOq$<{<`=bwg=v^ z2XMk{;J8`9{xkfd;u}YRXIJny93NT&Jh&vm+Ra&sll}bab48KQ@C84%l}m{$kahJMbrSXHDV3!WF|j>b-0jczF%*;%eZPHRhY{ z?BK}jc=CE)i-0uXg>4Ne>S*M>d1m8f$Qt% zk2JIK>V&N#?u!*DD63;cxu`M@;#@^ksa3~x5kAI2B5&ZC&-GQuL9{{=;~)_Yp_EY( zzmpyS%qvd&RL78^Q)|l>kW5#n-EdiKKti;k(tu`ygX0 zi7K_~m@dM{ILN^B%)yh&Z|Z#zmLxqP=`|*sHxDmtk%)msrM+KQ97Ovg%FvA3AROiu zr+unp$tbn=b!u&$?}ISe<)-1a#}uAef8X&j4r1k*gZD09*B5nvA4DthMb#~j`h(|2T6IiRO4E;Ehs#-{!n>ao~q*jeaN#i%XeuYwd`s_@yHbQ zW>D+v2VOJN2atdx*wcBzH;~=c=`gMH~+IP~K=A2XADzW}XcpK7_LNIZNs(Ds%`I&ocLWu8!Fu{xb3J;a1 z)*mWw%Tv_P--mpuaSj*n(m+CugD@zop^vABqIQMMtH^roTAOACulG)?6Sj(w_r+o$ z8fk4bW+|&JM=}b zg%Ss$B6CyQAROiur+up9D1z)Yomv}G97KDpImdur%!FbPyM#1UzJ+lRCcAJ$YoD$! zLW_fF&lz~~EEIw(H!so?L@;rRJiPY%98I@Rf(9S5k1 zXQ8&wrGbPR2g#hX@Z#4dw!GB#gutuFdhPlq%?e&$d0L&YRfHS|@u(vKFy>1S(g5^@ zYh?)-ecKQH8V7Omnm9;iRROZIhKi(I7l{6?R@G!2G~AtUO?9uHMn_M#p!IFHh~eRAPGv-u3i_K_Nplp zOjGq&#@kT24N`^OVawygL2-%axV|*r)QJrb9_>dkYplOj#>aQV*UnmKBl` z%O|aN0iiXvMG@5UsEG`h;aQX~2&Vi6jgnWl%x`a6^=z64YF4qhOV<4EMp0gdi|>_Z z<*h0h;d(OP&`J{gB+xW!3lvrz{82%f9dgXDDsOEGrTij-;i;ZxTGOL8#di3-9r=#fPjGZxwhuZ+k5Z-E()^SwZa^h zM?k=H`CL=Y#5ZRb4E@Wil^b+1#O9#}xW|7-w<)og(U8bjlZ07Q$DHItsu$y=9h!xD zQdG457g`uBnn=`NJN|L{aH7JLF%8_s(iN#ivied^mony_<`?9%JH02T*OJ!3t_B8t z?RlG-o0*OIWtDB4&cM+LL)aaVL$GVO{s>R8?j`V%qNCR({+ z`9e|l;66if8i@#*pt`P`buZJ5OtUk$bYlN!N?{FFO>m&}zSXteBfNNo0HA42oS#9^ zisKExWJO#<9c`gt+)S~)HkwC_0aZRxxgAWf0dtyh*RiqT6(|80{Cp}F zG|mQjU}sFPgzJDY)LfG#d1u|pps0@B-YS^bE`K`hDyq1!f0Vo^prXpKpn(15YEFpR-rtsg50T0{m|1(VXW~0rKiKdfZnIg>=21UxI zCJPk~P|LO+OhG}o(EwGHnYP<^@cmk~0J5I1lV;Dj!VTuSzL`r3Fw=!TfEi?G7=qq; zr55e6+M{VfP+?b*A{?z%dgYL3r}|xhA5X9W@!b;Jk;qU3u1>MK*NN;51_mwh)sJ`T zh0|W_exrKE^taht>(vx%TOh!-t&O*BiLOVzbxmy1 zsoFJ<^O2H9rPEhRXi}NqFROj9eaw4|{_B<@jWhV{l7HN=e;ZjyFila}D+V{)QUsYobnXZbk)uY#s@)$rTVa?K&ra4_cKlXBC+SCIX{>Swx+r8H>&w;tY} zIheT6`e~KWS9#CVxdsw;pZLVeI($s$Q$d-bBP)mz($9XLf^mYLUr45C?ZC=ho~~R* zzI#jYYk}bY>cis2!awW>ud?rX;v1m$Ce@z24>@Ys-UE+6=Vgxz6Jv$3JLRuHkJOV@ z)hj;1U!XshnHRC>tCTIz!<9t}td!(RNacUWy<>UQCA4Zdi@sZG-V$f~jDcwB(9oV} z_0*O!Yv#8wQ(t{*_m_#T$e&MF*$;|J%DLWIPt`L$el1*}zDOYA*5THm7s0S;+g|G% zC*L)nrktLOmLX+m&e45LgSz^PRu<&^@Xr-#-iKI6VJnlP-YJ0+Ld;rC^lW)kl^ z*KC^n{N%9A;-|wXY}wu`zz2FfTJn-XU69su?*|nu#!$NA8@)S2y3hR|_3ww9TXgVf zApk7+JTz~OwINUi_obqe+>>%%>$7lsy)~LG-k0~% zTx&rJk#rr4Et^JTK1areyLpjHZF=ez{%T>R&SxN505$gkDV}Rvm62+lB*ly6pV~do zc9Lf)E6hBvLfm>E6&>!z|3=`+(ut6X_SXD<$;4O&s<29&pnnJxi&tVEmJcaAH^t&5tgEpIX?=;5K?0Z z_<|m~EhG;$D6Ascf`|hy)_11r{`6z+STEJvu3a%2ESl!LATGWJ%|7_kQ&Wy`<8VVy zBd?FLT>X(DJ}{yL3mU|Vybaz3{))eZ$y!mUBscl^pPNazaC{r&(R>7~zb8aCk09VE z%sWD(dy|~_#xKZWm0H4~-CGpqk zJi97_2M_G}L+GWxR^M*Y#B77KA@Ird;O!mYDb0sd~hIC7GgKNqL2`{Zd&-7W(G)6V!}S3! zF_3M4O`)dUS>Xig1YfRoAYg;_<`BJ5Y_)g2kaYW#HL*f7a&)H{wdEq+muo0gSh+N{ z3~=PKKNs}*f~yV579%~)-39FxKMOfqAW*#cs>Ek+h(Yy-C9_o&G~V>4ATzB|E)kw+ z6&T`UUW{jKxbISK`DKJ%Z>Yf{(d91vT*vFMEv=k6LIg$#nH}u35M%Oak^CHw8QbEM zg$x%BzaReW&H!W8aZjT0M-f4S6_sxG_}!*YkZ*%44tV^Kbre^gv~DBqZ$BxM-c(VU z|EzvJlb}&IRPNy^tOV|7CLdubn`;)M?%PfvTxX>9pj$e;A%g{01^6?oTnBQ6%3ivC zm!Fn+OVp%!XWx98!TAV=%U=d)p6~ElH_@IS5TBfAb?0)0Bwl_=JNvQ{YVl(MqtaH@ z1{@Z&7wa<~C_9N*&PMj%x7Y~}BbOxx&An>XgJLE`r5@i5`G?$CVqhNstd_!xF1PvE z@@&J|MMg_y$3K32Hoj68z~r0Sv%AgLN;y?8WHrl7%tUaFW0SJPVD%q?Zh-qW)ncPH znc!_dr!UKf0lB~{n^$fAGDNc1rNen~1u*YmU+(j1PM_u?Ho_?Evq^&Pw2fhSl5zHRrg#98;6>{cs4mwa;<=~#KI1%G+ATXDhZNJ^{KUjaXr|eN@Ge<3LBW)8gVhxOf_S#dPn70&X z4ulrE-*vA7F>BD&WdQ5W)i1xpi-NfPU_tk3g^#a2+&@i0jq{EJ8K?tXc8&t0V`Co+ zcPf6X;%$}?V=1A946oRS#~t5%bBp#|Tmgt_fVxAEwl~8oMFRH*cP6~4=&YBlgBN{o zA+ihez$=-fbq^@J$g4s@H&a~SSD@gtg<~((I)T3CiM1uR*gMk zunI0n0htV;O&?@>JM_+=HY(h_>iS{JvyD#T4t*K)54|<(y10ezP6FRkNYKeyCJ6Ht zO=k4}vMzV2cdz=J&BEZLb5>5}ryDe6h*d!QMLLkE(3xvQ@6cAiuiGy+9Owq`DH$Gi z-iHHPc#iABuNE`y{R9FB-D6vzP>9?LKt_6iT%P55f}P3Qc84>sEI-7J`KpV~Bm>rp zn2BkZ&EK%TS#CbQzz=3iBt0pQH1(X{5DT|fQV)*s##$h|dQ4r7Wo-`YClACSc~>~w zcDcF>{BSnOdmAR2TpmMKm|xkUs?zM^oWT%E;b%_eeuZ3*&nD2S9^*QEur2et2N-K~1Tnb@cHI5(Xz z-2YE`r-K(IH(C@KYif#?`#m^LFAR=Q<$9o4{pM4%$w_|RodthcuL+*PM1Z0xk9~z zv$E;U>oaHFe_ameBVPC@x({z0JH*Zy=V-2cHLE9QiJt+S)Q?;W`mR+VF+uabwPtf? zY)fDGh-PE*9f(76Y3EQAEE_v1-O453bSj4Z4b#{TQj1L<{SMw@U5eq!Q~)szzhjoI z9BQ*{@)AO{Ew=d^9K6Es%mpr+!XuBI$Vp;6Z@_tUfSK` zKZu9d=GtwK4@>s^@rL%>HF7+wE3=LK8#i-1f#BjJ8^)P=V_Z{wmpPW4Ckgq^`D{u& zdk!GHm4KO-W7OCd3iKMa)IC5AKWui`3jr+NA3xn*0I#&rfyZ(Ag879pBamn(G zpae{7bz?Y!!U_Pg^J7HmMtCc^wx2pNObS=7fMp^R@i1MyJq|mU9yot0iXs+M;`eWT z`(THcXmXA|;94euTsHga5O65mq}H5nHJ9Ip1gINadITtpXh zl1mMUu-U`b>Z5m6>YZB`)%wLhw?6pGNlm z+4szfwUdiN3-!IlK<)U;C-6}0LiUwtPIh3*3Y46n=Mh;NHbrSqn0knpPVqo$zeFfB zO6Kh%ce6cDmG>wLg+00hf0h>~A~xdr3KHS<6RfJvzPu-M+{oG)p*I`Kcg>GyVz1gs zOU(=)>`k*a0j*&Si4(d1sm%Vh|9KQ$og5-ja9uf9=4kq$tpccRnkT>%yUPnN>fbz6 zNpK@KNgTKy4BU zEby9bBRcXJL~mprD=TKmqox`gt~s>LYvhf?fy7Iw(awq8EK%>WC*!pQ44Bj0Q!jp6 zdetr7bJYkkV#gimU2d%%ce@0Sw_mp%+)bpc2^s(P>n9V~tGu+k-qF&~*AZWR*r15p zE;&1*ew6X2D(n2P$twkEH+#8-6>w#wBfB-@D}t)b`UX+7As*fIyv6m=8>_+(@4bGT zCFhaHFn^sl>e^2DfoZ+wZ*S=#+=M25xwMEP!pdt|Kkc%t9CEQbE?s=2hszIRJ%FI4z&21(91JnLm&wIr#jH@h` zC7{d*)KT-(5=hYQT2QIn+a7e3@D#3^{);5RTHO_Ec{X~Kz;v(P+fVZ)cLcIh_NT6V zPLM=Z;&I!o@UHPP0F_C9TSy;Y&)>EoC;4kK%Q3eF+;;cfE;Wivft2Hh_2I#V;tk_= zS{aq=K@KDv>cl^6|AWuEP>hKFUmwV-q?!;wEtS>lTe*w0PR^e$<5}?mm3rc-Ds-Mf z_Ya{sm$QO#*8#humEav3n;%h*_1=&DUxRhsqZ^>{ZmUlPVzJ>HhrJjp1WX^4-F8{= z<<)Y>7bub(gh#uE3#-NvrsoqOPTBqP36_f5xm(ExOmCXLgQ-no!x`LbdqBk@x-=@7Fr>Sq{d)WTh=Vs7f~CF!p!H(&C@=_;FIlw z+1F$=zBiw*;ywcWYYsG2P?Hr6MGZ;`h|N}Wd6HU`cR~zw(gKw23r0`zo)#zZpAB4 zQs-9mE8D1m+Y)$Jnb+I;OWQtg7db52rLEgzNozyfXq>`eyYN_; zKH)1|nd-#_=O%fj|+S1F`+iJ{nXvo388MRN8Qj1YP*MoghUiE4KMBO&4Lrm(FLl77 z{e_~W&HTOnEG%(wkWM?-0J{(5%@f9lbT7khhFg(npGdee|3Qx^Qp>o5-|%m_vAmB{ zt=&VSmwhyJucP6!?+O@6`I;s1L4LYTK6VWrzs{mBgyPnH{CMvHR7l*Wg9%dFySddrp*UffK@~ z&NGRZYEnWQmH9G^R~8Vs_e*7#wHf`qeXoa0Cz zkq0}={KhI#H|@V$GJWQduk?WFe70K1|96M<*;~GKBiD>y3i^MI^AzvIQ)p9I7HyjY z*?{&B-8u-7$#}wn(>@o~9ED^hj;0UvRbC)g)7z=TTq|SK2aQwi{su7a!$vtwunqZy zOS~v9gn(ClG{VjEA0E&qv6~R~Ie@5p@ClPEURitBP~iuaK1*BqBDoO?KD-G8O?Qsr zn8}}O?`ux~Wrgazyp@%WaJLMfoHq#4PhJfYX562TA-|$=j~B_G2S6dRtfnLpd%_;8 zzsg+DBS9$$TAUVt+nJ76^xMLP&uhe(zvWEe6XBo#zn1oVykRm}&y4YT58#jUB%7LV zV^;WHCL1;bVe@6tss!u!f6t5uu{p8ap2Fm?8U?`!tz1+%(1+2~5iJLfG;mMq{dNnhO~Z?nNLoz_yn=;zCC3|=|>ta-SvY*5{w;I5ZKEn8;B@gL9) z1-H50Zp|6W8OszWiXBzmYO#=fTV=eHRJK6VkAv+C$3oy=Wxi*+LT@$S2t(K5L>r~a z7jMzOmyx8gR*vrWuP*kv^M7rx#$<*Ip%*8P0C7jjNpbSVgO;Dz8nip6zDFv9qf^vo4vC!6{OtfL%Bt{<{BSc6|~I+!;hr+z6kmmg;x6BeYjB zm1Qo_I==h=%WBbghZ%@b>S*!9jK5F0?_uU&{=ZIaB@lZiz2)D T^j#y4E-5M%r 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
9bJgQ-Ljsc4!hN#4Mp>G*UQYj3!kCc~qfu4eYEW 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 Date: Thu, 6 Jun 2019 19:18:20 +0530 Subject: [PATCH 010/306] kivy new updates --- src/bitmessagekivy/kivy_helper_search.py | 2 +- src/bitmessagekivy/main.kv | 142 +++++++++----- src/bitmessagekivy/mpybit.py | 240 ++++++++++++++++++----- src/bitmessagekivy/uikivysignaler.py | 2 + src/state.py | 8 +- src/tr.py | 5 +- 6 files changed, 302 insertions(+), 97 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index cbf00fb4..73a8a1ff 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -42,4 +42,4 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file + return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 62d3cbe3..208253ff 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,4 +1,3 @@ - #:import Toolbar kivymd.toolbar.Toolbar #:import ThemeManager kivymd.theming.ThemeManager #:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer @@ -34,10 +33,14 @@ #:import MDBottomNavigation kivymd.tabs.MDBottomNavigation #:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton +#:import Factory kivy.factory.Factory : icon: 'checkbox-blank-circle' +: + font_size: '12.5sp' + : drawer_logo: './images/drawer_logo1.png' NavigationDrawerDivider: @@ -48,6 +51,8 @@ Spinner: pos_hint:{"x":0,"y":.25} id: btn + option_cls: Factory.get("MySpinnerOption") + font_size: '12.5sp' text: app.getDefaultAccData() values: app.variable_1 on_text:app.getCurrentAccountData(self.text) @@ -175,7 +180,7 @@ NavigationLayout: id:sc12 NetworkStat: id:sc13 - SentDetail: + MailDetail: id:sc14 : @@ -184,20 +189,8 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' + ComposerButton: : name: 'sent' @@ -205,20 +198,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' + ComposerButton: : name: 'trash' @@ -226,21 +206,8 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' - + ComposerButton: + : name: 'draft' Label: @@ -289,6 +256,8 @@ NavigationLayout: text: 'select' values: app.variable_1 on_text: ti.text = self.text + option_cls: Factory.get("MySpinnerOption") + font_size: '12.5sp' BoxLayout: orientation: 'vertical' @@ -530,6 +499,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml + ComposerButton: : name: 'addressbook' @@ -539,6 +509,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml + ComposerButton: : name: 'payment' @@ -648,8 +619,8 @@ NavigationLayout: size_hint: .8, .6 text: root.text_variable_5 -: - name: 'sentdetail' +: + name: 'mailDetail' ScrollView: do_scroll_x: False BoxLayout: @@ -662,6 +633,11 @@ NavigationLayout: theme_text_color: 'Primary' text: root.subject halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "From: " + root.from_addr + halign: 'left' MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' @@ -670,11 +646,81 @@ NavigationLayout: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' - text: "From: " + root.from_addr + text: root.status halign: 'left' MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: root.message halign: 'left' - bold: True \ No newline at end of file + bold: True + BoxLayout: + spacing:50 + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Copy' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Delete' + on_press: root.delete_mail() + +: + 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' + +: + id: myadd_popup + background: './images/popup.jpeg' + separator_height: 0 + auto_dismiss: False + BoxLayout: + size_hint_y: None + spacing:50 + id: popup_box + orientation: 'vertical' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address_label + halign: 'left' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + halign: 'left' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Save' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Cancel' + on_press: root.dismiss() + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Scan QR code' \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 7273aeee..046b2fe4 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -46,6 +46,7 @@ from kivy.uix.button import Button import kivy_helper_search from kivy.core.window import Window from functools import partial +from kivy.uix.carousel import Carousel class Navigatorss(MDNavigationDrawer): @@ -56,6 +57,8 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" + data = ListProperty() + def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) if state.association == '': @@ -64,7 +67,7 @@ class Inbox(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method sent accounts.""" + """Clock Schdule for method inbox accounts.""" self.inboxaccounts() print(dt) @@ -74,7 +77,7 @@ class Inbox(Screen): self.loadMessagelist(account, 'All', '') def loadMessagelist(self, account, where="", what=""): - """Load Sent list for Sent messages.""" + """Load Inbox list for Inbox messages.""" xAddress = 'toaddress' data = [] queryreturn = kivy_helper_search.search_sql( @@ -82,11 +85,29 @@ class Inbox(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[2].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[2]) > 10 else mail[2] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text }) + # ('inbox', 'j\xe5(M\xcfPbe\rl\x0f\xa3\r\xef>\xf0\x0b&\t\'}"RYg\x03\x80\x14\x82\xeb&,', 'BM-2cXpNNd7dhTjsv7LHNfmphfUabZk958sA3', 'hello', 'BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe', 'test from peter', '1559121770', 0) + data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - self.ids.ml.add_widget(meny) + meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) + carousel = Carousel(direction='right') + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_color = (1, 0, 0, .5) + del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0,1,0,1) + ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) + carousel.add_widget(ach_btn) + carousel.index=1 + self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -97,6 +118,40 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) + def inbox_detail(self, receivedTime, *args): + """Load inbox page details""" + state.detailPageType = 'inbox' + state.sentMailTime = receivedTime + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + + def delete(self, data_index, instance, *args): + """Delete inbox mail from inbox listing""" + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def archive(self, data_index, instance, *args): + """Archive inbox mail from inbox listing""" + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + except Exception as e: + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) + + class MyAddress(Screen): """MyAddress Screen uses screen to show widgets of screens.""" @@ -106,13 +161,14 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or state.kivyapp.variable_1: + if BMConfigParser().addresses() or ContentNavigationDrawer().ids.btn.values: data = [] - for address in state.kivyapp.variable_1: + for address in ContentNavigationDrawer().ids.btn.values: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.bind(on_press = partial(self.myadd_detail, item['secondary_text'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -128,6 +184,11 @@ class MyAddress(Screen): except Exception as e: pass + def myadd_detail(self, fromaddress, *args): + p = MyaddDetailPopup() + p.open() + p.get_address(fromaddress) + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -278,6 +339,7 @@ class DropDownWidget(BoxLayout): self.main_pop = Popup(title="Error", content=self.box, size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) self.but.bind(on_press=self.main_pop.dismiss) + # self.main_pop.background = './images/popup.jpeg' self.main_pop.open() @@ -370,13 +432,16 @@ class Random(Screen): nonceTrialsPerByte, payloadLengthExtraBytes) ) - self.manager.current = 'add_sucess' + # self.manager.current = 'add_sucess' + self.manager.current = 'myaddress' self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - self.parent.parent.parent.parent.ids.sc10.clear_widgets() - self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 + # self.parent.parent.parent.parent.ids.sc10.clear_widgets() + # self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + class AddressSuccessful(Screen): pass @@ -410,18 +475,35 @@ class Sent(Screen): def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" xAddress = 'fromaddress' - data = [] queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) + state.totalSentMail = len(queryreturn) if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[0].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, 'lastactiontime': mail[6]}) - for item in data: + self.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, 'lastactiontime': mail[6]}) + for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) - self.ids.ml.add_widget(meny) + carousel = Carousel(direction='right') + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_color = (1, 0, 0, .5) + del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0,1,0,1) + ach_btn.bind(on_press=partial(self.archive, item['lastactiontime'])) + carousel.add_widget(ach_btn) + carousel.index=1 + self.ids.ml.add_widget(carousel) + # self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -433,14 +515,37 @@ class Sent(Screen): self.ids.ml.add_widget(content) def sent_detail(self, lastsenttime, *args): + """Load sent mail details""" + state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: src_mng_obj = self.manager else: src_mng_obj = self.parent.parent src_mng_obj.screens[13].clear_widgets() - src_mng_obj.screens[13].add_widget(SentDetail()) - src_mng_obj.current = 'sentdetail' + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + + def delete(self, data_index, instance, *args): + """delete sent mail from sent mail listing""" + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def archive(self, data_index, instance, *args): + """archive sent mail from sent mail listing""" + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + except Exception as e: + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) class Trash(Screen): @@ -451,22 +556,14 @@ class Trash(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - data = [{'text': "neha cis", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "paytm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "pol", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "akshayaura", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "codementor", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "yatra", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "mdtezm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "crewqt", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] - for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash';") + sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash';") + trash_data = inbox + sent + for item in trash_data: + meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) - class Page(Screen): pass @@ -493,7 +590,7 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() - # obj_2 = ObjectProperty() + obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() total_sentmail = str(state.totalSentMail) @@ -523,10 +620,11 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() - # self.obj_2 = MyAddress() + self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() + Window.bind(on_keyboard=self.on_key) return main_widget def run(self): @@ -541,7 +639,6 @@ class NavigateApp(App): shutdown.doCleanShutdown() def show_address_success(self): - print("9062 I am pressed...............................................................") content = MDLabel(font_style='Body1', theme_text_color='Secondary', text="Successfully Saved your contact address. " @@ -555,6 +652,7 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": + # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -574,6 +672,7 @@ class NavigateApp(App): self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) + self.root.ids.scr_mngr.current = 'inbox' def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" @@ -605,14 +704,29 @@ class NavigateApp(App): return True return False - def prnttttttttttttt(self): - pass - def limit_spinner(self): max = 2.8 - spinner_obj =ContentNavigationDrawer().ids.btn + spinner_obj = ContentNavigationDrawer().ids.btn spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 + def on_key(self, window, key, *args): + if key == 27: # the esc key + if self.root.ids.scr_mngr.current_screen.name == "mailDetail": + self.root.ids.scr_mngr.current = 'sent' + # this is for direction of the screen comesup + # self.root.ids.scr_mngr.transition.direction = 'right' + return True + elif self.root.ids.scr_mngr.current_screen.name == "create": + self.root.ids.scr_mngr.current = 'inbox' + return True + else: + return True + + def status_dispatching(self, data): + ackData, message = data + if state.ackdata == ackData: + state.status.status = message + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -685,22 +799,58 @@ class NavigationDrawerTwoLineListItem( pass -class SentDetail(Screen): - """SentDetail Screen uses to show the detail of mails.""" +class MailDetail(Screen): + """MailDetail Screen uses to show the detail of mails.""" to_addr = StringProperty() from_addr = StringProperty() subject = StringProperty() message = StringProperty() + status = StringProperty() def __init__(self, *args, **kwargs): - super(SentDetail, self).__init__(*args, **kwargs) + super(MailDetail, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method SentDetail mails.""" - data = sqlQuery("select toaddress, fromaddress, subject, message from sent where lastactiontime = {};".format(state.sentMailTime)) - if data: - self.to_addr = data[0][0] - self.from_addr = data[0][1] - self.subject = data[0][2].upper() - self.message = data[0][3] \ No newline at end of file + """Clock Schdule for method MailDetail mails.""" + if state.detailPageType == 'sent': + data = sqlQuery("select toaddress, fromaddress, subject, message , status, ackdata from sent where lastactiontime = {};".format(state.sentMailTime)) + state.status = self + state.ackdata = data[0][5] + self.assign_mail_details(data) + elif state.detailPageType == 'inbox': + data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + self.assign_mail_details(data) + + def assign_mail_details(self, data): + self.to_addr = data[0][0] + self.from_addr = data[0][1] + self.subject = data[0][2].upper() + self.message = data[0][3] + if len(data[0]) == 6: + self.status = data[0][4] + + def delete_mail(self): + if state.detailPageType == 'sent': + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) + self.parent.parent.screens[3].clear_widgets() + self.parent.parent.screens[3].add_widget(Sent()) + self.parent.parent.current = 'sent' + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) + + +class MyaddDetailPopup(Popup): + """MyaddDetailPopup pop is used for showing my address detail""" + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + super(MyaddDetailPopup, self).__init__(**kwargs) + self.size_hint_y = 0.4 + self.size_hint_x = 0.9 + + def get_address(self, address): + """Getting address for displaying details on popup""" + self.address_label = BMConfigParser().get(address, 'label') if BMConfigParser().get(address, 'label') else '' + self.address = address \ No newline at end of file diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py index 82d94a14..5681d25d 100644 --- a/src/bitmessagekivy/uikivysignaler.py +++ b/src/bitmessagekivy/uikivysignaler.py @@ -18,6 +18,8 @@ class UIkivySignaler(Thread): state.kivyapp.variable_1.append(address) elif command == 'rerenderAddressBook': state.kivyapp.obj_1.refreshs() + elif command == 'updateSentItemStatusByAckdata': + state.kivyapp.status_dispatching(data) except Exception as e: print(e) diff --git a/src/state.py b/src/state.py index 3c7dd9ea..4aca8ae7 100644 --- a/src/state.py +++ b/src/state.py @@ -78,6 +78,10 @@ totalSentMail = 0 sentMailTime = 0 -dynamicAddressList = [] +myAddressObj = None -myAddressObj = None \ No newline at end of file +detailPageType = None + +ackdata = None + +status = None \ No newline at end of file diff --git a/src/tr.py b/src/tr.py index 6f26e75d..0d9643a8 100644 --- a/src/tr.py +++ b/src/tr.py @@ -13,8 +13,11 @@ class translateClass: else: return self.text +# def _translate(context, text, disambiguation = None, encoding = None, n = None): +# return translateText(context, text, n) + def _translate(context, text, disambiguation = None, encoding = None, n = None): - return translateText(context, text, n) + return text def translateText(context, text, n = None): try: From 92b0f45f2e878af825bf7ac744f0971ef7cfaabf Mon Sep 17 00:00:00 2001 From: surbhi Date: Fri, 28 Jun 2019 20:24:47 +0530 Subject: [PATCH 011/306] Implement qrcode display feature with Ui enhancement and message avtar display based on message --- src/bitmessagekivy/main.kv | 306 ++++++++++++++++++++++++++--------- src/bitmessagekivy/mpybit.py | 223 +++++++++++++++++++++---- src/images/text_images/A.png | Bin 0 -> 6857 bytes src/images/text_images/B.png | Bin 0 -> 6533 bytes src/images/text_images/C.png | Bin 0 -> 7662 bytes src/images/text_images/D.png | Bin 0 -> 6381 bytes src/images/text_images/E.png | Bin 0 -> 5009 bytes src/images/text_images/F.png | Bin 0 -> 4972 bytes src/images/text_images/G.png | Bin 0 -> 7593 bytes src/images/text_images/H.png | Bin 0 -> 5054 bytes src/images/text_images/I.png | Bin 0 -> 4713 bytes src/images/text_images/J.png | Bin 0 -> 5841 bytes src/images/text_images/K.png | Bin 0 -> 6719 bytes src/images/text_images/L.png | Bin 0 -> 4878 bytes src/images/text_images/M.png | Bin 0 -> 6569 bytes src/images/text_images/N.png | Bin 0 -> 6509 bytes src/images/text_images/O.png | Bin 0 -> 7912 bytes src/images/text_images/P.png | Bin 0 -> 5914 bytes src/images/text_images/Q.png | Bin 0 -> 8271 bytes src/images/text_images/R.png | Bin 0 -> 6404 bytes src/images/text_images/S.png | Bin 0 -> 7826 bytes src/images/text_images/T.png | Bin 0 -> 4793 bytes src/images/text_images/U.png | Bin 0 -> 6113 bytes src/images/text_images/V.png | Bin 0 -> 6761 bytes src/images/text_images/W.png | Bin 0 -> 7805 bytes src/images/text_images/X.png | Bin 0 -> 7367 bytes src/images/text_images/Y.png | Bin 0 -> 6459 bytes src/images/text_images/Z.png | Bin 0 -> 6166 bytes src/state.py | 14 +- 29 files changed, 428 insertions(+), 115 deletions(-) create mode 100644 src/images/text_images/A.png create mode 100644 src/images/text_images/B.png create mode 100644 src/images/text_images/C.png create mode 100644 src/images/text_images/D.png create mode 100644 src/images/text_images/E.png create mode 100644 src/images/text_images/F.png create mode 100644 src/images/text_images/G.png create mode 100644 src/images/text_images/H.png create mode 100644 src/images/text_images/I.png create mode 100644 src/images/text_images/J.png create mode 100644 src/images/text_images/K.png create mode 100644 src/images/text_images/L.png create mode 100644 src/images/text_images/M.png create mode 100644 src/images/text_images/N.png create mode 100644 src/images/text_images/O.png create mode 100644 src/images/text_images/P.png create mode 100644 src/images/text_images/Q.png create mode 100644 src/images/text_images/R.png create mode 100644 src/images/text_images/S.png create mode 100644 src/images/text_images/T.png create mode 100644 src/images/text_images/U.png create mode 100644 src/images/text_images/V.png create mode 100644 src/images/text_images/W.png create mode 100644 src/images/text_images/X.png create mode 100644 src/images/text_images/Y.png create mode 100644 src/images/text_images/Z.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 208253ff..562e9f98 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -35,11 +35,18 @@ #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory +#: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 + : icon: 'checkbox-blank-circle' : font_size: '12.5sp' + background_color: color_button if self.state == 'down' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/button' + color: color_font : drawer_logo: './images/drawer_logo1.png' @@ -54,19 +61,24 @@ option_cls: Factory.get("MySpinnerOption") font_size: '12.5sp' text: app.getDefaultAccData() + background_color: color_button if self.state == 'normal' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/spinner' + color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) on_press: app.limit_spinner() NavigationDrawerIconButton: + id: inbox_cnt icon: 'email-open' text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "99+" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: + id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' - badge_text: "0" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: icon: 'message-draw' text: "Draft" @@ -87,10 +99,11 @@ on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "8+" NavigationDrawerIconButton: + id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' - badge_text: "9+" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: text: "All Mails" icon:'contact-mail' @@ -182,6 +195,8 @@ NavigationLayout: id:sc13 MailDetail: id:sc14 + ShowQRCode: + id:sc15 : name: 'inbox' @@ -233,7 +248,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(app.scr_size) + height: dp(600) padding: dp(32) spacing: 15 BoxLayout: @@ -249,11 +264,10 @@ NavigationLayout: BoxLayout: size_hint_y: None - height: 100 + height: dp(40) Spinner: background_color: app.theme_cls.primary_dark id: btn - text: 'select' values: app.variable_1 on_text: ti.text = self.text option_cls: Factory.get("MySpinnerOption") @@ -289,17 +303,19 @@ NavigationLayout: required: True helper_text_mode: "on_error" BoxLayout: + spacing:50 AnchorLayout: MDRaisedButton: - size_hint: .8, .3 + size_hint: 1, None + height: dp(40) text: 'send' on_press: root.send() - BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .3 + size_hint: 1, None + height: dp(40) text: 'reset' - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: app.root.ids.scr_mngr.current = 'random' : readonly: False @@ -341,7 +357,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(800) + height: dp(700) BoxLayout: MDLabel: font_style: 'Body1' @@ -483,7 +499,7 @@ NavigationLayout: MDCheckbox: id: chkbox size_hint: None, None - size: dp(48), dp(48) + size: dp(48), dp(64) active: True MDLabel: font_style: 'Body1' @@ -519,44 +535,62 @@ NavigationLayout: id: popup title: 'add contact\'s' background: './images/popup.jpeg' - title_size: sp(30) + title_size: sp(20) title_color: 0.4, 0.3765, 0.3451, 1 size_hint: 1, 1 auto_dismiss: False separator_color: 0.3529, 0.3922, 0.102, 0.7 BoxLayout: - size_hint_y: None + size_hint_y: 0.5 orientation: 'vertical' - spacing:50 + spacing:dp(20) id: popup_box - orientation: 'vertical' - MDTextField: - id: label - multiline: True - hint_text: "Label" - required: True - helper_text_mode: "on_error" - MDTextField: - id: address - hint_text: "Address" - required: True - helper_text_mode: "on_error" - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Save' - on_release: - root.savecontact() - app.root.ids.scr_mngr.current = 'addressbook' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Cancel' - on_press: root.dismiss() - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Scan QR code' + BoxLayout: + orientation: 'vertical' + MDTextField: + id: label + multiline: True + hint_text: "Label" + required: True + helper_text_mode: "on_error" + MDTextField: + id: address + hint_text: "Address" + required: True + helper_text_mode: "on_error" + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_release: + root.savecontact() + MDLabel: + font_style: 'Title' + text: 'Save' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Scan QR code' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'networkstat' @@ -659,7 +693,8 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Copy' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() MDRaisedButton: size_hint: 1, None height: dp(40) @@ -680,6 +715,7 @@ NavigationLayout: elevation_normal: 8 md_bg_color: [0.941, 0, 0,1] on_press: app.root.ids.scr_mngr.current = 'create' + on_release: app.clear_composer() : id: myadd_popup @@ -688,39 +724,151 @@ NavigationLayout: auto_dismiss: False BoxLayout: size_hint_y: None - spacing:50 - id: popup_box + spacing:dp(70) + id: myadd_popup_box orientation: 'vertical' - MDLabel: - font_style: 'Title' - theme_text_color: 'Primary' - text: "Label" - halign: 'left' - MDLabel: - font_style: 'Subhead' - theme_text_color: 'Primary' - text: root.address_label - halign: 'left' - MDLabel: - font_style: 'Title' - theme_text_color: 'Primary' - text: "Address" - halign: 'left' - MDLabel: - font_style: 'Subhead' - theme_text_color: 'Primary' - text: root.address - halign: 'left' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Save' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Cancel' - on_press: root.dismiss() - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Scan QR code' \ No newline at end of file + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:dp(25) + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address_label + font_size: '15sp' + halign: 'left' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + font_size: '15sp' + halign: 'left' + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + on_press: root.send_message_from() + MDLabel: + font_style: 'Title' + text: 'Send message from' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + on_press: app.root.ids.scr_mngr.current = 'showqrcode' + on_press: app.root.ids.sc15.qrdisplay() + MDLabel: + font_style: 'Title' + text: 'Show QR code' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + id: addbook_popup + background: './images/popup.jpeg' + separator_height: 0 + auto_dismiss: False + BoxLayout: + size_hint_y: None + spacing:dp(70) + id: addbook_popup_box + orientation: 'vertical' + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:dp(20) + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + font_size: '17sp' + halign: 'left' + MDTextField: + id: add_label + font_style: 'Subhead' + font_size: '15sp' + halign: 'left' + text: root.address_label + theme_text_color: 'Primary' + required: True + helper_text_mode: "on_error" + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + font_size: '15sp' + halign: 'left' + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + on_press: root.send_message_to() + MDLabel: + font_style: 'Title' + text: 'Send message to' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + font_size: '10sp' + on_press: root.update_addbook_label(root.address) + MDLabel: + font_style: 'Title' + text: 'Save' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + name: 'showqrcode' + BoxLayout: + orientation: 'vertical' + id: qr \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 046b2fe4..851375a1 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -47,6 +47,8 @@ import kivy_helper_search from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel +from kivy.garden.qrcode import QRCodeWidget +from kivy.utils import platform class Navigatorss(MDNavigationDrawer): @@ -89,10 +91,11 @@ class Inbox(Screen): data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') - carousel.height = 150 + if platform == 'android': + carousel.height = 150 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -132,6 +135,7 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing""" + state.navigation_drawer_obj = self.parent.parent.parent.parent.children[2].children[0].children[0].children[0].children sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -161,14 +165,14 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or ContentNavigationDrawer().ids.btn.values: + if BMConfigParser().addresses() or state.kivyapp.variable_1: data = [] - for address in ContentNavigationDrawer().ids.btn.values: + for address in state.kivyapp.variable_1: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - meny.bind(on_press = partial(self.myadd_detail, item['secondary_text'])) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper()))) + meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -184,10 +188,10 @@ class MyAddress(Screen): except Exception as e: pass - def myadd_detail(self, fromaddress, *args): + def myadd_detail(self, fromaddress, label, *args): p = MyaddDetailPopup() p.open() - p.get_address(fromaddress) + p.set_address(fromaddress, label) class AddressBook(Screen): @@ -202,7 +206,8 @@ class AddressBook(Screen): if data: for item in data: meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) + meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -218,6 +223,10 @@ class AddressBook(Screen): state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) + def addBook_detail(self, address, label, *args): + p = AddbookDetailPopup() + p.open() + p.set_addbook_data(address, label) class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): @@ -307,6 +316,10 @@ class DropDownWidget(BoxLayout): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) + state.check_sent_acc = fromAddress + state.msg_counter_objs = self.parent.parent.parent.parent.parent.parent.children[0].children[2].children[0].ids + # state.msg_counter_objs.send_cnt.badge_text = str(int(state.sent_count) + 1) + # state.sent_count = str(int(state.sent_count) + 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' @@ -319,6 +332,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' + return None else: msg = 'Enter a valid recipients address' @@ -438,10 +452,10 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 - # self.parent.parent.parent.parent.ids.sc10.clear_widgets() - # self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) - + # state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 + self.parent.parent.parent.parent.ids.sc10.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + class AddressSuccessful(Screen): pass @@ -478,16 +492,22 @@ class Sent(Screen): queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) state.totalSentMail = len(queryreturn) + if state.msg_counter_objs and state.association == state.check_sent_acc: + state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) + state.sent_count = str(int(state.sent_count) + 1) + state.check_sent_acc = None + if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') self.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, 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - carousel.height = 150 + if platform == 'android': + carousel.height = 150 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -528,8 +548,19 @@ class Sent(Screen): def delete(self, data_index, instance, *args): """delete sent mail from sent mail listing""" + try: + msg_count_objs = self.parent.parent.parent.parent.children[2].ids + except Exception as e: + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + if int(state.sent_count) > 0: + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.sent_count = str(int(state.sent_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) + # self.update_mail_count() self.update_trash() def archive(self, data_index, instance, *args): @@ -556,12 +587,17 @@ class Trash(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash';") - sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash';") + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + + inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) trash_data = inbox + sent + for item in trash_data: meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper()))) self.ids.ml.add_widget(meny) class Page(Screen): @@ -590,11 +626,10 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() - obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() total_sentmail = str(state.totalSentMail) - scr_size = Window.size[0] + state.screen_density = Window.size title = "PyBitmessage" count = 0 menu_items = [ @@ -620,7 +655,6 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() - self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() @@ -631,13 +665,6 @@ class NavigateApp(App): kivyuisignaler.release() super(NavigateApp, self).run() - def say_exit(self): - """Exit the application as uses shutdown PyBitmessage.""" - print("**************************EXITING FROM APPLICATION*****************************") - App.get_running_app().stop() - import shutdown - shutdown.doCleanShutdown() - def show_address_success(self): content = MDLabel(font_style='Body1', theme_text_color='Secondary', @@ -674,6 +701,17 @@ class NavigateApp(App): self.root.ids.sc5.add_widget(Trash()) self.root.ids.scr_mngr.current = 'inbox' + msg_counter_objs = self.root_window.children[1].children[2].children[0].ids + state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format(state.association))[0][0]) + state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format(state.association))[0][0]) + state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + + if msg_counter_objs: + msg_counter_objs.send_cnt.badge_text = state.sent_count + msg_counter_objs.inbox_cnt.badge_text = state.inbox_count + msg_counter_objs.trash_cnt.badge_text = state.trash_count + + def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" try: @@ -727,12 +765,44 @@ class NavigateApp(App): if state.ackdata == ackData: state.status.status = message + def clear_composer(self): + """if slow down the nwe will make new composer edit screen""" + composer_obj = self.root.ids.sc3.children[0].ids + composer_obj.ti.text = '' + composer_obj.btn.text = '' + composer_obj.txt_input.text = '' + composer_obj.subject.text = '' + + def on_stop(self): + """On stop methos is used for stoping the runing script""" + print("**************************EXITING FROM APPLICATION*****************************") + import shutdown + shutdown.doCleanShutdown() + + def mail_count(self, text): + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + if text == 'Sent': + state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.sent_count + elif text == 'Inbox': + state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.inbox_count + elif text == 'Trash': + state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + return state.trash_count + class GrashofPopup(Popup): def __init__(self, **kwargs): super(GrashofPopup, self).__init__(**kwargs) - self.size_hint_y = 0.7 - self.size_hint_x = 0.9 + if state.screen_density[0] <= 720: + self.size_hint_y = 0.4 + self.size_hint_x = 0.9 + else: + self.size_hint_y = 0.42 + self.size_hint_x = 0.7 def savecontact(self): label = self.ids.label.text @@ -742,6 +812,7 @@ class GrashofPopup(Popup): queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): content = MDLabel(font_style='Body1', @@ -806,6 +877,7 @@ class MailDetail(Screen): subject = StringProperty() message = StringProperty() status = StringProperty() + page_type = StringProperty() def __init__(self, *args, **kwargs): super(MailDetail, self).__init__(*args, **kwargs) @@ -813,6 +885,7 @@ class MailDetail(Screen): def init_ui(self, dt=0): """Clock Schdule for method MailDetail mails.""" + self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent': data = sqlQuery("select toaddress, fromaddress, subject, message , status, ackdata from sent where lastactiontime = {};".format(state.sentMailTime)) state.status = self @@ -836,9 +909,28 @@ class MailDetail(Screen): self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' + elif state.detailPageType == 'inbox': + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(state.sentMailTime)) + self.parent.parent.screens[0].clear_widgets() + self.parent.parent.screens[0].add_widget(Inbox()) + self.parent.parent.current = 'inbox' self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + def inbox_reply(self): + """This method is used for replying inbox messages""" + data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + composer_obj = self.parent.parent.screens[2].children[0].ids + composer_obj.ti.text = data[0][1] + composer_obj.btn.text = data[0][1] + composer_obj.txt_input.text = data[0][0] + composer_obj.subject.text = data[0][2] + self.parent.parent.current = 'create' + + def copy_sent_mail(self): + """This method is used for copying sent mail to the composer""" + pass + class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail""" @@ -847,10 +939,71 @@ class MyaddDetailPopup(Popup): def __init__(self, **kwargs): super(MyaddDetailPopup, self).__init__(**kwargs) - self.size_hint_y = 0.4 - self.size_hint_x = 0.9 + if state.screen_density[0] <= 720: + self.size_hint_y = 0.32 + self.size_hint_x = 0.9 + else: + self.size_hint_y = 0.32 + self.size_hint_x = 0.7 - def get_address(self, address): + def set_address(self, address, label): """Getting address for displaying details on popup""" - self.address_label = BMConfigParser().get(address, 'label') if BMConfigParser().get(address, 'label') else '' - self.address = address \ No newline at end of file + self.address_label = label + self.address = address + + def send_message_from(self): + """This method used to fill from address of composer autofield""" + window_obj = self.parent.children[1].ids + window_obj.sc3.children[0].ids.ti.text = self.address + window_obj.sc3.children[0].ids.btn.text = self.address + window_obj.sc3.children[0].ids.txt_input.text = '' + window_obj.sc3.children[0].ids.subject.text = '' + window_obj.sc3.children[0].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.dismiss() + +class AddbookDetailPopup(Popup): + """AddbookDetailPopup pop is used for showing my address detail""" + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + super(AddbookDetailPopup, self).__init__(**kwargs) + if state.screen_density[0] <= 720: + self.size_hint_y = 0.35 + self.size_hint_x = 0.95 + else: + self.size_hint_y = 0.35 + self.size_hint_x = 0.7 + + def set_addbook_data(self, address, label): + """Getting address book data for detial dipaly""" + self.address_label = label + self.address = address + + def update_addbook_label(self, address): + """Updating the label of address book address""" + if str(self.ids.add_label.text): + sqlExecute("UPDATE addressbook SET label = '{}' WHERE address = '{}';".format(str(self.ids.add_label.text), address)) + self.parent.children[1].ids.sc11.clear_widgets() + self.parent.children[1].ids.sc11.add_widget(AddressBook()) + self.dismiss() + + def send_message_to(self): + """This method used to fill to_address of composer autofield""" + window_obj = self.parent.children[1].ids + window_obj.sc3.children[0].ids.txt_input.text = self.address + window_obj.sc3.children[0].ids.ti.text = '' + window_obj.sc3.children[0].ids.btn.text = '' + window_obj.sc3.children[0].ids.subject.text = '' + window_obj.sc3.children[0].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.dismiss() + + +class ShowQRCode(Screen): + """ShowQRCode Screen uses to show the detail of mails.""" + + def qrdisplay(self): + self.ids.qr.clear_widgets() + self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) \ No newline at end of file diff --git a/src/images/text_images/A.png b/src/images/text_images/A.png new file mode 100644 index 0000000000000000000000000000000000000000..64ed6110e2cabcfe663e2b0c5ac459477d2020f3 GIT binary patch literal 6857 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/D.png b/src/images/text_images/D.png new file mode 100644 index 0000000000000000000000000000000000000000..2549ffc2e8bdc6e63dad4ba8d03e20e1ad08b4c3 GIT binary patch literal 6381 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/E.png b/src/images/text_images/E.png new file mode 100644 index 0000000000000000000000000000000000000000..5d6316114ef0eff37bd721612d3c9112f89b5c4b GIT binary patch literal 5009 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 I#Wv#q07IPYQ~&?~ literal 0 HcmV?d00001 diff --git a/src/images/text_images/H.png b/src/images/text_images/H.png new file mode 100644 index 0000000000000000000000000000000000000000..279bd1ce6db1edf17782fdb3babb05b5cfc39ecb GIT binary patch literal 5054 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 OU~F*fdX=7Y-2VXhe*nn< literal 0 HcmV?d00001 diff --git a/src/images/text_images/I.png b/src/images/text_images/I.png new file mode 100644 index 0000000000000000000000000000000000000000..c88f048d7a0a28879958c158d554a7457d21481d GIT binary patch literal 4713 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/J.png b/src/images/text_images/J.png new file mode 100644 index 0000000000000000000000000000000000000000..1533117129f4e267b4e475d10a41eb7fd378f7ce GIT binary patch literal 5841 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Ν zv2;ZhW~|rzS^IlTbUY}~{55O4T_^09{VI2mpo-dYu67Q-Sk-+E>p z=~UXX44_%*!d$cjEIJeOFyuuH<#M^znlI@r+w9szUB2 zaV?}?k0Sw%GvH|y>^k>Ps?j_(*ChB|qBD-K@x3vuds8&9Cz>AA#hcLm0o>=UsXV^1 zP8^!anNPhQ8fiw5S;L->9r9(ulaaWobVI)dW1hkg^AI_Ylg}hIisp}(*aP+|2**zk zrW3d*L|^3{FfX`uEAH;?xRGVOEJ|%4@GLwEI)u!Le0hwV^TA%L z*VZ!Q@qd{^0g2yu`(NDR&kyWdQ@EBzbx?o@(*tY3uVqIwbHo~0bswl{jZx7i2o$-I z`uGwXoVVF}Nfcc*_d|&>$zeHdG_?5Mt2dRmo?5+x`(&!F(bn_c+65;&>lMoCb^((g zv<6#kA_8wbOojW5@7e$VL^^e0djWDA+EyN(Tu`1g`E$>Cb#MKrQ`ph`~ebvqktE4>jU~6e5i<;p8nEkE*U0mYl z-x5N16dn~`cfS-a_=2ASOfCc(nbiRHZQvD(^Y3m4Jc?UQA7)`#h`1;|r8FXUU5;hx z88PSXh%{;5;uccx*pjF!Bwy@XO>|?Qu}e#KXRF})(99&=<3MB;a496Dx2qvF&sU%> zaM{@U;IkZ?XTY5>g4JReI4i1jxW~qNjdU$bawUYwW&S0JXRUh$9Ex8s)qm zZI^!IW=!(}e~|vBj*&oYlKkZ)nx9vK9_a7~@%NNUW&RP*7iwA1T4;|84U3nw8Nes9 zhl!=wcjmR2FuvK9*Bkq0VP@SXIQl?`{rTzj^sh6u;af39r7?SV`Xy~YU4I%IE}mnz zxWu#BNVer1dV^A5$d)vY3f@>jFOVB9$de>ggGH-^*IlboY;;Cnu!lGh3UnTjud*fpK49UY%sPN z`RjrOIrAMGmEX}%Vs;ERct!eRuua%AG!DXFmD!bDUEZVGIMV4a1`1K|AiC z_;42~0Xjt_j6YvbL8ia0HAyRWRMpGO%s4yZG%;`Du#~~ivUT5KR(%Sld_(s{>DAW8 zOAqdbHmfJ>tXF=pI^7K|oU^dKcmL>AorXD^u3`ENTyiuJ*(DzrkN9CO&`Z003e~Ul z*^NL}5lU>l{SrB(%4sb5f#WAa)B{;S33l*#{u-@UoBcIFu+~^p%KnEGC;$XZ@lgs< zn}31&Y+lKgD?e_!L9ObqNtF~C5sMbGFMtN%(wefDo(2@cF}cEO-p*n|aX>-R!*jY* zT)Y-qMPJ=CE`Qjv%|v3WBEkmj?p{)o5k(JfJ=6vP1Wi?di}N5;_;fs|MD30LY!TSM zpP0~jp~%agRq4ySj**Heh|HSCb&}JiAQunM!0dYyqIrjfUBO())E_CUPTRBxjOO9N z?4U3&;G{wQ_0PMCRln-M3;D#gxerRapMGIri*>dKNqk&>Jyp_drq zBadit4^;D*&%q?d^q($Gxar@1zT^GJtO;^R_1ek(=5GOW%O~^#_;QAnM7}|`CY}AK zzAkSDd#Z+IrK5^)i3cusU1C*Q9_-wn@W=M;tbLp3=Ji(*Rx;)L+|Qp=X~~Hi9=s<} z;WKwt)#wuYp+Q9VgF$YpLM_-Js!ocLIMf5S_>$$DFwex!IzVvno!{jrCEr-H&Rnwr)vh@V>driFI~de84) z{D_gQ2CtyI*2h&c3uP*TYFlmA>wVcWiy-cp{0V@pi8M71ViV7{_4sVC#W9Po1YQNZ z`TU`f=~t+JIngV+6$E2Jo*3gK`5a?B{`rVcd*K;WezoSE;pCIqUY}G4ypzq8dx*Qb z(^TuO$!a^FV{d;IATQRj_x)5DChG8|Y<;;cD{KQnhAFXFhAk;vdn%;ZH_El;A!Cwc ztKfo`E)rxI?r-N6sEAzME0;V6(+I8uM9E#y=^i%}xur|mON|eC=TXkp#CV>_@o~lF zi4x`aK1J^ExC~C_Xpj1`*^}6&O+e|UFPg=%i!7MckBi(yLGHC`)@I^ zEwcIZmEP;ey42c+60@pB@p_uFg8q9gKZ{_At_{h7}eMi=_~QM*}WX7p^hP{a84 zlK`l7*T}8cW-N<=-dz{`DsRciy`3o+Bc|QdjBxsdt8-fc$z2)qG1f}jc4Zape4X~_ z`1+@Yk~}UpC;|=A?mRcvwAjI=%|%nF_*7nsMDg|R*t92F09eJ%DXa$%ILo*2%ZWn{ zH+JtR+?Q4q-lgVp_ZluJ>#yJduiq;=8g?k0LtP*Go%|XfR2F@5b{jDwUDe!fd4P!* zWbd9FR_51(xvyg+CH0JiVjzCEBS7Q(UVoPaMMrKwOz|mW09U+%$uLJYipBnNnN0a= zX}MSiz@*abG4*LEX#C?eD*u;w7FsrisuNFBz-SRQRw3%C@LZ0bG_G7?1J_eAlSY@J zf&m|8M44OMvg$?tr(T`qp==sFV7o>aGUwb{ole9|?q8q9a$U-9p>gaM*V;e+;4UJk zot%KM4_GkTp;6b3W%~47UL@YQ)AirfTWFOx&{xjzC;W}ON4}{gKRfQ1G+kA)tB^}Y z8N9)uRS>2Y!spfdoGWq(uoC1aooJU=R+>`PC zu7D-h>)m=sx^xh&aD3Qu=VH*bM$=GO7}8uF`9L`t-6W=k80WtB=H_b0-jWKTx%k}g z+c!d&3X)aUlSa*Y-QJ=i9dKd>@VY+!VXxI}L0%106+$XNwm;z~qAfXn?wa;wXWq?w ztIeOhdULz8^y9qC5GXD)RRu@)+E5aXyt;3%JA`%y)a!WY^-D#W z;G*_C#sm`3w;NsL*yeNK%ti3!#R2VU-(AK96{BfWnJ2sl6- z4(SR5Z~1s*D0@4gh3d_PHWy>mWuMkkNjPsp2Hn1R17Ex6L%cxBf*u$)H1iiGDv>(?-xn~pSSRAYS|UCNMEKdzfZ zxx)WcztGotGCEREa2CRU@!U~}dDuI9#iJ*x=|Mu9nbMXpe2a%O7mR46#cAi%WiCzU9}(ET2+X+XUH5H zloKp%M4`|#0hQAKDSLG3tY0s(-eiN5$xbWY%dckq&i`6(l4(&)U{3}T!ObViAG*qKX>$hGs~gCp73;_!+y}`YXs<0_OoKwta!!*|>%D$$qF7S)tUi-p_ zeGO=|N9qjGY?sqbPVFVW=b@r4c^hS*{yrh(uZ?ucmgJPR4|oehBd#FXuinudT+*iQ zGUqOtKIb7dl|shKMu_gg>VdHvo3`uw48>i=CTA@omW={} zF3D+MjY=+LQ$yn>+`@dTPGET5$>!NmnJVa4AiqbHX#fuGvO=jwe#voBQazgMg>t&u zyqa=}UC3wY>8N1wVYzoyZu`-&Oq)PC3r|VRJSL!@vfT%W2h>1bi2E$WXoA&B`iWxq zL|3K2Ukt}c&%OXV3#$#TT{i+3Yc)}jyae$e4wdY@BMB ziuJRFa0<=b;|r>V92v+3J2%wojv9(9?XXh2fX@Dd9_vK}LHT=$Ls_m9LhduWj>U?N zY^NKT=PSD>F0PbH!ak!ZYidWK{w+;D32PQkfr0%v)Jr2gHC9cAUy6re2i^8kGeOU1zjD^_guOcIVLQcV1mODt;Mv`wz_b~^ zoEUVmGPFk#lKlgtkQs_soFEpE*YOX;xi|cR2)YuH>3Kh=Bi@x%$!);#y(xnz_tz!C z;q+fsyRCF+6ilMQa>A*C34qfesop#MpvFal-A6=R|C+8f(`EC>FK6doXb|X=Lw|Do ze2*B}+SBB}+NsHGXH5N?FbO*zyS?7@{f-2?UV!g$8+>^m>?`wSy^|)-rys#Ej)fcrOtSABYeI?m@ zy6fk7Ef2qU+$cI#zGZZaS{IR$4?A<2YP_=0>HZ~WHh3+se1?`C95lLA zDX>x+`l4t$X?8Mh8_L;X6hc^&w2LVSl4MWXar7y0#=L<>&SpEEAvuM_=j@W6%NMp{ z!SC&URz}o>GtF_SST^%qEQnA6!`mwO+#Q52{$2r~vrR0Eihzrw$Nx6$SA-3R%C z`2LaHW~O(bsngb!xvcd2ZU5Fs&9$eG$Y>nu_s*~_d@o}&YFx0ZC}dV;S_{m7Tn!yH zf=M4gS`@V^*+Jt{81|A>R@%R$p3pqvWn`oIqLY-xVfAWX6?c9|0tk?IMtH!AJ*-t|+WR=J;bqr8irns6p3%l@{gP$39yRcc?EO=|r zP|Vg};EG0No385;1~Gm5zhIhfugdU?JICJ?M5LC#rAaMlJXMLHW~lXO5)*K?^OrlZ z#EW6b$AL`v9n4KQ9Rs-U{$rGDDQ#9?s0-^pg_($A{d#AKxhBfRM*Z5C;*;k|1F0E+ zZ&C3!6uG-nHgu^xe;^+5cxK6+;_{EHpIF6ZtmY+8hw$Fh;=)k5g+jmQ5=F~H+>7v87_8{`BHysp+R!Ccgp0s>{ezky&(Lfz*nfv}DXyl@9 zE3g(@VAXgWB;e_GH8xM!dxH!MVy8E3B-8tj&wV~+oZri>+l&%U2stSDk|FIeYqvR- zP?4611CtzU1W)XzHao5QzE~|VCk60umv^R)M!wf7Derr+CqyIu}5sGVv8B8 zNTdz1-~68EeLwFX=bV4ex$o<`?(g@y?)!7%j2}N>q~oOn004{z`u9x8&;I`|8fx;r z+NvfW0O0X6xCb^1$=$QJg^TyTa%gxZCLQM_!9_iuW$VT-PQ{%YPC=SQu8Ti877u+S z_?L@7M@7BH-Fv-Lh3-3t2r5851e6%*m#xsz(J@>D`d8jsX$h}rurPlW{0etc{Pj25 z(SB;bx!TBanCj9k5~jEq?%BO*HwO-6Kj zo20Sh{Gvm0Y_-J0DU2-}_ta=-qVAxoV<&|+AUs+l;4i$8GY3u$Nj6jFj58-oN$bli zFEt)fCL30*nh8w2ZtyTmRK4*vDW~|NViaF&Q!FXJaU)mq?o;GiV>b)UoG`D`o08fZ z*-w#olCk3JJwdQWD67`*^^TV<^b}LnMcOiB8w-;aiWm>nM*16B%!W1wgN--%q@Eu|tbGO_D;*lBX|Bzy^;m^cqqXM

>+H{M~b8>%pf3JKtc-k{y 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%0D5`$twgTSVjp;W&a%weXFx{XI`>KYXf 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 literal 0 HcmV?d00001 From 61aa874f09893663678d46cdd412321ce504eae7 Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 19:42:55 +0530 Subject: [PATCH 095/306] Added Ui for Search bar for message searching and also manage exit button on Action bar --- src/bitmessagekivy/main.kv | 26 ++++++++++++++++++-------- src/bitmessagekivy/mpybit.py | 15 +++++++++++++++ src/images/search.png | Bin 0 -> 2982 bytes 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/images/search.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 4b4316d4..1b7b2a6b 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -46,14 +46,24 @@ BoxLayout: title: app.getCurrentAccount() background_color: app.theme_cls.primary_dark left_action_items: [['menu', lambda x: app.nav_drawer.toggle()]] - Button: - text:"EXIT" - color: 0,0,0,1 - background_color: (0,0,0,0) - size_hint_y: 0.4 - size_hint_x: 0.1 - pos_hint: {'x': 0.8, 'y':0.4} - on_press: app.say_exit() + + ActionView: + SearchBar: + size_hint_x: 1.7 + size_hint_y: .5 + pos_hint: {'x': 0, 'center_y':.5} + on_text_validate: searchbutt.trigger_action() + + ActionPrevious: + with_previous: False + app_icon: '' + + ActionOverflow: + ActionButton: + text: 'Filters' + ActionButton: + text: 'Exit' + on_press: app.say_exit() ScreenManager: id: scr_mngr diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a5241e0a..1d4f7178 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -20,6 +20,7 @@ from helper_ackPayload import genAckPayload from addresses import decodeAddress, addBMIfNotPresent from helper_sql import sqlExecute from kivy.core.window import Window +from kivy.uix.actionbar import ActionItem statusIconColor = 'red' @@ -43,11 +44,15 @@ class NavigateApp(App, TextInput): return main_widget def _key_handler(self, instance, key, *args): + """Escape key manages previous screen on back.""" if key is 27: + print(args) + print(instance) self.set_previous_screen() return True def set_previous_screen(self): + """Set previous screen based on back.""" if self.root.ids.scr_mngr.current != 'inbox': self.root.ids.scr_mngr.transition.direction = 'left' self.root.ids.scr_mngr.current = 'inbox' @@ -401,5 +406,15 @@ class NewIdentity(Screen): self.manager.current = 'add_sucess' +class SearchBar(TextInput, ActionItem): + def __init__(self, *args, **kwargs): + super(SearchBar, self).__init__(*args, **kwargs) + self.hint_text = 'Search' + + def search(self): + request = self.text + return str(request) + + if __name__ == '__main__': NavigateApp().run() diff --git a/src/images/search.png b/src/images/search.png new file mode 100644 index 0000000000000000000000000000000000000000..42a1e45a82f694cc0dc187370b080b43ef6b8040 GIT binary patch literal 2982 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 literal 0 HcmV?d00001 From ef21351486582883f89f680b8a8eb9e8cafd905f Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 19:48:57 +0530 Subject: [PATCH 096/306] fix pylint issues based on commit relevant to Search bar --- src/bitmessagekivy/mpybit.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 1d4f7178..28321e01 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -407,11 +407,15 @@ class NewIdentity(Screen): class SearchBar(TextInput, ActionItem): + """Create SearchBar for PyBitmessage.""" + def __init__(self, *args, **kwargs): + """Initailizes SearchBar with hint text.""" super(SearchBar, self).__init__(*args, **kwargs) self.hint_text = 'Search' def search(self): + """Search for message request.""" request = self.text return str(request) From 73ce4b4c83ec2327b0aa36355e2b16c267a68a63 Mon Sep 17 00:00:00 2001 From: surbhi Date: Thu, 9 May 2019 18:18:29 +0530 Subject: [PATCH 097/306] rebase conflict fix and Ui Enhancement with dynamic addressbook updation and sent screen updation Ui Enhancement with dynamic addressbook updation and sent screen updation Changes made for Sent Items refresh feature with auto add new message in kivy --- build/README.md | 2 - build/changelang.sh | 16 - build/compiletest.py | 23 - build/mergepullrequest.sh | 11 - build/osx.sh | 26 - build/updatetranslations.sh | 22 - .../platform/python-for-android-new-toolchain | 1 + .../recipes/bitmsghash/__init__.py | 50 + .../recipes/kivymd/__init__.py | 60 + .../kivymd/kivymd-fix-dev-compatibility.patch | 36 + src/bitmessagekivy/kivy_helper_search.py | 4 +- src/bitmessagekivy/main.kv | 914 ++++++---- src/bitmessagekivy/mpybit.py | 1001 +++++++---- src/bitmessagekivy/uikivysignaler.py | 23 + src/bitmessagemain.py | 18 +- src/bitmsghash/bitmsghash.cpp | 44 +- src/buildozer.spec | 39 +- src/class_addressGenerator.py | 13 +- src/class_singleWorker.py | 3 + src/debug.py | 2 +- src/depends.py | 9 +- src/helper_generic.py | 114 ++ src/helper_startup.py | 2 + src/images/account_multiple.png | Bin 0 -> 9798 bytes src/images/addressbookadd.png | Bin 0 -> 7765 bytes src/kivymd/LICENSE | 21 - src/kivymd/__init__.py | 6 - src/kivymd/accordion.py | 254 --- src/kivymd/backgroundcolorbehavior.py | 23 - src/kivymd/bottomsheet.py | 211 --- src/kivymd/button.py | 453 ----- src/kivymd/card.py | 58 - src/kivymd/color_definitions.py | 360 ---- src/kivymd/date_picker.py | 325 ---- src/kivymd/dialog.py | 176 -- src/kivymd/elevationbehavior.py | 187 -- .../fonts/Material-Design-Iconic-Font.ttf | Bin 99212 -> 0 bytes src/kivymd/fonts/Roboto-Bold.ttf | Bin 163448 -> 0 bytes src/kivymd/fonts/Roboto-Italic.ttf | Bin 132440 -> 0 bytes src/kivymd/fonts/Roboto-Light.ttf | Bin 140276 -> 0 bytes src/kivymd/fonts/Roboto-LightItalic.ttf | Bin 133172 -> 0 bytes src/kivymd/fonts/Roboto-Medium.ttf | Bin 137308 -> 0 bytes src/kivymd/fonts/Roboto-MediumItalic.ttf | Bin 134312 -> 0 bytes src/kivymd/fonts/Roboto-Regular.ttf | Bin 145348 -> 0 bytes src/kivymd/fonts/Roboto-Thin.ttf | Bin 130044 -> 0 bytes src/kivymd/fonts/Roboto-ThinItalic.ttf | Bin 132860 -> 0 bytes src/kivymd/grid.py | 168 -- src/kivymd/icon_definitions.py | 1569 ----------------- src/kivymd/images/kivymd_512.png | Bin 30694 -> 0 bytes src/kivymd/images/kivymd_logo.png | Bin 42074 -> 0 bytes src/kivymd/images/quad_shadow-0.png | Bin 29962 -> 0 bytes src/kivymd/images/quad_shadow-1.png | Bin 30186 -> 0 bytes src/kivymd/images/quad_shadow-2.png | Bin 19289 -> 0 bytes src/kivymd/images/quad_shadow.atlas | 1 - src/kivymd/images/rec_shadow-0.png | Bin 46593 -> 0 bytes src/kivymd/images/rec_shadow-1.png | Bin 43957 -> 0 bytes src/kivymd/images/rec_shadow.atlas | 1 - src/kivymd/images/rec_st_shadow-0.png | Bin 30721 -> 0 bytes src/kivymd/images/rec_st_shadow-1.png | Bin 32265 -> 0 bytes src/kivymd/images/rec_st_shadow-2.png | Bin 28526 -> 0 bytes src/kivymd/images/rec_st_shadow.atlas | 1 - src/kivymd/images/round_shadow-0.png | Bin 39635 -> 0 bytes src/kivymd/images/round_shadow-1.png | Bin 40767 -> 0 bytes src/kivymd/images/round_shadow-2.png | Bin 26510 -> 0 bytes src/kivymd/images/round_shadow.atlas | 1 - src/kivymd/label.py | 94 - src/kivymd/list.py | 531 ------ src/kivymd/material_resources.py | 50 - src/kivymd/menu.py | 192 -- src/kivymd/navigationdrawer.py | 76 - src/kivymd/progressbar.py | 79 - src/kivymd/ripplebehavior.py | 169 -- src/kivymd/selectioncontrols.py | 240 --- src/kivymd/slider.py | 247 --- src/kivymd/slidingpanel.py | 92 - src/kivymd/snackbar.py | 115 -- src/kivymd/spinner.py | 149 -- src/kivymd/tabs.py | 303 ---- src/kivymd/textfields.py | 215 --- src/kivymd/theme_picker.py | 422 ----- src/kivymd/theming.py | 350 ---- src/kivymd/time_picker.py | 84 - src/kivymd/toolbar.py | 98 - src/kivymd/vendor/__init__.py | 1 - src/kivymd/vendor/circleLayout/LICENSE | 22 - src/kivymd/vendor/circleLayout/README.md | 21 - src/kivymd/vendor/circleLayout/__init__.py | 196 -- src/kivymd/vendor/circularTimePicker/LICENSE | 22 - .../vendor/circularTimePicker/README.md | 43 - .../vendor/circularTimePicker/__init__.py | 770 -------- src/main.py | 4 +- src/navigationdrawer/__init__.py | 82 - src/network/networkthread.py | 2 + src/paths.py | 21 +- src/plugins/menu_qrcode.py | 2 +- src/proofofwork.py | 14 +- src/pyelliptic/openssl.py | 9 +- src/semaphores.py | 3 + src/shared.py | 19 +- src/singleinstance.py | 3 +- src/state.py | 4 + src/tr.py | 10 +- 102 files changed, 1674 insertions(+), 9328 deletions(-) delete mode 100644 build/README.md delete mode 100755 build/changelang.sh delete mode 100755 build/compiletest.py delete mode 100755 build/mergepullrequest.sh delete mode 100755 build/osx.sh delete mode 100755 build/updatetranslations.sh create mode 160000 src/.buildozer/android/platform/python-for-android-new-toolchain create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py create mode 100644 src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch create mode 100644 src/bitmessagekivy/uikivysignaler.py create mode 100644 src/helper_generic.py create mode 100644 src/images/account_multiple.png create mode 100644 src/images/addressbookadd.png delete mode 100644 src/kivymd/LICENSE delete mode 100644 src/kivymd/__init__.py delete mode 100644 src/kivymd/accordion.py delete mode 100644 src/kivymd/backgroundcolorbehavior.py delete mode 100644 src/kivymd/bottomsheet.py delete mode 100644 src/kivymd/button.py delete mode 100644 src/kivymd/card.py delete mode 100644 src/kivymd/color_definitions.py delete mode 100644 src/kivymd/date_picker.py delete mode 100644 src/kivymd/dialog.py delete mode 100644 src/kivymd/elevationbehavior.py delete mode 100644 src/kivymd/fonts/Material-Design-Iconic-Font.ttf delete mode 100644 src/kivymd/fonts/Roboto-Bold.ttf delete mode 100644 src/kivymd/fonts/Roboto-Italic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Light.ttf delete mode 100644 src/kivymd/fonts/Roboto-LightItalic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Medium.ttf delete mode 100644 src/kivymd/fonts/Roboto-MediumItalic.ttf delete mode 100644 src/kivymd/fonts/Roboto-Regular.ttf delete mode 100644 src/kivymd/fonts/Roboto-Thin.ttf delete mode 100644 src/kivymd/fonts/Roboto-ThinItalic.ttf delete mode 100644 src/kivymd/grid.py delete mode 100644 src/kivymd/icon_definitions.py delete mode 100644 src/kivymd/images/kivymd_512.png delete mode 100644 src/kivymd/images/kivymd_logo.png delete mode 100644 src/kivymd/images/quad_shadow-0.png delete mode 100644 src/kivymd/images/quad_shadow-1.png delete mode 100644 src/kivymd/images/quad_shadow-2.png delete mode 100644 src/kivymd/images/quad_shadow.atlas delete mode 100644 src/kivymd/images/rec_shadow-0.png delete mode 100644 src/kivymd/images/rec_shadow-1.png delete mode 100644 src/kivymd/images/rec_shadow.atlas delete mode 100644 src/kivymd/images/rec_st_shadow-0.png delete mode 100644 src/kivymd/images/rec_st_shadow-1.png delete mode 100644 src/kivymd/images/rec_st_shadow-2.png delete mode 100644 src/kivymd/images/rec_st_shadow.atlas delete mode 100644 src/kivymd/images/round_shadow-0.png delete mode 100644 src/kivymd/images/round_shadow-1.png delete mode 100644 src/kivymd/images/round_shadow-2.png delete mode 100644 src/kivymd/images/round_shadow.atlas delete mode 100644 src/kivymd/label.py delete mode 100644 src/kivymd/list.py delete mode 100644 src/kivymd/material_resources.py delete mode 100644 src/kivymd/menu.py delete mode 100644 src/kivymd/navigationdrawer.py delete mode 100644 src/kivymd/progressbar.py delete mode 100644 src/kivymd/ripplebehavior.py delete mode 100644 src/kivymd/selectioncontrols.py delete mode 100644 src/kivymd/slider.py delete mode 100644 src/kivymd/slidingpanel.py delete mode 100644 src/kivymd/snackbar.py delete mode 100644 src/kivymd/spinner.py delete mode 100644 src/kivymd/tabs.py delete mode 100644 src/kivymd/textfields.py delete mode 100644 src/kivymd/theme_picker.py delete mode 100644 src/kivymd/theming.py delete mode 100644 src/kivymd/time_picker.py delete mode 100644 src/kivymd/toolbar.py delete mode 100644 src/kivymd/vendor/__init__.py delete mode 100644 src/kivymd/vendor/circleLayout/LICENSE delete mode 100644 src/kivymd/vendor/circleLayout/README.md delete mode 100644 src/kivymd/vendor/circleLayout/__init__.py delete mode 100644 src/kivymd/vendor/circularTimePicker/LICENSE delete mode 100644 src/kivymd/vendor/circularTimePicker/README.md delete mode 100644 src/kivymd/vendor/circularTimePicker/__init__.py delete mode 100644 src/navigationdrawer/__init__.py create mode 100644 src/semaphores.py diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 248d2c41..00000000 --- a/build/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains scripts that are helpful for developers when building -or maintaining PyBitmessage. diff --git a/build/changelang.sh b/build/changelang.sh deleted file mode 100755 index 915c5dea..00000000 --- a/build/changelang.sh +++ /dev/null @@ -1,16 +0,0 @@ -export LANG=de_DE.UTF-8 -export LANGUAGE=de_DE -export LC_CTYPE="de_DE.UTF-8" -export LC_NUMERIC=de_DE.UTF-8 -export LC_TIME=de_DE.UTF-8 -export LC_COLLATE="de_DE.UTF-8" -export LC_MONETARY=de_DE.UTF-8 -export LC_MESSAGES="de_DE.UTF-8" -export LC_PAPER=de_DE.UTF-8 -export LC_NAME=de_DE.UTF-8 -export LC_ADDRESS=de_DE.UTF-8 -export LC_TELEPHONE=de_DE.UTF-8 -export LC_MEASUREMENT=de_DE.UTF-8 -export LC_IDENTIFICATION=de_DE.UTF-8 -export LC_ALL= -python2.7 src/bitmessagemain.py diff --git a/build/compiletest.py b/build/compiletest.py deleted file mode 100755 index fdbf7db1..00000000 --- a/build/compiletest.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python2.7 - -import ctypes -import fnmatch -import os -import sys -import traceback - -matches = [] -for root, dirnames, filenames in os.walk('src'): - for filename in fnmatch.filter(filenames, '*.py'): - matches.append(os.path.join(root, filename)) - -for filename in matches: - source = open(filename, 'r').read() + '\n' - try: - compile(source, filename, 'exec') - except Exception as e: - if 'win' in sys.platform: - ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) - else: - print "Exception in %s: %s" % (filename, traceback.format_exc()) - sys.exit(1) diff --git a/build/mergepullrequest.sh b/build/mergepullrequest.sh deleted file mode 100755 index 35e87566..00000000 --- a/build/mergepullrequest.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ]; then - echo "You must specify pull request number" - exit -fi - -git pull -git checkout v0.6 -git fetch origin pull/"$1"/head:"$1" -git merge --ff-only "$1" diff --git a/build/osx.sh b/build/osx.sh deleted file mode 100755 index e58a49f4..00000000 --- a/build/osx.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# OS X Build script wrapper around the py2app script. -# This build can only be generated on OS X. -# Requires all build dependencies for Bitmessage -# Especially important is OpenSSL installed through brew - -export ARCHFLAGS="-arch i386 -arch x86_64" - -if [[ -z "$1" ]]; then - echo "Please supply a version number for this release as the first argument." - exit -fi - -echo "Creating OS X packages for Bitmessage." - -export PYBITMESSAGEVERSION=$1 - -cd src && python2.7 build_osx.py py2app - -if [[ $? = "0" ]]; then - hdiutil create -fs HFS+ -volname "Bitmessage" -srcfolder dist/Bitmessage.app dist/bitmessage-v$1.dmg -else - echo "Problem creating Bitmessage.app, stopping." - exit -fi diff --git a/build/updatetranslations.sh b/build/updatetranslations.sh deleted file mode 100755 index ba5a3fdb..00000000 --- a/build/updatetranslations.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [ ! -f "$1" ]; then - echo "$1 not found, please specify the file name for source" - exit -fi - -srcdir=`mktemp -d` - -unzip "$1" -d $srcdir - -for i in $srcdir/*ts; do - o=`basename $i|cut -b3-` - o="${o,,}" - o="${o//@/_}" - echo "$i -> $o" - mv "$i" "$HOME/src/PyBitmessage/src/translations/$o" -done - -rm -rf -- $srcdir - -lrelease-qt4 "$HOME/src/PyBitmessage/src/translations/bitmessage.pro" diff --git a/src/.buildozer/android/platform/python-for-android-new-toolchain b/src/.buildozer/android/platform/python-for-android-new-toolchain new file mode 160000 index 00000000..5aa322da --- /dev/null +++ b/src/.buildozer/android/platform/python-for-android-new-toolchain @@ -0,0 +1 @@ +Subproject commit 5aa322da9179dae305fde5af1db516c1ad9baea4 diff --git a/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py new file mode 100644 index 00000000..4566ebfb --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/bitmsghash/__init__.py @@ -0,0 +1,50 @@ +from pythonforandroid.toolchain import Recipe, shprint, shutil, current_directory +from os.path import exists, join +import os +import sys +from multiprocessing import cpu_count +import sh + + +class BitmsghashRecipe(Recipe): + # This could also inherit from PythonRecipe etc. if you want to + # use their pre-written build processes + + url = 'https://github.com/surbhicis/bitmsghash/archive/master.zip' + # {version} will be replaced with self.version when downloading + + depends = ['openssl'] + + conflicts = [] + + def get_recipe_env(self, arch=None): + env = super(BitmsghashRecipe, self).get_recipe_env(arch) + r = Recipe.get_recipe('openssl', self.ctx) + b = r.get_build_dir(arch.arch) + env['CCFLAGS'] = env['CFLAGS'] = \ + env['CFLAGS'] + ' -I{openssl_build_path}/include ' \ + '-I{openssl_build_path}/include/openssl'.format( + openssl_build_path=b) + env['LDFLAGS'] = \ + env['LDFLAGS'] + ' -L{openssl_build_path} ' \ + '-lcrypto{openssl_version} ' \ + '-lssl{openssl_version}'.format( + openssl_build_path=b, + openssl_version=r.version) + return env + + def should_build(self, arch=None): + super(BitmsghashRecipe, self).should_build(arch) + return not exists( + join(self.ctx.get_libs_dir(arch.arch), 'libbitmsghash.so')) + + def build_arch(self, arch=None): + super(BitmsghashRecipe, self).build_arch(arch) + env = self.get_recipe_env(arch) + with current_directory(join(self.get_build_dir(arch.arch))): + dst_dir = join(self.get_build_dir(arch.arch)) + shprint(sh.make, '-j', str(cpu_count()), _env=env) + self.install_libs(arch, '{}/libbitmsghash.so'.format(dst_dir), + 'libbitmsghash.so') + +recipe = BitmsghashRecipe() diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py new file mode 100644 index 00000000..b49013a7 --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py @@ -0,0 +1,60 @@ +from os import environ +from os.path import exists, join + +import sh +from pythonforandroid.logger import shprint, info_main, info +from pythonforandroid.recipe import PythonRecipe +# from pythonforandroid.util import ensure_dir + + +class KivyMDRecipe(PythonRecipe): + # This recipe installs KivyMD into the android dist from source + version = 'master' + # url = 'https://gitlab.com/kivymd/KivyMD/repository/{version}/archive.zip' + url = 'https://github.com/HeaTTheatR/KivyMD/archive/master.zip' + depends = ['kivy'] + site_packages_name = 'kivymd' + call_hostpython_via_targetpython = False + # patches = ['kivymd-fix-dev-compatibility.patch'] + # Made commented as use different repo for updates + + def should_build(self, arch): + return True + + # def unpack(self, arch): + # info_main('Unpacking {} for {}'.format(self.name, arch)) + # + # build_dir = self.get_build_container_dir(arch) + # + # user_dir = environ.get('P4A_{}_DIR'.format(self.name.lower())) + # + # if user_dir is not None: + # info("Installing KivyMD development version (from modded source)") + # self.clean_build() + # shprint(sh.rm, '-rf', build_dir) + # shprint(sh.mkdir, '-p', build_dir) + # shprint(sh.rmdir, build_dir) + # ensure_dir(build_dir) + # ensure_dir(build_dir + "/kivymd") + # shprint(sh.cp, user_dir + '/setup.py', self.get_build_dir(arch) + "/setup.py") + # shprint(sh.cp, '-a', user_dir + "/kivymd", self.get_build_dir(arch) + "/kivymd") + # return + + def get_recipe_env(self, arch): + env = super(KivyMDRecipe, self).get_recipe_env(arch) + env['PYTHON_ROOT'] = self.ctx.get_python_install_dir() + env['CFLAGS'] += ' -I' + env['PYTHON_ROOT'] + '/include/python2.7' + env['LDFLAGS'] += ' -L' + env['PYTHON_ROOT'] + '/lib' + \ + ' -lpython2.7' + if 'sdl2' in self.ctx.recipe_build_order: + env['USE_SDL2'] = '1' + env['KIVY_SDL2_PATH'] = ':'.join([ + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'), + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'), + ]) + return env + + +recipe = KivyMDRecipe() diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch new file mode 100644 index 00000000..bc8d5dee --- /dev/null +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/kivymd-fix-dev-compatibility.patch @@ -0,0 +1,36 @@ +diff -Naurp KivyMD.orig/kivymd/button.py KivyMD/kivymd/button.py +--- KivyMD.orig/kivymd/button.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/button.py 2018-07-10 10:37:55.719440354 +0200 +@@ -175,7 +175,8 @@ class BaseButton(ThemableBehavior, Butto + self._current_button_color = self.md_bg_color_disabled + else: + self._current_button_color = self.md_bg_color +- super(BaseButton, self).on_disabled(instance, value) ++ # To add compatibility to last kivy (disabled is now an Alias property) ++ # super(BaseButton, self).on_disabled(instance, value) + + + class BasePressedButton(BaseButton): +diff -Naurp KivyMD.orig/kivymd/selectioncontrols.py KivyMD/kivymd/selectioncontrols.py +--- KivyMD.orig/kivymd/selectioncontrols.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/selectioncontrols.py 2018-07-10 10:40:06.971439102 +0200 +@@ -45,6 +45,7 @@ Builder.load_string(''' + pos: self.pos + + : ++ _thumb_pos: (self.right - dp(12), self.center_y - dp(12)) if self.active else (self.x - dp(12), self.center_y - dp(12)) + canvas.before: + Color: + rgba: self._track_color_disabled if self.disabled else \ +diff -Naurp KivyMD.orig/kivymd/tabs.py KivyMD/kivymd/tabs.py +--- KivyMD.orig/kivymd/tabs.py 2017-08-25 13:12:34.000000000 +0200 ++++ KivyMD/kivymd/tabs.py 2018-07-10 10:39:20.603439544 +0200 +@@ -185,7 +185,7 @@ class MDBottomNavigationBar(ThemableBeha + + class MDTabHeader(MDFlatButton): + """ Internal widget for headers based on MDFlatButton""" +- ++ + width = BoundedNumericProperty(dp(0), min=dp(72), max=dp(264), errorhandler=lambda x: dp(72)) + tab = ObjectProperty(None) + panel = ObjectProperty(None) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 684a1722..6758f554 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -9,7 +9,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if folder == "sent": sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime + SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' else: sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read @@ -42,4 +42,4 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) + return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1b7b2a6b..dc74450d 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,203 +1,243 @@ -#:import la kivy.adapters.listadapter -#:import factory kivy.factory -#:import mpybit bitmessagekivy.mpybit -#:import C kivy.utils.get_color_from_hex -: - id: nav_drawer +#:import Toolbar kivymd.toolbar.Toolbar +#:import ThemeManager kivymd.theming.ThemeManager +#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer +#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout +#:import NavigationDrawerDivider kivymd.navigationdrawer.NavigationDrawerDivider +#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar +#:import NavigationDrawerSubheader kivymd.navigationdrawer.NavigationDrawerSubheader +#:import MDCheckbox kivymd.selectioncontrols.MDCheckbox +#:import MDSwitch kivymd.selectioncontrols.MDSwitch +#:import MDList kivymd.list.MDList +#:import OneLineListItem kivymd.list.OneLineListItem +#:import TwoLineListItem kivymd.list.TwoLineListItem +#:import ThreeLineListItem kivymd.list.ThreeLineListItem +#:import OneLineAvatarListItem kivymd.list.OneLineAvatarListItem +#:import OneLineIconListItem kivymd.list.OneLineIconListItem +#:import OneLineAvatarIconListItem kivymd.list.OneLineAvatarIconListItem +#:import MDTextField kivymd.textfields.MDTextField +#:import MDSpinner kivymd.spinner.MDSpinner +#:import MDCard kivymd.card.MDCard +#:import MDSeparator kivymd.card.MDSeparator +#:import MDDropdownMenu kivymd.menu.MDDropdownMenu +#:import get_color_from_hex kivy.utils.get_color_from_hex +#:import colors kivymd.color_definitions.colors +#:import SmartTile kivymd.grid.SmartTile +#:import MDSlider kivymd.slider.MDSlider +#:import MDTabbedPanel kivymd.tabs.MDTabbedPanel +#:import MDTab kivymd.tabs.MDTab +#:import MDProgressBar kivymd.progressbar.MDProgressBar +#:import MDAccordion kivymd.accordion.MDAccordion +#:import MDAccordionItem kivymd.accordion.MDAccordionItem +#:import MDAccordionSubItem kivymd.accordion.MDAccordionSubItem +#:import MDThemePicker kivymd.theme_picker.MDThemePicker +#:import MDBottomNavigation kivymd.tabs.MDBottomNavigation +#:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem +#:import MDFloatingActionButton kivymd.button.MDFloatingActionButton + +: + icon: 'checkbox-blank-circle' + +: + drawer_logo: './images/drawer_logo1.png' + NavigationDrawerDivider: + + NavigationDrawerTwoLineListItem: + text: "Accounts" NavigationDrawerIconButton: Spinner: - pos_hint:{"x":0,"y":.3} + pos_hint:{"x":0,"y":.25} id: btn - background_color: app.theme_cls.primary_dark - text: app.showmeaddresses(name='text') - values: app.showmeaddresses(name='values') + text: app.getDefaultAccData() + values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - NavigationDrawerIconButton: icon: 'email-open' - text: "inbox" + text: "Inbox" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "99+" + NavigationDrawerIconButton: + icon: 'send' + text: "Sent" + on_release: app.root.ids.scr_mngr.current = 'sent' + badge_text: "2" + NavigationDrawerIconButton: + icon: 'message-draw' + text: "Draft" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "99+" + NavigationDrawerIconButton: + text: "Starred" + icon:'star' on_release: app.root.ids.scr_mngr.current = 'inbox' NavigationDrawerIconButton: - icon: 'mail-send' - text: "sent" - on_release: app.root.ids.scr_mngr.current = 'sent' - NavigationDrawerIconButton: - icon: 'dropbox' - text: "trash" + icon: 'archive' + text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'trash' + badge_text: "9+" NavigationDrawerIconButton: - icon: 'email' - text: "drafts" - on_release: app.root.ids.scr_mngr.current = 'dialog' + icon: 'email-open-outline' + text: "Spam" + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "8+" NavigationDrawerIconButton: - icon: 'markunread-mailbox' - text: "test" - on_release: app.root.ids.scr_mngr.current = 'test' + icon: 'delete' + text: "Trash" + on_release: app.root.ids.scr_mngr.current = 'trash' + badge_text: "9+" NavigationDrawerIconButton: - text: "new identity" - icon:'accounts-add' - on_release: app.root.ids.scr_mngr.current = 'newidentity' - -BoxLayout: - orientation: 'vertical' - Toolbar: - id: toolbar - title: app.getCurrentAccount() - background_color: app.theme_cls.primary_dark - left_action_items: [['menu', lambda x: app.nav_drawer.toggle()]] + text: "All Mails" + icon:'contact-mail' + on_release: app.root.ids.scr_mngr.current = 'inbox' + badge_text: "999+" + NavigationDrawerDivider: + NavigationDrawerSubheader: + text: "All labels" + NavigationDrawerIconButton: + text: "Address Book" + icon:'book-multiple' + on_release: app.root.ids.scr_mngr.current = 'addressbook' + NavigationDrawerIconButton: + text: "Settings" + icon:'settings' + on_release: app.root.ids.scr_mngr.current = 'set' + NavigationDrawerIconButton: + text: "Subscriptions/Payment" + icon:'wallet' + on_release: app.root.ids.scr_mngr.current = 'payment' + NavigationDrawerIconButton: + text: "new address" + icon:'account-plus' + on_release: app.root.ids.scr_mngr.current = 'login' + NavigationDrawerIconButton: + text: "Network Status" + icon:'server-network' + on_release: app.root.ids.scr_mngr.current = 'networkstat' + NavigationDrawerIconButton: + text: "My Addresses" + icon:'account-multiple' + on_release: app.root.ids.scr_mngr.current = 'myaddress' - ActionView: - SearchBar: - size_hint_x: 1.7 - size_hint_y: .5 - pos_hint: {'x': 0, 'center_y':.5} - on_text_validate: searchbutt.trigger_action() +NavigationLayout: + id: nav_layout - ActionPrevious: - with_previous: False - app_icon: '' + ContentNavigationDrawer: + id: nav_drawer - ActionOverflow: - ActionButton: - text: 'Filters' - ActionButton: - text: 'Exit' - on_press: app.say_exit() - - ScreenManager: - id: scr_mngr - Inbox: - id:sc1 - Sent: - id:sc2 - Trash: - id:sc3 - Dialog: - id:sc4 - Test: - id:sc5 - Create: - id:sc6 - NewIdentity: - id:sc7 - Page: - id:sc8 - AddressSuccessful: - id:sc9 - - Button: - id:create - height:100 - size_hint_y: 0.13 - size_hint_x: 0.1 - pos_hint: {'x': 0.85, 'y': 0.5} - background_color: (0,0,0,0) - on_press: scr_mngr.current = 'create' - Image: - source: 'images/plus.png' - y: self.parent.y - 7.5 - x: self.parent.x + self.parent.width - 50 - size: 70, 70 - -: - text: '' - size_hint_y: None - height: 48 - ignore_perpendicular_swipes: True - data_index: 0 - min_move: 20 / self.width - - on__offset: app.update_index(root.data_index, self.index) - - canvas.before: - Color: - rgba: C('FFFFFF33') - - Rectangle: - pos: self.pos - size: self.size - - Line: - rectangle: self.pos + self.size - - Button: - text: 'delete ({}:{})'.format(root.text, root.data_index) - on_press: app.delete(root.data_index) - - Button: - text: root.text - on_press: app.getInboxMessageDetail(self.text) - - Button: - text: 'archive' - on_press: app.archive(root.data_index) + BoxLayout: + orientation: 'vertical' + Toolbar: + id: toolbar.. + md_bg_color: app.theme_cls.primary_color + background_palette: 'Primary' + background_hue: '500' + left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] + Button: + id: myButton + size_hint_y: 0.35 + size_hint_x: 0.2 + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.addingtoaddressbook() + Image: + source: './images/addressbookadd.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + ScreenManager: + id: scr_mngr + Inbox: + id:sc1 + Page: + id:sc2 + Create: + id:sc3 + Sent: + id:sc4 + Trash: + id:sc5 + Login: + id:sc6 + Random: + id:sc7 + AddressSuccessful: + id:sc8 + Setting: + id:sc9 + MyAddress: + id:sc10 + AddressBook: + id:sc11 + Payment: + id:sc12 + NetworkStat: + id:sc13 : name: 'inbox' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + 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' : name: 'sent' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + 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' : name: 'trash' - RecycleView: - data: root.data - viewclass: 'SwipeButton' + ScrollView: do_scroll_x: False - scroll_timeout: 100 + MDList: + id: ml + BoxLayout: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} - RecycleBoxLayout: - id:rc - orientation: 'vertical' - size_hint_y: None - height: self.minimum_height - default_size_hint: 1, None - canvas.before: - Color: - rgba: 0,0,0, 1 - Rectangle: - pos: self.pos - size: self.size + Widget: -

: - name: 'dialog' + 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' + +: + name: 'draft' Label: text:"I have a good dialox box" color: 0,0,0,1 @@ -207,175 +247,391 @@ BoxLayout: text:"I am in test" color: 0,0,0,1 -: - name: 'create' - GridLayout: - rows: 5 - cols: 1 - padding: 60,60,60,60 - spacing: 50 - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'FROM' - color: 0,0,0,1 - Spinner: - size_hint: 1,1 - pos_hint: {"x":0,"top":1.} - pos: 10,10 - id: spinner_id - text: app.showmeaddresses(name='text') - values: app.showmeaddresses(name='values') - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'TO' - color: 0,0,0,1 - TextInput: - id: recipent - hint_text: 'To' - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'SUBJECT' - color: 0,0,0,1 - TextInput: - id: subject - hint_text: 'SUBJECT' - - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: 'BODY' - color: 0,0,0,1 - TextInput: - id: message - multiline:True - size_hint: 1,2 - - Button: - text: 'send' - size_hint_y: 0.1 - size_hint_x: 0.2 - height: '32dp' - pos_hint: {'x': .5, 'y': 0.1} - on_press: root.send() - Button: - text: 'cancel' - size_hint_y: 0.1 - size_hint_x: 0.2 - height: '32dp' - pos_hint: {'x': .72, 'y': 0.1} - on_press: root.cancel() - -: - name: 'newidentity' - GridLayout: - padding: '120dp' - cols: 1 - Label: - text:"""Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged.""" - line_height:1.5 - text_size:(700,None) - color: 0,0,0,1 - BoxLayout: - CheckBox: - canvas.before: - Color: - rgb: 1,0,0 - Ellipse: - pos:self.center_x-8, self.center_y-8 - size:[16,16] - group: "money" - id:chk - text:"use a random number generator to make an address" - on_active: - root.checked = self.text - active:root.is_active - - Label: - text: "use a random number generator to make an address" - color: 0,0,0,1 - BoxLayout: - CheckBox: - canvas.before: - Color: - rgb: 1,0,0 - Ellipse: - pos:self.center_x-8, self.center_y-8 - size:[16,16] - group: "money" - id:chk - text:"use a pseudo number generator to make an address" - on_active: - root.checked = self.text - active:not root.is_active - Label: - text: "use a pseudo number generator to make an address" - color: 0,0,0,1 - Label: - color: 0,0,0,1 - size_hint_x: .35 - markup: True - text: "[b]{}[/b]".format("Randomly generated addresses") - BoxLayout: - size_hint_y: None - height: '32dp' - Label: - text: "Label (not shown to anyone except you)" - color: 0,0,0,1 - BoxLayout: - size_hint_y: None - height: '32dp' - TextInput: - id: label - - Button: - text: 'Cancel' - size_hint_y: 0.1 - size_hint_x: 0.3 - height: '32dp' - pos_hint: {'x': .1, 'y': 0.1} - Button: - text: 'Ok' - size_hint_y: 0.1 - size_hint_x: 0.3 - height: '32dp' - pos_hint: {'x': .5, 'y': 0.1} - on_press: root.generateaddress() - : name: 'page' - ActionBar: - background_color:0,0,0,0 - pos_hint: {'top':0.98} - size_hint_y: 0.05 - size_hint_x: 0.07 - ActionView: - ActionPrevious: - with_previous: False - app_icon: 'images/back-button.png' - markup:True - font_size:"16dp" - on_release: app.set_previous_screen() Label: - text:"Message sent on 5 september 2018 05:44" + text:"I am on page" color: 0,0,0,1 - size: self.texture_size - size_hint: (None, None) - Label: - text: 'I am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\n' - color: 0,0,0,1 +: + name: 'create' + +: + ScrollView: + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(app.scr_size) + padding: dp(32) + spacing: 15 + BoxLayout: + orientation: 'vertical' + TextInput: + id: ti + hint_text: 'type or select sender address' + size_hint_y: None + height: 100 + multiline: False + + BoxLayout: + size_hint_y: None + height: 100 + Spinner: + background_color: app.theme_cls.primary_dark + id: btn + text: 'select' + values: app.variable_1 + on_text: ti.text = self.text + + BoxLayout: + orientation: 'vertical' + txt_input: txt_input + rv: rv + size : (890, 60) + size_hint: 1,2 + MyTextInput: + id: txt_input + size_hint_y: None + height: 100 + hint_text: 'type or search recipients address starting with BM-' + RV: + id: rv + TextInput: + id: subject + hint_text: 'subject' + size_hint_y: None + height: 100 + multiline: False + TextInput: + id: body + hint_text: 'body' + size_hint_y: None + height: 100 + multiline:True + size_hint: 1,2 + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'send' + on_press: root.send() + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'reset' + on_press: app.root.ids.scr_mngr.current = 'random' + +: + readonly: False + multiline: False + +: + # Draw a background to indicate selection + color: 0,0,0,1 + canvas.before: + Color: + rgba: app.theme_cls.primary_dark if self.selected else (1, 1, 1, 0) + Rectangle: + pos: self.pos + size: self.size + +: + canvas: + Color: + rgba: 0,0,0,.2 + + Line: + rectangle: self.x +1 , self.y, self.width - 2, self.height -2 + bar_width: 10 + scroll_type:['bars'] + viewclass: 'SelectableLabel' + SelectableRecycleBoxLayout: + default_size: None, dp(20) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + orientation: 'vertical' + multiselect: False + + +: + name: 'login' + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(800) + BoxLayout: + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "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 \n pros and cons:\n" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + BoxLayout: + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "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" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + MDCheckbox: + id: grp_chkbox_1 + group: 'test' + active: True + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "use a random number generator to make an address" + halign: 'center' + size_hint_y: None + bold: True + height: self.texture_size[1] + dp(4) + color: [0.941, 0, 0,1] + MDCheckbox: + id: grp_chkbox_1 + group: 'test' + MDLabel: + font_style: 'Caption' + theme_text_color: 'Primary' + text: "use a pseudo number generator to make an address" + halign: 'center' + size_hint_y: None + bold: True + color: [0.941, 0, 0,1] + height: self.texture_size[1] + dp(4) + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .5 + text: 'proceed' + on_press: app.root.ids.scr_mngr.current = 'random' + +: + name: 'random' + ScrollView: + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: self.minimum_height + padding: dp(48) + spacing: 200 + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "Random Addresses" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "Here you may generate as many addresses as you like, Indeed creating and abandoning addresses is encouraged" + halign: 'center' + bold: True + color:app.theme_cls.primary_dark + + MDTextField: + id: label + multiline: True + hint_text: "Label" + helper_text: "Label (not shown to anyone except you)" + helper_text_mode: "persistent" + MDRaisedButton: + text: 'next' + size_hint_y: 0.13 + size_hint_x: 0.8 + pos_hint: {'x': .1, 'y': 0.3} + opposite_colors: True + on_release: root.generateaddress() : name: 'add_sucess' Label: text: 'Successfully created a new bit address' color: 0,0,0,1 + +: + name: 'set' + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(500) + OneLineListItem: + text: "SERVER SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Server ' + on_press: app.root.ids.scr_mngr.current = 'random' + OneLineListItem: + text: "DATA SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Import or export data' + on_press: app.root.ids.scr_mngr.current = 'random' + OneLineListItem: + text: "OTHER SETTINGS" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: 'Restart background service' + on_press: app.root.ids.scr_mngr.current = 'random' + BoxLayout: + AnchorLayout: + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "bitmessage is 11 seconds behind the network" + halign: 'center' + bold: True + color: [0.941, 0, 0,1] + + BoxLayout: + MDCheckbox: + id: chkbox + size_hint: None, None + size: dp(48), dp(48) + active: True + MDLabel: + font_style: 'Body1' + theme_text_color: 'Primary' + text: "show settings (for advanced users only)" + halign: 'left' + bold: True + color: app.theme_cls.primary_dark + +: + name: 'myaddress' + ScrollView: + do_scroll_x: False + MDList: + id: ml + +: + name: 'addressbook' + BoxLayout: + orientation:'vertical' + ScrollView: + do_scroll_x: False + MDList: + id: ml + +: + name: 'payment' + + +: + id: popup + title: 'add contact\'s' + background: './images/popup.jpeg' + title_size: sp(30) + title_color: 0.4, 0.3765, 0.3451, 1 + size_hint: 1, 1 + auto_dismiss: False + separator_color: 0.3529, 0.3922, 0.102, 0.7 + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:50 + id: popup_box + orientation: 'vertical' + MDTextField: + id: label + multiline: True + hint_text: "Label" + required: True + helper_text_mode: "on_error" + MDTextField: + id: address + hint_text: "Address" + required: True + helper_text_mode: "on_error" + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Save' + on_release: + root.savecontact() + app.root.ids.scr_mngr.current = 'addressbook' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Cancel' + on_press: root.dismiss() + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Scan QR code' + +: + name: 'networkstat' + MDTabbedPanel: + id: tab_panel + tab_display_mode:'text' + + MDTab: + name: 'connections' + text: "Total connections" + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(200) + OneLineListItem: + text: "Total Connections" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .5 + text: root.text_variable_1 + MDTab: + name: 'processes' + text: 'Processes' + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(500) + OneLineListItem: + text: "person-to-person" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_2 + OneLineListItem: + text: "Brodcast" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_3 + OneLineListItem: + text: "publickeys" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_4 + + OneLineListItem: + text: "objects" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .8, .6 + text: root.text_variable_5 \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 28321e01..a6a29ead 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,349 +1,241 @@ -import kivy_helper_search -import os -import queues -import shutdown -import state -import time - +# -*- coding: utf-8 -*- from kivy.app import App from kivy.lang import Builder -from kivy.properties import BooleanProperty -from kivy.clock import Clock -from navigationdrawer import NavigationDrawer -from kivy.properties import ObjectProperty, StringProperty, ListProperty +from kivy.metrics import dp +from kivy.properties import ObjectProperty +from kivy.uix.image import Image from kivy.uix.screenmanager import Screen -from kivy.uix.textinput import TextInput +from kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet +from kivymd.button import MDIconButton +from kivymd.date_picker import MDDatePicker +from kivymd.dialog import MDDialog +from kivymd.label import MDLabel +from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch, BaseListItem +from kivymd.material_resources import DEVICE_TYPE +from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase +from kivymd.selectioncontrols import MDCheckbox +from kivymd.snackbar import Snackbar from kivymd.theming import ThemeManager -from kivymd.toolbar import Toolbar +from kivymd.time_picker import MDTimePicker +from kivymd.list import ThreeLineAvatarIconListItem, TwoLineAvatarIconListItem, TwoLineListItem +from kivy.properties import ListProperty, StringProperty, BooleanProperty +from kivy.clock import Clock from bmconfigparser import BMConfigParser -from helper_ackPayload import genAckPayload -from addresses import decodeAddress, addBMIfNotPresent -from helper_sql import sqlExecute +import state +import queues +from kivy.uix.popup import Popup +from helper_sql import * +from kivy.uix.gridlayout import GridLayout +from kivy.app import App +from kivy.uix.textinput import TextInput +from kivy.lang import Builder +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.floatlayout import FloatLayout +from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty +from kivy.uix.recycleview import RecycleView +from kivy.uix.recyclegridlayout import RecycleGridLayout +from kivy.uix.recycleview.views import RecycleDataViewBehavior +from kivy.uix.label import Label +from kivy.uix.recycleboxlayout import RecycleBoxLayout +from kivy.uix.behaviors import FocusBehavior +from kivy.uix.recycleview.layout import LayoutSelectionBehavior +import time +from uikivysignaler import UIkivySignaler +from semaphores import kivyuisignaler +from kivy.uix.button import Button +import kivy_helper_search from kivy.core.window import Window -from kivy.uix.actionbar import ActionItem - -statusIconColor = 'red' -class NavigateApp(App, TextInput): - """Application uses kivy in which base Class of Navigate App inherits from the App class.""" - - theme_cls = ThemeManager() - nav_drawer = ObjectProperty() - - def build(self): - """Return a main_widget as a root widget. - - An application can be built if you return a widget on build(), or if you set - self.root. - """ - main_widget = Builder.load_file( - os.path.join(os.path.dirname(__file__), 'main.kv')) - self.nav_drawer = Navigator() - Window.bind(on_keyboard=self._key_handler) - return main_widget - - def _key_handler(self, instance, key, *args): - """Escape key manages previous screen on back.""" - if key is 27: - print(args) - print(instance) - self.set_previous_screen() - return True - - def set_previous_screen(self): - """Set previous screen based on back.""" - if self.root.ids.scr_mngr.current != 'inbox': - self.root.ids.scr_mngr.transition.direction = 'left' - self.root.ids.scr_mngr.current = 'inbox' - - def getCurrentAccountData(self, text): - """Get Current Address Account Data.""" - state.association = text - self.root.ids.sc1.clear_widgets() - self.root.ids.sc2.clear_widgets() - self.root.ids.sc3.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) - self.root.ids.sc2.add_widget(Sent()) - self.root.ids.sc3.add_widget(Trash()) - self.root.ids.toolbar.title = BMConfigParser().get( - state.association, 'label') + '({})'.format(state.association) - Inbox() - Sent() - Trash() - - def say_exit(self): - """Exit the application as uses shutdown PyBitmessage.""" - print("**************************EXITING FROM APPLICATION*****************************") - App.get_running_app().stop() - shutdown.doCleanShutdown() - - @staticmethod - def showmeaddresses(name="text"): - """Show the addresses in spinner to make as dropdown.""" - if name == "text": - return BMConfigParser().addresses()[0] - elif name == "values": - return BMConfigParser().addresses() - - def update_index(self, data_index, index): - """Update index after archieve message to trash.""" - if self.root.ids.scr_mngr.current == 'inbox': - self.root.ids.sc1.data[data_index]['index'] = index - elif self.root.ids.scr_mngr.current == 'sent': - self.root.ids.sc2.data[data_index]['index'] = index - elif self.root.ids.scr_mngr.current == 'trash': - self.root.ids.sc3.data[data_index]['index'] = index - - def delete(self, data_index): - """It will make delete using remove function.""" - print("delete {}".format(data_index)) - self._remove(data_index) - - def archive(self, data_index): - """It will make archieve using remove function.""" - print("archive {}".format(data_index)) - self._remove(data_index) - - def _remove(self, data_index): - """It will remove message by resetting the values in recycleview data.""" - if self.root.ids.scr_mngr.current == 'inbox': - self.root.ids.sc1.data.pop(data_index) - self.root.ids.sc1.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc1.data) - ] - elif self.root.ids.scr_mngr.current == 'sent': - self.root.ids.sc2.data.pop(data_index) - self.root.ids.sc2.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc2.data) - ] - elif self.root.ids.scr_mngr.current == 'trash': - self.root.ids.sc3.data.pop(data_index) - self.root.ids.sc3.data = [{ - 'data_index': i, - 'index': d['index'], - 'height': d['height'], - 'text': d['text']} - for i, d in enumerate(self.root.ids.sc3.data) - ] - - def getInboxMessageDetail(self, instance): - """It will get message detail after make selected message description.""" - try: - self.root.ids.scr_mngr.current = 'page' - except AttributeError: - self.parent.manager.current = 'page' - print('Message Clicked {}'.format(instance)) - - @staticmethod - def getCurrentAccount(): - """It uses to get current account label.""" - return BMConfigParser().get(state.association, 'label') + '({})'.format(state.association) - - -class Navigator(NavigationDrawer): - """Navigator class uses NavigationDrawer. - - It is an UI panel that shows our app's main navigation menu - It is hidden when not in use, but appears when the user swipes - a finger from the left edge of the screen or, when at the top - level of the app, the user touches the drawer icon in the app bar - """ +userAddress = '' +class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') + drawer_logo = StringProperty() + # print("priiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnnnttttttttttthethingsss.................", ) class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" - - data = ListProperty() - def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text + # if state.association == '': + # state.association = 'BM-2cTuPpAPbu44sbkfVJN2F99sXGJoeNpDBh' + # print(self.get_address_via_split(state.association)) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - self.inboxaccounts() - print(dt) - - def inboxaccounts(self): - """Load inbox accounts.""" - account = state.association - self.loadMessagelist(account, 'All', '') - - def loadMessagelist(self, account, where="", what=""): - """Load Inbox list for inbox messages.""" - xAddress = "toaddress" - queryreturn = kivy_helper_search.search_sql( - xAddress, account, 'inbox', where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[4]} - for i, row in enumerate(queryreturn) - ] + print("generateaddressgenerateaddressgenerateaddressgenerateaddressgenerateaddress", BMConfigParser().addresses()) + if BMConfigParser().addresses(): + data = [{'text': "surbhi cis222222", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "peter surda", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "uber", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "ola", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "glitch", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "github", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "kivy", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "andrew", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/kivymd_logo.png')) + self.ids.ml.add_widget(meny) else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] + self.manager.current = 'login' -class Page(Screen): - pass - - -class AddressSuccessful(Screen): - pass - - -class Sent(Screen): - """Sent Screen uses screen to show widgets of screens.""" - - data = ListProperty() - +class MyAddress(Screen): + """MyAddress Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): - super(Sent, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock Schdule for method sent accounts.""" - self.sentaccounts() - print(dt) - - def sentaccounts(self): - """Load sent accounts.""" - account = state.association - self.loadSent(account, 'All', '') - - def loadSent(self, account, where="", what=""): - """Load Sent list for Sent messages.""" - xAddress = 'fromaddress' - queryreturn = kivy_helper_search.search_sql( - xAddress, account, "sent", where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[2]} - for i, row in enumerate(queryreturn) - ] - else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] - - -class Trash(Screen): - """Trash Screen uses screen to show widgets of screens.""" - - data = ListProperty() - - def __init__(self, *args, **kwargs): - super(Trash, self).__init__(*args, **kwargs) - if state.association == '': - state.association = Navigator().ids.btn.text + super(MyAddress, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - self.inboxaccounts() - print(dt) - - def inboxaccounts(self): - """Load inbox accounts.""" - account = state.association - self.loadTrashlist(account, 'All', '') - - def loadTrashlist(self, account, where="", what=""): - """Load Trash list for trashed messages.""" - xAddress = "toaddress" - queryreturn = kivy_helper_search.search_sql( - xAddress, account, 'trash', where, what, False) - if queryreturn: - self.data = [{ - 'data_index': i, - 'index': 1, - 'height': 48, - 'text': row[4]} - for i, row in enumerate(queryreturn) - ] - else: - self.data = [{ - 'data_index': 1, - 'index': 1, - 'height': 48, - 'text': "yet no message for this account!!!!!!!!!!!!!"} - ] + pass + # if BMConfigParser().AddressSuccessful(): + # data = [{'text': "me", 'secondary_text': "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyTfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyVfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWySfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyHfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyJfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyKfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyMnBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyOkBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, + # {'text': "me", 'secondary_text': "BM-2cWyWuBdY2FbgyuCb7abFZ49JYxSzUhNFe"}] + # for item in data: + # meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + # meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + # self.ids.ml.add_widget(meny) + # else: + # self.manager.current = 'login' -class Dialog(Screen): - """Dialog Screen uses screen to show widgets of screens.""" - - pass - - -class Test(Screen): - """Test Screen uses screen to show widgets of screens.""" - - pass - - -class Create(Screen): - """Create Screen uses screen to show widgets of screens.""" +class AddressBook(Screen): + """AddressBook Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): - super(Create, self).__init__(*args, **kwargs) + super(AddressBook, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + # sqlExecute("DELETE FROM addressbook WHERE label='' ") + data = sqlQuery("SELECT label, address from addressbook") + if data: + for item in data: + meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="No Contact Found yet...... ", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + print("chek iniiiiiiiiiiiiiittttttttttttttttttttttttttttttttt", self) + # self.ids.ml.clear_widgets() + + def refreshs(self, *args): + state.navinstance.ids.sc11.clear_widgets() + state.navinstance.ids.sc11.add_widget(AddressBook()) + +class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, + RecycleBoxLayout): + ''' Adds selection and focus behaviour to the view. ''' + + +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): + ''' 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: + print("selection changed to {0}".format(rv.data[index])) + rv.parent.txt_input.text = rv.parent.txt_input.text.replace(rv.parent.txt_input.text, rv.data[index]['text']) + + +class RV(RecycleView): + def __init__(self, **kwargs): + super(RV, self).__init__(**kwargs) + + +class DropDownWidget(BoxLayout): + txt_input = ObjectProperty() + rv = ObjectProperty() def send(self): """Send message from one address to another.""" - fromAddress = self.ids.spinner_id.text + fromAddress = str(self.ids.ti.text) # For now we are using static address i.e we are not using recipent field value. - toAddress = "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe" - message = self.ids.message.text - subject = self.ids.subject.text + # toAddress = str(self.ids.txt_input.text) + # print("hiiiiiiiiiiiiiiiiii i am hereeeeeeeeeeeeeeeeeeeeee..............") + # print("hiiiiiiiiiseeeee to addresssssssssss..........................", self.ids) + # print("ssssssssssseeeeeeeeeeeeeeeeeeetheeeeeeeeeeetexttinput....data...", self.ids.txt_input.text) + # toAddress = "BM-2cVJ8Bb9CM5XTEjZK1CZ9pFhm7jNA1rsa6" + # print("every thng is good for the day..................", str(self.ids.txt_input.text)) + toAddress = str(self.ids.txt_input.text) + print("alllllllllllllllllllllllllllsss wel ends wellllllllllllllll", ) + subject = str(self.ids.subject.text) + message = str(self.ids.body.text) + print("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR") encoding = 3 - print("message: ", self.ids.message.text) + print("message: ", self.ids.body.text) sendMessageToPeople = True + print("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS") if sendMessageToPeople: + print("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT") + print("did_addresssssssssssssssss_existsssssssssssssssssssss.........buyyyyy", toAddress) if toAddress != '': + print("UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU") + from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) + print("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV") if status == 'success': + from addresses import * toAddress = addBMIfNotPresent(toAddress) - + statusIconColor = 'red' + print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") if addressVersionNumber > 4 or addressVersionNumber <= 1: print("addressVersionNumber > 4 or addressVersionNumber <= 1") if streamNumber > 1 or streamNumber == 0: print("streamNumber > 1 or streamNumber == 0") if statusIconColor == 'red': print("shared.statusIconColor == 'red'") + print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') + print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") + from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) + print("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY") t = () + print("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', @@ -361,64 +253,511 @@ class Create(Screen): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) + print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + self.parent.parent.screens[3].clear_widgets() + self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) - print("sqlExecute successfully ##### ##################") - self.ids.message.text = '' - self.ids.spinner_id.text = '' - self.ids.subject.text = '' - self.ids.recipent.text = '' - return None + +class MyTextInput(TextInput): + txt_input = ObjectProperty() + flt_list = ObjectProperty() + word_list = ListProperty() + # this is the variable storing the number to which the look-up will start + starting_no = NumericProperty(3) + suggestion_text = '' + + def __init__(self, **kwargs): + super(MyTextInput, self).__init__(**kwargs) + + def on_text(self, instance, value): + # find all the occurrence of the word + self.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 the data in the recycleview + display_data = [] + for i in matches: + display_data.append({'text': i}) + self.parent.parent.parent.parent.ids.rv.data = display_data + # ensure the size is okay + 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): + 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 NewIdentity(Screen): - """Create new address for PyBitmessage.""" +class Payment(Screen): + pass +class Login(Screen): + pass + + +class NetworkStat(Screen): + 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): + super(NetworkStat, self).__init__(*args, **kwargs) + Clock.schedule_interval(self.init_ui, 1) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + import network.stats + import shared + from network import objectracker + self.text_variable_1 = '{0} :: {1}'.format('Total Connections', str(len(network.stats.connectedHostsList()))) + self.text_variable_2 = 'Processed {0} per-to-per messages'.format(str(shared.numberOfMessagesProcessed)) + self.text_variable_3 = 'Processed {0} brodcast messages'.format(str(shared.numberOfBroadcastsProcessed)) + self.text_variable_4 = 'Processed {0} public keys'.format(str(shared.numberOfPubkeysProcessed)) + self.text_variable_5 = '{0} object to be synced'.format(len(objectracker.missingObjects)) + + +class ContentNavigationDrawer(Navigatorss): + pass + + +class Random(Screen): is_active = BooleanProperty(False) checked = StringProperty("") # self.manager.parent.ids.create.children[0].source = 'images/plus-4-xxl.png' def generateaddress(self): - """Generate new address.""" - if self.checked == 'use a random number generator to make an address': - queues.apiAddressGeneratorReturnQueue.queue.clear() - streamNumberForAddress = 1 - label = self.ids.label.text - eighteenByteRipe = False - nonceTrialsPerByte = 1000 - payloadLengthExtraBytes = 1000 + import queues + # queues.apiAddressGeneratorReturnQueue.queue.clear() + streamNumberForAddress = 1 + label = self.ids.label.text + eighteenByteRipe = False + nonceTrialsPerByte = 1000 + payloadLengthExtraBytes = 1000 + queues.addressGeneratorQueue.put(( + 'createRandomAddress', + 4, streamNumberForAddress, + label, 1, "", eighteenByteRipe, + nonceTrialsPerByte, + payloadLengthExtraBytes) + ) + self.manager.current = 'add_sucess' + print("whhhheeeeeeee55566666666666666666666..................", self) + print("what is the screeen forrrrrrrrrrrrrrrrr...............", self.ids) + self.ids.label.text = '' + # print("whatttttt99999999999999999999999999999999999988888888......", self.parent.parent) + # print("go.....more...parenxccccccccccccccccccccccc555559955555555555", self.parent.parent.parent) + # print("ssssshooooocxvxcvxcvoooouuuuuuuuuuuuuuuuuueeeettttttttteeeeeeeeeee............... ", ContentNavigationDrawer().ids.btn) + # print("spiiiiinnnxcvxcxc99999999999999999999999999999999999999tttt..........", ContentNavigationDrawer().ids.btn.text) + # print("text_dirrrrrrrrrrrrrrrrrrrrrr9999999999999999fgdg.............................", dir(ContentNavigationDrawer().ids.btn)) + # print("ttttttttttttttiiiiiiiiilllllllllllllllttttleeeeeeeee9999999999999999999", ContentNavigationDrawer().ids.btn.text) + # prnit("55555557777777777777777888888888888888888jjjjjjjjjj", ContentNavigationDrawer().ids.btn.text) + # print("what account is associated..............................", state.association) + # print("pppppppppp999999999666666666663333333333333333333333..............", BMConfigParser().addresses()) + # print("whatssssssssssssssssssssssstheva,lllllllllllleeeeeeeee...........") + # print("wh.....................8888888899999999999999999999999999", queues.addressGeneratorQueue.get()) - queues.addressGeneratorQueue.put(( - 'createRandomAddress', - 4, streamNumberForAddress, - label, 1, "", eighteenByteRipe, - nonceTrialsPerByte, - payloadLengthExtraBytes) - ) - self.manager.current = 'add_sucess' + # print("ljjkkkkkkkkkkkkkkkkkkk666666666666666666666666666666666", self.parent.parent.parent.parent.parent) + # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] + # if BMConfigParser().addresses(): + # print("iiiinnnnnnnnnnnnnnnnnnnnnnnnnnsssssssssssiiiiiiiiiideeeeeeeee") + # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] + # return BMConfigParser().addresses()[0] + # print("iiiiiiiiiiiiiihhhhhhhhhhhhhhhhh5555555555555555555....", ContentNavigationDrawer()) + # print("khhhhhhhhhhhhhyaaaaaaaaaaaaaaaa5555555555555555...............", ContentNavigationDrawer().ids) + # print("it is sccccccccccccefssssfulllllll............................", ContentNavigationDrawer().ids.btn.text) + # ids.btn.text -class SearchBar(TextInput, ActionItem): - """Create SearchBar for PyBitmessage.""" +class AddressSuccessful(Screen): + pass + + +class NavigationLayout(): + pass + +class Sent(Screen): + """Sent Screen uses screen to show widgets of screens.""" + data = ListProperty() def __init__(self, *args, **kwargs): - """Initailizes SearchBar with hint text.""" - super(SearchBar, self).__init__(*args, **kwargs) - self.hint_text = 'Search' + super(Sent, self).__init__(*args, **kwargs) + # print("I amuuuuuupfatgd vale should get..................... .", ContentNavigationDrawer().ids.btn.text) + # print("yyyyyyuuuuuuuuuuuuuuuuuoooooooooouuuyyyyyyyyyyyy...............", ContentNavigationDrawer().ids.btn.values) + # print("ccchekkkkkkkkkccccccccccclre..................................................", ContentNavigationDrawer().ids.btn) + # print("llllllllllleeeeetttttttttttttttttttttheeeeeeeeemmmmmmcheccccccccccckkk........", dir(ContentNavigationDrawer().ids.btn)) + # print("llllllllllllllllllllllllllleeeeeeeeeeeeeeeeeeeeeeeexfgcgcgvcgvcvgbeeechhhhhhhhhhheck", state.association) + if state.association == '': + # state.association = Navigatocoming inside thew methoddddddddddddddddddds1buildrss().ids.btn.text + print("uuuuuuuuuuuuuuuuuuuuuuuuu999999999999999999999999999999") + print("lllllllllllllllllllllllllllllll55555555556666666666", BMConfigParser().addresses()) + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + print("kkkkkkkkkkkkkkkkkkkkkkkkkkkk6666666666888888888888888888...................", state.association) + Clock.schedule_once(self.init_ui, 0) - def search(self): - """Search for message request.""" - request = self.text - return str(request) + def init_ui(self, dt=0): + """Clock Schdule for method sent accounts.""" + print("oooooooooooooooooooooooooooo999999999999999999999000000000") + self.sentaccounts() + print(dt) + + def sentaccounts(self): + """Load sent accounts.""" + print("mmmmmmmmmmmmmmmmmmmmmmmm44444444444444444455555555555__........") + account = state.association + print("zzzzzzzzzzzzzzzzzzzzzzz99999999999999999999999999999999999", account) + self.loadSent(account, 'All', '') + + def loadSent(self, account, where="", what=""): + """Load Sent list for Sent messages.""" + # print("uuuuuuuuuuuuuuuuyyyyyyyyyrrrrrrrrrrrinside_loadSent..........") + xAddress = 'fromaddress' + data = [] + # print("check--------thre.................somethiong.......cvmnvb mvn xmnvcxv.") + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "sent", where, what, False) + print("qqqqqqqq77777777777777777777777777777777555hhhhhhhhhhhhhhhfffffff....", queryreturn) + if queryreturn: + # for mail in sqlQuery("SELECT toaddress, subject, message FROM addressbook a, sent s WHERE a.address = s.fromaddress and s.fromaddress = 'BM-2cUz6dniZHjFTqv6j2es2wBSe3NydZdk4R';"): + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + print("whatttttttttttttttttttttttttttisssssssssssssssssssssssserrrrrrrrrrrrror") + print("nowwwwwwwwww9999999999999999999999999999999..................", third_text) + # print("sssssssssssssssseeeeeeeeeeeeeeeeeeeeeeeeeeeepprob.....", mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2]) + # data.append({'text': mail[0].strip(), 'secondary_text': mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) + # data.append({'text': '', 'secondary_text': mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) + data.append({'text': mail[0].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 }) + print("kyaaaaaaaaaaaaaaaaaaaaaaaaaayhaaaaaaaaaaaaerorrrrrrrrrr") + # self.data = [{ + # 'data_index': i, + # 'index': 1, + # 'height': 48, + # 'text': row[2], + # } + # for i, row in enumerate(queryreturn) + # ] + print("show 6666666666666666666eeeeeee555555555555555daaaaaaaaaaa.......", data) + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + print("uyyyyyyyyyyyyyyyyyyyyyyyyyuuuuuuuuuggg558888888888gggggggoooooooooooooooooooooooooooooooooooooooo....") + # print("ufffffffffffffffffffffffff6666666666666ffffyyyyyyyyyyyyyyyyyyyyyyyyypp.......", self.data) + else: + # self.data = [{ + # 'data_index': 1, + # 'index': 1, + # 'height': 48, + # 'text': "yet no message for this account!!!!!!!!!!!!!"} + # ] + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + +class Trash(Screen): + """Trash Screen uses screen to show widgets of screens.""" + def __init__(self, *args, **kwargs): + super(Trash, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method inbox accounts.""" + data = [{'text': "neha cis", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "paytm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "pol", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "akshayaura", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "codementor", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "yatra", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "mdtezm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, + {'text': "crewqt", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + for item in data: + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) -if __name__ == '__main__': - NavigateApp().run() +class Page(Screen): + pass + + +class Create(Screen): + def __init__(self, **kwargs): + super(Create, self).__init__(**kwargs) + # from kivy.core.window import Window + print("cheeeeeeeeeeeehn888888888888888888888888gggkkkkkkkthe windowwwwwwwwwwwwwwww", Window.size) + # print("take the onlyyyyyyyyyyyyyyyyyyyyyyyyyyyy x axssssssssssssssssssssssswindow", Window.size[0]) + # print("realllllllllllyyyyyyyyyyyyy yyyyyyyyyyyoooooouuuuuuu wwwwwwaaaaaaaaaaaannnnnnnnnntttt", Window._get_width) + # print("mmmmmmmmmmmmmminnnnnnnnnnnnnnnn and mmmmmmmmaaaaaaaaxxxxxxxesssssssss", Window.minimum_height, Window.minimum_width) + # print("dir in windowwwwwwwwwkkkkkkkkkkkww of the mobile screen", dir(Window)) + # print("cheeeeeeeeeeeeeeeeeckkkkkkkkkkkkkkkk width and heightttttttttttttttttttt", Window.width, window.height) + widget_1 = DropDownWidget() + from helper_sql import * + widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] + # widget_1.ids.txt_input.word_list = ['how to use python', 'how to use kivy', 'how to use django', 'BM-2cTik2JBHAS92U633LPY', 'BM-2cUYmQofWjTQeUitL7'] + widget_1.ids.txt_input.starting_no = 2 + self.add_widget(widget_1) + +class AddressSuccessful(Screen): + pass + + +class Setting(Screen): + pass + + +class NavigateApp(App): + theme_cls = ThemeManager() + previous_date = ObjectProperty() + obj_1 = ObjectProperty() + variable_1 = ListProperty(BMConfigParser().addresses()) + nav_drawer = ObjectProperty() + # user_address = StringProperty('jai') + scr_size = Window.size[0] + + title = "KivyMD" + count = 0 + menu_items = [ + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', + 'text': 'Example item'}, + ] + + def build(self): + print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllllllrrrrrrrrrrahut......') + print('chreckoooooooooooooooo........................', self.variable_1) + print("dsssssssssssoddddddddd77777777777777777777eeeeeeeeetheroot", dir(self)) + import os + main_widget = Builder.load_file( + os.path.join(os.path.dirname(__file__), 'main.kv')) + self.nav_drawer = Navigatorss() + self.obj_1 = AddressBook() + kivysignalthread = UIkivySignaler() + kivysignalthread.daemon = True + kivysignalthread.start() + return main_widget + + def run(self): + kivyuisignaler.release() + super(NavigateApp, self).run() + + def say_exit(self): + """Exit the application as uses shutdown PyBitmessage.""" + print("**************************EXITING FROM APPLICATION*****************************") + App.get_running_app().stop() + import shutdown + shutdown.doCleanShutdown() + + def show_address_success(self): + print("9062 I am pressed...............................................................") + content = MDLabel(font_style='Body1', + theme_text_color='Secondary', + text="Successfully Saved your contact address. " + "That's pretty awesome right!", + size_hint_y=None, + valign='top') + print("9063 I am pressed...............................................................") + content.bind(texture_size=content.setter('size')) + print("9064 I am pressed...............................................................") + # self.dialog = MDDialog(content=content, + # size_hint=(.8, None), + # height=dp(200), + # auto_dismiss=False) + print("9065 I am pressed...............................................................") + # self.dialog.add_action_button("Dismiss", + # action=lambda *x: self.dialog.dismiss()) + print("966 I am pressed...............................................................") + self.dialog.open() + + @staticmethod + def showmeaddresses(name="text"): + """Show the addresses in spinner to make as dropdown.""" + if name == "text": + # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' + if bmconfigparserigParser().addresses(): + return BMConfigParser().addresses()[0][:16] + '..' + else: + return "textdemo" + elif name == "values": + if BMConfigParser().addresses(): + return [address[:16] + '..' for address in BMConfigParser().addresses()] + else: + return "valuesdemo" + # return [BMConfigParser().get(address, 'label')[:12] + '..' for address in BMConfigParser().sections()[1:]] + # return BMConfigParser().addresses() + + def getCurrentAccountData(self, text): + """Get Current Address Account Data.""" + print("self tttttttttttttttttttttteeeeeeeeeexfgvbcvgfcgfdgfdgfgxxxxxxxxtttttttttzzzzzzzz ", text) + state.association = text + # print("eeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrorrrrrrrrrrrrrrrrrr", self.root) + # print("iiiiiiiiiiiiiidddddddddddddddddeeeeeeeessssssssssssssssss55......", self.root.ids) + self.root.ids.sc1.clear_widgets() + self.root.ids.sc4.clear_widgets() + self.root.ids.sc5.clear_widgets() + # print("resffffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuurrrrrrrrrrrrr......") + self.root.ids.sc1.add_widget(Inbox()) + self.root.ids.sc4.add_widget(Sent()) + self.root.ids.sc5.add_widget(Trash()) + # print("again aaaaddddddddddddddddddinggggggggggggggggguuuuuuuuuuuuuuuu1 ........") + + # self.root.ids.toolbar.title = BMConfigParser().get( + # state.association, 'label') + '({})'.format(state.association) + # print("what theyyyyyyyyyyyyyyyyyyyy areeeeeeeeeeeee printing11........", self.root.ids.toolbar.title) + # Inbox() + # Sent() + # Trash() + # print("finish gamneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!") + + def getInboxMessageDetail(self, instance): + """It will get message detail after make selected message description.""" + try: + self.root.ids._mngr.current = 'page' + except AttributeError: + self.parent.manager.current = 'page' + print('Message Clicked {}'.format(instance)) + + @staticmethod + def getCurrentAccount(): + """It uses to get current account label.""" + if state.association: + return state.association + else: + return "Bitmessage Login" + + def addingtoaddressbook(self): + p = GrashofPopup() + p.open() + + def getDefaultAccData(self): + print("coming inside thew methodddddddddddddddddddsdcassdfs1") + print("combbbbbbbbbbbbggggffffffdfgdgfffffffgggggggggggggggggggllllllloooo", BMConfigParser().addresses()) + # return BMConfigParser.addresses[0] + if BMConfigParser().addresses(): + return BMConfigParser().addresses()[0] + return 'Select Address' + + +class GrashofPopup(Popup): + def __init__(self, **kwargs): + super(GrashofPopup, self).__init__(**kwargs) + self.size_hint_y = 0.7 + self.size_hint_x = 0.9 + + def savecontact(self): + print("show the addedes addess in databaseeeeeeeeeeeeeeeeee............................") + print("1110 I am pressed...............................................................") + label = self.ids.label.text + print("2210 I am pressed...............................................................") + address = self.ids.address.text + print("3310 I am pressed...............................................................") + if label and address: + state.navinstance = self.parent.children[1] + queues.UISignalQueue.put(('rerenderAddressBook', '')) + self.dismiss() + sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + # self.parent.children[1].ids.sc11.clear_widgets() + # self.parent.children[1].ids.sc11.add_widget(AddressBook()) + + def show_error_message(self): + content = MDLabel(font_style='Body1', + theme_text_color='Secondary', + text="Hey you are not allowed to save blank address contact. " + "That's wrong!", + size_hint_y=None, + valign='top') + content.bind(texture_size=content.setter('size')) + self.dialog = MDDialog(content=content, + size_hint=(.8, None), + height=dp(200), + auto_dismiss=False) + + self.dialog.add_action_button("ok", + action=lambda *x: self.dialog.dismiss()) + self.dialog.open() + + +class AvatarSampleWidget(ILeftBody, Image): + pass + + +class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): + pass + + +class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): + + pass + + +class NavigationDrawerTwoLineListItem( + TwoLineListItem, NavigationDrawerHeaderBase): + + address_property = StringProperty() + + def __init__(self, **kwargs): + super(NavigationDrawerTwoLineListItem, self).__init__(**kwargs) + Clock.schedule_once(lambda dt: self.setup()) + + def setup(self): + """ + Binds Controller.current_account property. + """ + pass + # self.controller = App.get_running_app().controller + # self.controller.bind( + # current_account=lambda _, value: self.on_current_account(value)) + + def on_current_account(self, account): + pass + # e.g. deleting the last account, would set + # Controller.current_account to None + # if account is None: + # return + # address = "0x" + account.address.encode("hex") + # self.address_property = address + + def _update_specific_text_color(self, instance, value): + pass + + def _set_active(self, active, list): + pass \ No newline at end of file diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py new file mode 100644 index 00000000..41e532fe --- /dev/null +++ b/src/bitmessagekivy/uikivysignaler.py @@ -0,0 +1,23 @@ + +from threading import Thread +import state +import queues +from semaphores import kivyuisignaler +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure + +class UIkivySignaler(Thread): + + def run(self): + kivyuisignaler.acquire() + while state.shutdown == 0: + try: + command, data = queues.UISignalQueue.get() + print("ssssssseeeeeeeeeeeeeeeeeeeeeeeeeewuhatsacomment.................", command) + if command == 'writeNewAddressToTable': + label, address, streamNumber = data + state.kivyapp.variable_1.append(address) + elif command == 'rerenderAddressBook': + state.kivyapp.obj_1.refreshs() + + except Exception as e: + print(e) \ No newline at end of file diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 5dcfea6c..c8f2d445 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -18,6 +18,7 @@ sys.path.insert(0, app_dir) import depends + depends.check_dependencies() import ctypes @@ -251,7 +252,8 @@ class Main: if daemon: state.enableGUI = False # run without a UI - if state.enableGUI and not state.curses and not depends.check_pyqt(): + # is the application already running? If yes then exit. + if state.enableGUI and not state.curses and not state.kivy and not depends.check_pyqt(): sys.exit( 'PyBitmessage requires PyQt unless you want' ' to run it as a daemon and interact with it' @@ -289,9 +291,7 @@ class Main: defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) defaults.networkDefaultPayloadLengthExtraBytes = int( defaults.networkDefaultPayloadLengthExtraBytes / 100) - knownnodes.readKnownNodes() - # Not needed if objproc is disabled if state.enableObjProc: @@ -313,14 +313,11 @@ class Main: # The closeEvent should command this thread to exit gracefully. sqlLookup.daemon = False sqlLookup.start() - Inventory() # init # init, needs to be early because other thread may access it early Dandelion() - # Enable object processor and SMTP only if objproc enabled if state.enableObjProc: - # SMTP delivery thread if daemon and config.safeGet( 'bitmessagesettings', 'smtpdeliver', '') != '': @@ -342,18 +339,15 @@ class Main: # each object. objectProcessorThread.daemon = False objectProcessorThread.start() - # Start the cleanerThread singleCleanerThread = singleCleaner() # close the main program even if there are threads left singleCleanerThread.daemon = True singleCleanerThread.start() - # Not needed if objproc disabled if state.enableObjProc: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - # API is also objproc dependent if config.safeGetBoolean('bitmessagesettings', 'apienabled'): import api # pylint: disable=relative-import @@ -361,7 +355,6 @@ class Main: # close the main program even if there are threads left singleAPIThread.daemon = True singleAPIThread.start() - # start network components if networking is enabled if state.enableNetwork: self.start_proxyconfig(config) @@ -398,7 +391,6 @@ class Main: else: # Populate with hardcoded value (same as connectToStream above) state.streamsInWhichIAmParticipating.append(1) - if not daemon and state.enableGUI: if state.curses: if not depends.check_curses(): @@ -406,10 +398,12 @@ class Main: print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() + elif state.kivy: config.remove_option('bitmessagesettings', 'dontconnect') from bitmessagekivy.mpybit import NavigateApp - NavigateApp().run() + state.kivyapp = NavigateApp() + state.kivyapp.run() else: import bitmessageqt bitmessageqt.run() diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index 24775475..7c2188e6 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -78,7 +78,7 @@ void getnumthreads() #ifdef _WIN32 DWORD_PTR dwProcessAffinity, dwSystemAffinity; #elif __linux__ - cpu_set_t dwProcessAffinity; + // cpu_set_t dwProcessAffinity; #elif __OpenBSD__ int mib[2], core_count = 0; int dwProcessAffinity = 0; @@ -87,13 +87,13 @@ void getnumthreads() int dwProcessAffinity = 0; int32_t core_count = 0; #endif - size_t len = sizeof(dwProcessAffinity); - if (numthreads > 0) - return; + // size_t len = sizeof(dwProcessAffinity); + // if (numthreads > 0) + // return; #ifdef _WIN32 GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); #elif __linux__ - sched_getaffinity(0, len, &dwProcessAffinity); + // sched_getaffinity(0, len, &dwProcessAffinity); #elif __OpenBSD__ len2 = sizeof(core_count); mib[0] = CTL_HW; @@ -106,22 +106,22 @@ void getnumthreads() else if (sysctlbyname("hw.ncpu", &core_count, &len, 0, 0) == 0) numthreads = core_count; #endif - for (unsigned int i = 0; i < len * 8; i++) -#if defined(_WIN32) -#if defined(_MSC_VER) - if (dwProcessAffinity & (1i64 << i)) -#else // CYGWIN/MINGW - if (dwProcessAffinity & (1ULL << i)) -#endif -#elif defined __linux__ - if (CPU_ISSET(i, &dwProcessAffinity)) -#else - if (dwProcessAffinity & (1 << i)) -#endif - numthreads++; - if (numthreads == 0) // something failed - numthreads = 1; - printf("Number of threads: %i\n", (int)numthreads); +// for (unsigned int i = 0; i < len * 8; i++) +// #if defined(_WIN32) +// #if defined(_MSC_VER) +// if (dwProcessAffinity & (1i64 << i)) +// #else // CYGWIN/MINGW +// if (dwProcessAffinity & (1ULL << i)) +// #endif +// #elif defined __linux__ +// if (CPU_ISSET(i, &dwProcessAffinity)) +// #else +// if (dwProcessAffinity & (1 << i)) +// #endif +// numthreads++; +// if (numthreads == 0) // something failed +// numthreads = 1; +// printf("Number of threads: %i\n", (int)numthreads); } extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) @@ -146,7 +146,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # else pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); # ifdef __linux__ - pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); + pthread_setschedparam(threads[i], 0, &schparam); # else pthread_setschedparam(threads[i], SCHED_RR, &schparam); # endif diff --git a/src/buildozer.spec b/src/buildozer.spec index 07f9e6b2..cc91e880 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -1,10 +1,10 @@ [app] # (str) Title of your application -title = PyBitmessage +title = bluewhale # (str) Package name -package.name = PyBitmessage +package.name = bluewhale # (str) Package domain (needed for android/ios packaging) package.domain = org.test @@ -36,21 +36,20 @@ version = 0.1 # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy -requirements = python2, sqlite3, kivy, openssl +requirements = python2, sqlite3, kivy, openssl, bitmsghash, libexpat, kivymd # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes # requirements.source.kivy = ../../kivy -#requirements.source.sqlite3 = # (list) Garden requirements #garden_requirements = # (str) Presplash of the application -#presplash.filename = %(source.dir)s/data/presplash.png +presplash.filename = "images/presplas.gif" # (str) Icon of the application -#icon.filename = %(source.dir)s/data/icon.png +icon.filename ='images/if_android_1220385.png' # (str) Supported orientation (one of landscape, portrait or all) orientation = portrait @@ -66,8 +65,7 @@ orientation = portrait # author = © Copyright Info # change the major version of python used by the app -#osx.python_version = 2 - +osx.python_version = 3 # Kivy version to use osx.kivy_version = 1.9.1 @@ -87,31 +85,31 @@ fullscreen = 0 #android.presplash_color = #FFFFFF # (list) Permissions -android.permissions = INTERNET +android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE # (int) Android API to use -#android.api = 19 +android.api = 19 # (int) Minimum API required #android.minapi = 9 # (int) Android SDK version to use -#android.sdk = 20 +android.sdk = 20 # (str) Android NDK version to use -#android.ndk = 9c +android.ndk = 10e # (bool) Use --private data storage (True) or --dir public storage (False) #android.private_storage = True # (str) Android NDK directory (if empty, it will be automatically downloaded.) -#android.ndk_path = +android.ndk_path =/home/cis/Downloads/android-ndk-r10e # (str) Android SDK directory (if empty, it will be automatically downloaded.) -#android.sdk_path = +android.sdk_path =/home/cis/Android/Sdk # (str) ANT directory (if empty, it will be automatically downloaded.) -#android.ant_path = +android.ant_path =/home/cis/apache-ant-1.10.5 # (bool) If True, then skip trying to update the Android sdk # This can be useful to avoid excess Internet downloads or save time @@ -124,9 +122,6 @@ android.permissions = INTERNET # (list) Pattern to whitelist for the whole project #android.whitelist = -android.whitelist = /usr/lib/komodo-edit/python/lib/python2.7/lib-dynload/_sqlite3.so - - # (str) Path to a custom whitelist file #android.whitelist_src = @@ -150,9 +145,9 @@ android.whitelist = /usr/lib/komodo-edit/python/lib/python2.7/lib-dynload/_sqlit # (list) Gradle dependencies to add (currently works only with sdl2_gradle # bootstrap) #android.gradle_dependencies = -, /home/cis/Downloads/libssl1.0.2_1.0.2l-2+deb9u2_amd64 -# (str) python-for-android branch to use, defaults to stable -#p4a.branch = stable + +# (str) python-for-android branch to use, defaults to master +p4a.branch = master # (str) OUYA Console category. Should be one of GAME or APP # If you leave this blank, OUYA support will not be enabled @@ -198,7 +193,7 @@ android.arch = armeabi-v7a #p4a.source_dir = # (str) The directory in which python-for-android should look for your own build recipes (if any) -#p4a.local_recipes = +p4a.local_recipes =/home/cis/Desktop/Mobileandroid/peter_android/PyBitmessage/src/bitmessagekivy/android/python-for-android/recipes/ # (str) Filename to the hook for p4a #p4a.hook = diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index d930fc99..b5c0cbcd 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -4,7 +4,6 @@ import hashlib from binascii import hexlify from pyelliptic import arithmetic from pyelliptic.openssl import OpenSSL - import tr import queues import state @@ -30,6 +29,7 @@ class addressGenerator(StoppableThread): super(addressGenerator, self).stopThread() def run(self): + while state.shutdown == 0: queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 @@ -111,9 +111,7 @@ class addressGenerator(StoppableThread): defaults.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': queues.UISignalQueue.put(( - 'updateStatusBar', - tr._translate( - "MainWindow", "Generating one new address") + 'updateStatusBar' )) # This next section is a little bit strange. We're going # to generate keys over and over until we find one @@ -170,7 +168,6 @@ class addressGenerator(StoppableThread): privEncryptionKey).digest()).digest()[0:4] privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKey + checksum, 256, 58) - BMConfigParser().add_section(address) BMConfigParser().set(address, 'label', label) BMConfigParser().set(address, 'enabled', 'true') @@ -190,11 +187,7 @@ class addressGenerator(StoppableThread): queues.apiAddressGeneratorReturnQueue.put(address) queues.UISignalQueue.put(( - 'updateStatusBar', - tr._translate( - "MainWindow", - "Done generating address. Doing work necessary" - " to broadcast it...") + 'updateStatusBar' )) queues.UISignalQueue.put(('writeNewAddressToTable', ( label, address, streamNumber))) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 0798296e..6686e2c4 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -31,6 +31,8 @@ from helper_sql import sqlExecute, sqlQuery from helper_threading import StoppableThread from inventory import Inventory +# This thread, of which there is only one, does the heavy lifting: +# calculating POWs. def sizeof_fmt(num, suffix='h/s'): """Format hashes per seconds nicely (SI prefix)""" @@ -48,6 +50,7 @@ class singleWorker(StoppableThread): def __init__(self): super(singleWorker, self).__init__(name="singleWorker") proofofwork.init() + print("I am in single worker 52.....................................................") def stopThread(self): """Signal through the queue that the thread should be stopped""" diff --git a/src/debug.py b/src/debug.py index d3730d7f..082497d2 100644 --- a/src/debug.py +++ b/src/debug.py @@ -32,7 +32,7 @@ import helper_startup import state helper_startup.loadConfig() - +print("333333333333333333333333333333333333333333333333333333333333333333333333333333333") # Now can be overriden from a config file, which uses standard python # logging.config.fileConfig interface # examples are here: diff --git a/src/depends.py b/src/depends.py index 0114ec94..5a8b9a74 100755 --- a/src/depends.py +++ b/src/depends.py @@ -17,7 +17,7 @@ if not hasattr(sys, 'hexversion') or sys.hexversion < 0x20300F0: import logging import os from importlib import import_module - +import state # We can now use logging so set up a simple configuration formatter = logging.Formatter('%(levelname)s: %(message)s') handler = logging.StreamHandler(sys.stdout) @@ -231,6 +231,7 @@ def check_sqlite(): def check_openssl(): + print(state.kivy, "state.kivystate.kivystate.kivystate.kivystate.kivystate.kivystate.kivystate.kivy") """Do openssl dependency check. Here we are checking for openssl with its all dependent libraries @@ -248,8 +249,12 @@ def check_openssl(): if getattr(sys, 'frozen', False): import os.path paths.insert(0, os.path.join(sys._MEIPASS, 'libeay32.dll')) + elif state.kivy: + print("kivykivykivykivykivykivykivy...........................") + return True else: paths = ['libcrypto.so', 'libcrypto.so.1.0.0'] + if sys.platform == 'darwin': paths.extend([ 'libcrypto.dylib', @@ -278,6 +283,7 @@ def check_openssl(): logger.info('Checking OpenSSL at %s', path) try: library = ctypes.CDLL(path) + print("I am loading here in depends file................................................................") except OSError: continue logger.info('OpenSSL Name: %s', library._name) @@ -425,7 +431,6 @@ def check_dependencies(verbose=False, optional=False): check_functions = [check_ripemd160, check_sqlite, check_openssl] if optional: check_functions.extend([check_msgpack, check_pyqt, check_curses]) - # Unexpected exceptions are handled here for check in check_functions: try: diff --git a/src/helper_generic.py b/src/helper_generic.py new file mode 100644 index 00000000..368a6c54 --- /dev/null +++ b/src/helper_generic.py @@ -0,0 +1,114 @@ +""" +Helper Generic perform generic operations for threading. + +Also perform some conversion operations. +""" + +import socket +import sys +import threading +import traceback +try: + import multiprocessing +except Exception as e: + pass +from binascii import hexlify, unhexlify + +import shared +import state +import queues +import shutdown +from debug import logger + + +def powQueueSize(): + curWorkerQueue = queues.workerQueue.qsize() + for thread in threading.enumerate(): + try: + if thread.name == "singleWorker": + curWorkerQueue += thread.busy + except Exception as err: + logger.info('Thread error %s', err) + return curWorkerQueue + + +def convertIntToString(n): + a = __builtins__.hex(n) + if a[-1:] == 'L': + a = a[:-1] + if (len(a) % 2) == 0: + return unhexlify(a[2:]) + else: + return unhexlify('0' + a[2:]) + + +def convertStringToInt(s): + return int(hexlify(s), 16) + + +def allThreadTraceback(frame): + id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) + code = [] + for threadId, stack in sys._current_frames().items(): + code.append( + '\n# Thread: %s(%d)' % (id2name.get(threadId, ''), threadId)) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append( + 'File: "%s", line %d, in %s' % (filename, lineno, name)) + if line: + code.append(' %s' % (line.strip())) + print('\n'.join(code)) + + +def signal_handler(signal, frame): + try: + process = multiprocessing.current_process() + except Exception as e: + process = threading.current_thread() + logger.error( + 'Got signal %i in %s/%s', + signal, process.name, threading.current_thread().name + ) + if process.name == "RegExParser": + # on Windows this isn't triggered, but it's fine, + # it has its own process termination thing + raise SystemExit + if "PoolWorker" in process.name: + raise SystemExit + if threading.current_thread().name not in ("PyBitmessage", "MainThread"): + return + logger.error("Got signal %i", signal) + if shared.thisapp.daemon or not state.enableGUI: # FIXME redundant? + shutdown.doCleanShutdown() + else: + allThreadTraceback(frame) + print('Unfortunately you cannot use Ctrl+C when running the UI' + ' because the UI captures the signal.') + + +def isHostInPrivateIPRange(host): + if ":" in host: # IPv6 + hostAddr = socket.inet_pton(socket.AF_INET6, host) + if hostAddr == ('\x00' * 15) + '\x01': + return False + if hostAddr[0] == '\xFE' and (ord(hostAddr[1]) & 0xc0) == 0x80: + return False + if (ord(hostAddr[0]) & 0xfe) == 0xfc: + return False + elif ".onion" not in host: + if host[:3] == '10.': + return True + if host[:4] == '172.': + if host[6] == '.': + if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: + return True + if host[:8] == '192.168.': + return True + # Multicast + if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.': + return True + return False + + +def addDataPadding(data, desiredMsgLength=12, paddingChar='\x00'): + return data + paddingChar * (desiredMsgLength - len(data)) diff --git a/src/helper_startup.py b/src/helper_startup.py index 1a1119f5..6b60bdd2 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -44,6 +44,8 @@ def _loadTrustedPeer(): def loadConfig(): """Load the config""" config = BMConfigParser() + print("I am coming in loadConfig now................................................................") + if state.appdata: config.read(state.appdata + 'keys.dat') # state.appdata must have been specified as a startup option. diff --git a/src/images/account_multiple.png b/src/images/account_multiple.png new file mode 100644 index 0000000000000000000000000000000000000000..112716197dbe10f0191e2cb2f03b11e623e9af62 GIT binary patch literal 9798 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 QA{c13Im8JGjX{o5? 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 literal 0 HcmV?d00001 diff --git a/src/kivymd/LICENSE b/src/kivymd/LICENSE deleted file mode 100644 index a17ea136..00000000 --- a/src/kivymd/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrés Rodríguez and KivyMD contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/src/kivymd/__init__.py b/src/kivymd/__init__.py deleted file mode 100644 index bc07270c..00000000 --- a/src/kivymd/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -import os - -path = os.path.dirname(__file__) -fonts_path = os.path.join(path, "fonts/") -images_path = os.path.join(path, 'images/') diff --git a/src/kivymd/accordion.py b/src/kivymd/accordion.py deleted file mode 100644 index 6e816ca6..00000000 --- a/src/kivymd/accordion.py +++ /dev/null @@ -1,254 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, OptionProperty -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.accordion import Accordion, AccordionItem -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivy.uix.boxlayout import BoxLayout - - -class MDAccordionItemTitleLayout(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - pass - - -class MDAccordion(ThemableBehavior, BackgroundColorBehavior, Accordion): - pass - - -class MDAccordionItem(ThemableBehavior, AccordionItem): - title_theme_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - ''' Color theme for title text and icon ''' - - title_color = ListProperty(None, allownone=True) - ''' Color for title text and icon if `title_theme_color` is Custom ''' - - background_color = ListProperty(None, allownone=True) - ''' Color for the background of the accordian item title in rgba format. - ''' - - divider_color = ListProperty(None, allownone=True) - ''' Color for dividers between different titles in rgba format - To remove the divider set a color with an alpha of 0. - ''' - - indicator_color = ListProperty(None, allownone=True) - ''' Color for the indicator on the side of the active item in rgba format - To remove the indicator set a color with an alpha of 0. - ''' - - font_style = OptionProperty( - 'Subhead', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - ''' Font style to use for the title text ''' - - title_template = StringProperty('MDAccordionItemTitle') - ''' Template to use for the title ''' - - icon = StringProperty(None,allownone=True) - ''' Icon name to use when this item is expanded ''' - - icon_expanded = StringProperty('chevron-up') - ''' Icon name to use when this item is expanded ''' - - icon_collapsed = StringProperty('chevron-down') - ''' Icon name to use when this item is collapsed ''' - - -Builder.load_string(''' -#:import MDLabel kivymd.label.MDLabel -#:import md_icons kivymd.icon_definitions.md_icons - - -: - canvas.before: - Color: - rgba: self.background_color or self.theme_cls.primary_color - Rectangle: - size:self.size - pos:self.pos - - PushMatrix - Translate: - xy: (dp(2),0) if self.orientation == 'vertical' else (0,dp(2)) - canvas.after: - PopMatrix - Color: - rgba: self.divider_color or self.theme_cls.divider_color - Rectangle: - size:(dp(1),self.height) if self.orientation == 'horizontal' else (self.width,dp(1)) - pos:self.pos - Color: - rgba: [0,0,0,0] if self.collapse else (self.indicator_color or self.theme_cls.accent_color) - Rectangle: - size:(dp(2),self.height) if self.orientation == 'vertical' else (self.width,dp(2)) - pos:self.pos - -[MDAccordionItemTitle@MDAccordionItemTitleLayout]: - padding: '12dp' - spacing: '12dp' - orientation: 'horizontal' if ctx.item.orientation=='vertical' else 'vertical' - canvas: - PushMatrix - Translate: - xy: (-dp(2),0) if ctx.item.orientation == 'vertical' else (0,-dp(2)) - - Color: - rgba: self.background_color or self.theme_cls.primary_color - Rectangle: - size:self.size - pos:self.pos - - canvas.after: - Color: - rgba: [0,0,0,0] if ctx.item.collapse else (ctx.item.indicator_color or self.theme_cls.accent_color) - Rectangle: - size:(dp(2),self.height) if ctx.item.orientation == 'vertical' else (self.width,dp(2)) - pos:self.pos - PopMatrix - MDLabel: - id:_icon - theme_text_color:ctx.item.title_theme_color if ctx.item.icon else 'Custom' - text_color:ctx.item.title_color if ctx.item.icon else [0,0,0,0] - text: md_icons[ctx.item.icon if ctx.item.icon else 'menu'] - font_style:'Icon' - size_hint: (None,1) if ctx.item.orientation == 'vertical' else (1,None) - size: ((self.texture_size[0],1) if ctx.item.orientation == 'vertical' else (1,self.texture_size[1])) \ - if ctx.item.icon else (0,0) - text_size: (self.width, None) if ctx.item.orientation=='vertical' else (None,self.width) - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin: self.center - canvas.after: - PopMatrix - MDLabel: - id:_label - theme_text_color:ctx.item.title_theme_color - text_color:ctx.item.title_color - text: ctx.item.title - font_style:ctx.item.font_style - text_size: (self.width, None) if ctx.item.orientation=='vertical' else (None,self.width) - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin: self.center - canvas.after: - PopMatrix - - MDLabel: - id:_expand_icon - theme_text_color:ctx.item.title_theme_color - text_color:ctx.item.title_color - font_style:'Icon' - size_hint: (None,1) if ctx.item.orientation == 'vertical' else (1,None) - size: (self.texture_size[0],1) if ctx.item.orientation == 'vertical' else (1,self.texture_size[1]) - text:md_icons[ctx.item.icon_collapsed if ctx.item.collapse else ctx.item.icon_expanded] - halign: 'right' if ctx.item.orientation=='vertical' else 'center' - #valign: 'middle' if ctx.item.orientation=='vertical' else 'bottom' - canvas.before: - PushMatrix - Rotate: - angle: 90 if ctx.item.orientation == 'horizontal' else 0 - origin:self.center - canvas.after: - PopMatrix - -''') - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class AccordionApp(App): - theme_cls = ThemeManager() - - def build(self): - # self.theme_cls.primary_palette = 'Indigo' - return Builder.load_string(""" -#:import MDLabel kivymd.label.MDLabel -#:import MDList kivymd.list.MDList -#:import OneLineListItem kivymd.list.OneLineListItem -BoxLayout: - spacing: '64dp' - MDAccordion: - orientation:'vertical' - MDAccordionItem: - title:'Item 1' - icon: 'home' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 1" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 2" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 3" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordionItem: - title:'Item 2' - icon: 'globe' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 4" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 5" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 6" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordionItem: - title:'Item 3' - ScrollView: - MDList: - OneLineListItem: - text: "Subitem 7" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 8" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - OneLineListItem: - text: "Subitem 9" - theme_text_color: 'Custom' - text_color: [1,1,1,1] - MDAccordion: - orientation:'horizontal' - MDAccordionItem: - title:'Item 1' - icon: 'home' - MDLabel: - text:'Content 1' - theme_text_color:'Primary' - MDAccordionItem: - title:'Item 2' - MDLabel: - text:'Content 2' - theme_text_color:'Primary' - MDAccordionItem: - title:'Item 3' - MDLabel: - text:'Content 3' - theme_text_color:'Primary' -""") - - - AccordionApp().run() diff --git a/src/kivymd/backgroundcolorbehavior.py b/src/kivymd/backgroundcolorbehavior.py deleted file mode 100644 index bd98f129..00000000 --- a/src/kivymd/backgroundcolorbehavior.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.properties import BoundedNumericProperty, ReferenceListProperty -from kivy.uix.widget import Widget - -Builder.load_string(''' - - canvas: - Color: - rgba: self.background_color - Rectangle: - size: self.size - pos: self.pos -''') - - -class BackgroundColorBehavior(Widget): - r = BoundedNumericProperty(1., min=0., max=1.) - g = BoundedNumericProperty(1., min=0., max=1.) - b = BoundedNumericProperty(1., min=0., max=1.) - a = BoundedNumericProperty(0., min=0., max=1.) - - background_color = ReferenceListProperty(r, g, b, a) diff --git a/src/kivymd/bottomsheet.py b/src/kivymd/bottomsheet.py deleted file mode 100644 index 901322b0..00000000 --- a/src/kivymd/bottomsheet.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Bottom Sheets -============= - -`Material Design spec Bottom Sheets page `_ - -In this module there's the :class:`MDBottomSheet` class which will let you implement your own Material Design Bottom Sheets, and there are two classes called :class:`MDListBottomSheet` and :class:`MDGridBottomSheet` implementing the ones mentioned in the spec. - -Examples --------- - -.. note:: - - These widgets are designed to be called from Python code only. - -For :class:`MDListBottomSheet`: - -.. code-block:: python - - bs = MDListBottomSheet() - bs.add_item("Here's an item with text only", lambda x: x) - bs.add_item("Here's an item with an icon", lambda x: x, icon='md-cast') - bs.add_item("Here's another!", lambda x: x, icon='md-nfc') - bs.open() - -For :class:`MDListBottomSheet`: - -.. code-block:: python - - bs = MDGridBottomSheet() - bs.add_item("Facebook", lambda x: x, icon_src='./assets/facebook-box.png') - bs.add_item("YouTube", lambda x: x, icon_src='./assets/youtube-play.png') - bs.add_item("Twitter", lambda x: x, icon_src='./assets/twitter.png') - bs.add_item("Da Cloud", lambda x: x, icon_src='./assets/cloud-upload.png') - bs.add_item("Camera", lambda x: x, icon_src='./assets/camera.png') - bs.open() - -API ---- -''' -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.gridlayout import GridLayout -from kivy.uix.modalview import ModalView -from kivy.uix.scrollview import ScrollView -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.label import MDLabel -from kivymd.list import MDList, OneLineListItem, ILeftBody, \ - OneLineIconListItem -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - background: 'atlas://data/images/defaulttheme/action_group_disabled' - background_color: 0,0,0,.8 - sv: sv - upper_padding: upper_padding - gl_content: gl_content - ScrollView: - id: sv - do_scroll_x: False - BoxLayout: - size_hint_y: None - orientation: 'vertical' - padding: 0,1,0,0 - height: upper_padding.height + gl_content.height + 1 # +1 to allow overscroll - BsPadding: - id: upper_padding - size_hint_y: None - height: root.height - min(root.width * 9 / 16, gl_content.height) - on_release: root.dismiss() - BottomSheetContent: - id: gl_content - size_hint_y: None - background_color: root.theme_cls.bg_normal - cols: 1 -''') - - -class BsPadding(ButtonBehavior, FloatLayout): - pass - - -class BottomSheetContent(BackgroundColorBehavior, GridLayout): - pass - - -class MDBottomSheet(ThemableBehavior, ModalView): - sv = ObjectProperty() - upper_padding = ObjectProperty() - gl_content = ObjectProperty() - dismiss_zone_scroll = 1000 # Arbitrary high number - - def open(self, *largs): - super(MDBottomSheet, self).open(*largs) - Clock.schedule_once(self.set_dismiss_zone, 0) - - def set_dismiss_zone(self, *largs): - # Scroll to right below overscroll threshold: - self.sv.scroll_y = 1 - self.sv.convert_distance_to_scroll(0, 1)[1] - - # This is a line where m (slope) is 1/6 and b (y-intercept) is 80: - self.dismiss_zone_scroll = self.sv.convert_distance_to_scroll( - 0, (self.height - self.upper_padding.height) * (1 / 6.0) + 80)[ - 1] - # Uncomment next line if the limit should just be half of - # visible content on open (capped by specs to 16 units to width/9: - # self.dismiss_zone_scroll = (self.sv.convert_distance_to_scroll( - # 0, self.height - self.upper_padding.height)[1] * 0.50) - - # Check if user has overscrolled enough to dismiss bottom sheet: - self.sv.bind(on_scroll_stop=self.check_if_scrolled_to_death) - - def check_if_scrolled_to_death(self, *largs): - if self.sv.scroll_y >= 1 + self.dismiss_zone_scroll: - self.dismiss() - - def add_widget(self, widget, index=0): - if type(widget) == ScrollView: - super(MDBottomSheet, self).add_widget(widget, index) - else: - self.gl_content.add_widget(widget,index) - - -Builder.load_string(''' -#:import md_icons kivymd.icon_definitions.md_icons - - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - halign: 'center' - theme_text_color: 'Primary' - valign: 'middle' -''') - - -class ListBSIconLeft(ILeftBody, MDLabel): - icon = StringProperty() - - -class MDListBottomSheet(MDBottomSheet): - mlist = ObjectProperty() - - def __init__(self, **kwargs): - super(MDListBottomSheet, self).__init__(**kwargs) - self.mlist = MDList() - self.gl_content.add_widget(self.mlist) - Clock.schedule_once(self.resize_content_layout, 0) - - def resize_content_layout(self, *largs): - self.gl_content.height = self.mlist.height - - def add_item(self, text, callback, icon=None): - if icon: - item = OneLineIconListItem(text=text, on_release=callback) - item.add_widget(ListBSIconLeft(icon=icon)) - else: - item = OneLineListItem(text=text, on_release=callback) - - item.bind(on_release=lambda x: self.dismiss()) - self.mlist.add_widget(item) - - -Builder.load_string(''' - - orientation: 'vertical' - padding: 0, dp(24), 0, 0 - size_hint_y: None - size: dp(64), dp(96) - BoxLayout: - padding: dp(8), 0, dp(8), dp(8) - size_hint_y: None - height: dp(48) - Image: - source: root.source - MDLabel: - font_style: 'Caption' - theme_text_color: 'Secondary' - text: root.caption - halign: 'center' -''') - - -class GridBSItem(ButtonBehavior, BoxLayout): - source = StringProperty() - - caption = StringProperty() - - -class MDGridBottomSheet(MDBottomSheet): - def __init__(self, **kwargs): - super(MDGridBottomSheet, self).__init__(**kwargs) - self.gl_content.padding = (dp(16), 0, dp(16), dp(24)) - self.gl_content.height = dp(24) - self.gl_content.cols = 3 - - def add_item(self, text, callback, icon_src): - item = GridBSItem( - caption=text, - on_release=callback, - source=icon_src - ) - item.bind(on_release=lambda x: self.dismiss()) - if len(self.gl_content.children) % 3 == 0: - self.gl_content.height += dp(96) - self.gl_content.add_widget(item) diff --git a/src/kivymd/button.py b/src/kivymd/button.py deleted file mode 100644 index 75016716..00000000 --- a/src/kivymd/button.py +++ /dev/null @@ -1,453 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Buttons -======= - -`Material Design spec, Buttons page `_ - -`Material Design spec, Buttons: Floating Action Button page `_ - -TO-DO: DOCUMENT MODULE -''' -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.utils import get_color_from_hex -from kivy.properties import StringProperty, BoundedNumericProperty, \ - ListProperty, AliasProperty, BooleanProperty, NumericProperty, \ - OptionProperty -from kivy.uix.anchorlayout import AnchorLayout -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.animation import Animation -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.ripplebehavior import CircularRippleBehavior, \ - RectangularRippleBehavior -from kivymd.elevationbehavior import ElevationBehavior, \ - RoundElevationBehavior -from kivymd.theming import ThemableBehavior -from kivymd.color_definitions import colors - -Builder.load_string(''' -#:import md_icons kivymd.icon_definitions.md_icons -#:import colors kivymd.color_definitions.colors -#:import MDLabel kivymd.label.MDLabel - - size_hint: (None, None) - size: (dp(48), dp(48)) - padding: dp(12) - theme_text_color: 'Primary' - MDLabel: - id: _label - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - halign: 'center' - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - valign: 'middle' - - - canvas: - Color: - #rgba: self.background_color if self.state == 'normal' else self._bg_color_down - rgba: self._current_button_color - Rectangle: - size: self.size - pos: self.pos - size_hint: (None, None) - height: dp(36) - width: _label.texture_size[0] + dp(16) - padding: (dp(8), 0) - theme_text_color: 'Custom' - text_color: root.theme_cls.primary_color - MDLabel: - id: _label - text: root._text - font_style: 'Button' - size_hint_x: None - text_size: (None, root.height) - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - valign: 'middle' - halign: 'center' - opposite_colors: root.opposite_colors - -: - canvas: - Clear - Color: - rgba: self.background_color_disabled if self.disabled else \ - (self.background_color if self.state == 'normal' else self.background_color_down) - Rectangle: - size: self.size - pos: self.pos - - anchor_x: 'center' - anchor_y: 'center' - background_color: root.theme_cls.primary_color - background_color_down: root.theme_cls.primary_dark - background_color_disabled: root.theme_cls.divider_color - theme_text_color: 'Primary' - MDLabel: - id: label - font_style: 'Button' - text: root._text - size_hint: None, None - width: root.width - text_size: self.width, None - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - disabled: root.disabled - halign: 'center' - valign: 'middle' - -: - canvas: - Clear - Color: - rgba: self.background_color_disabled if self.disabled else \ - (self.background_color if self.state == 'normal' else self.background_color_down) - Ellipse: - size: self.size - pos: self.pos - - anchor_x: 'center' - anchor_y: 'center' - background_color: root.theme_cls.accent_color - background_color_down: root.theme_cls.accent_dark - background_color_disabled: root.theme_cls.divider_color - theme_text_color: 'Primary' - MDLabel: - id: label - font_style: 'Icon' - text: u"{}".format(md_icons[root.icon]) - size_hint: None, None - size: dp(24), dp(24) - text_size: self.size - theme_text_color: root.theme_text_color - text_color: root.text_color - opposite_colors: root.opposite_colors - disabled: root.disabled - halign: 'center' - valign: 'middle' -''') - - -class MDIconButton(CircularRippleBehavior, ButtonBehavior, BoxLayout): - icon = StringProperty('circle') - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - opposite_colors = BooleanProperty(False) - - -class MDFlatButton(ThemableBehavior, RectangularRippleBehavior, - ButtonBehavior, BackgroundColorBehavior, AnchorLayout): - width = BoundedNumericProperty(dp(64), min=dp(64), max=None, - errorhandler=lambda x: dp(64)) - - text_color = ListProperty() - - text = StringProperty('') - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - _text = StringProperty('') - _bg_color_down = ListProperty([0, 0, 0, 0]) - _current_button_color = ListProperty([0, 0, 0, 0]) - - def __init__(self, **kwargs): - super(MDFlatButton, self).__init__(**kwargs) - self._current_button_color = self.background_color - self._bg_color_down = get_color_from_hex( - colors[self.theme_cls.theme_style]['FlatButtonDown']) - - Clock.schedule_once(lambda x: self.ids._label.bind( - texture_size=self.update_width_on_label_texture)) - - def update_width_on_label_texture(self, instance, value): - self.ids._label.width = value[0] - - def on_text(self, instance, value): - self._text = value.upper() - - def on_touch_down(self, touch): - if touch.is_mouse_scrolling: - return False - elif not self.collide_point(touch.x, touch.y): - return False - elif self in touch.ud: - return False - elif self.disabled: - return False - else: - self.fade_bg = Animation(duration=.2, _current_button_color=get_color_from_hex( - colors[self.theme_cls.theme_style]['FlatButtonDown'])) - self.fade_bg.start(self) - return super(MDFlatButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if touch.grab_current is self: - self.fade_bg.stop_property(self, '_current_button_color') - Animation(duration=.05, _current_button_color=self.background_color).start(self) - return super(MDFlatButton, self).on_touch_up(touch) - - -class MDRaisedButton(ThemableBehavior, RectangularRippleBehavior, - ElevationBehavior, ButtonBehavior, - AnchorLayout): - _bg_color_down = ListProperty([]) - background_color = ListProperty() - background_color_down = ListProperty() - background_color_disabled = ListProperty() - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - def _get_bg_color_down(self): - return self._bg_color_down - - def _set_bg_color_down(self, color, alpha=None): - if len(color) == 2: - self._bg_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_down[3] = alpha - elif len(color) == 4: - self._bg_color_down = color - - background_color_down = AliasProperty(_get_bg_color_down, - _set_bg_color_down, - bind=('_bg_color_down',)) - - _bg_color_disabled = ListProperty([]) - - def _get_bg_color_disabled(self): - return self._bg_color_disabled - - def _set_bg_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._bg_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_disabled[3] = alpha - elif len(color) == 4: - self._bg_color_disabled = color - - background_color_disabled = AliasProperty(_get_bg_color_disabled, - _set_bg_color_disabled, - bind=('_bg_color_disabled',)) - - _elev_norm = NumericProperty(2) - - def _get_elev_norm(self): - return self._elev_norm - - def _set_elev_norm(self, value): - self._elev_norm = value if value <= 12 else 12 - self._elev_raised = (value + 6) if value + 6 <= 12 else 12 - self.elevation = self._elev_norm - - elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm, - bind=('_elev_norm',)) - - _elev_raised = NumericProperty(8) - - def _get_elev_raised(self): - return self._elev_raised - - def _set_elev_raised(self, value): - self._elev_raised = value if value + self._elev_norm <= 12 else 12 - - elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised, - bind=('_elev_raised',)) - - text = StringProperty() - - _text = StringProperty() - - def __init__(self, **kwargs): - super(MDRaisedButton, self).__init__(**kwargs) - self.elevation_press_anim = Animation(elevation=self.elevation_raised, - duration=.2, t='out_quad') - self.elevation_release_anim = Animation( - elevation=self.elevation_normal, duration=.2, t='out_quad') - - def on_disabled(self, instance, value): - if value: - self.elevation = 0 - else: - self.elevation = self.elevation_normal - super(MDRaisedButton, self).on_disabled(instance, value) - - def on_touch_down(self, touch): - if not self.disabled: - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - if self in touch.ud: - return False - Animation.cancel_all(self, 'elevation') - self.elevation_press_anim.start(self) - return super(MDRaisedButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if not self.disabled: - if touch.grab_current is not self: - return super(ButtonBehavior, self).on_touch_up(touch) - Animation.cancel_all(self, 'elevation') - self.elevation_release_anim.start(self) - else: - Animation.cancel_all(self, 'elevation') - self.elevation = 0 - return super(MDRaisedButton, self).on_touch_up(touch) - - def on_text(self, instance, text): - self._text = text.upper() - - def on__elev_norm(self, instance, value): - self.elevation_release_anim = Animation(elevation=value, - duration=.2, t='out_quad') - - def on__elev_raised(self, instance, value): - self.elevation_press_anim = Animation(elevation=value, - duration=.2, t='out_quad') - - -class MDFloatingActionButton(ThemableBehavior, CircularRippleBehavior, - RoundElevationBehavior, ButtonBehavior, - AnchorLayout): - _bg_color_down = ListProperty([]) - background_color = ListProperty() - background_color_down = ListProperty() - background_color_disabled = ListProperty() - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - text_color = ListProperty(None, allownone=True) - - def _get_bg_color_down(self): - return self._bg_color_down - - def _set_bg_color_down(self, color, alpha=None): - if len(color) == 2: - self._bg_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_down[3] = alpha - elif len(color) == 4: - self._bg_color_down = color - - background_color_down = AliasProperty(_get_bg_color_down, - _set_bg_color_down, - bind=('_bg_color_down',)) - - _bg_color_disabled = ListProperty([]) - - def _get_bg_color_disabled(self): - return self._bg_color_disabled - - def _set_bg_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._bg_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._bg_color_disabled[3] = alpha - elif len(color) == 4: - self._bg_color_disabled = color - - background_color_disabled = AliasProperty(_get_bg_color_disabled, - _set_bg_color_disabled, - bind=('_bg_color_disabled',)) - icon = StringProperty('android') - - _elev_norm = NumericProperty(6) - - def _get_elev_norm(self): - return self._elev_norm - - def _set_elev_norm(self, value): - self._elev_norm = value if value <= 12 else 12 - self._elev_raised = (value + 6) if value + 6 <= 12 else 12 - self.elevation = self._elev_norm - - elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm, - bind=('_elev_norm',)) - - # _elev_raised = NumericProperty(12) - _elev_raised = NumericProperty(6) - - def _get_elev_raised(self): - return self._elev_raised - - def _set_elev_raised(self, value): - self._elev_raised = value if value + self._elev_norm <= 12 else 12 - - elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised, - bind=('_elev_raised',)) - - def __init__(self, **kwargs): - if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12: - self.elevation_raised = self.elevation_normal + 6 - elif self.elevation_raised == 0: - self.elevation_raised = 12 - - super(MDFloatingActionButton, self).__init__(**kwargs) - - self.elevation_press_anim = Animation(elevation=self.elevation_raised, - duration=.2, t='out_quad') - self.elevation_release_anim = Animation( - elevation=self.elevation_normal, duration=.2, t='out_quad') - - def _set_ellipse(self, instance, value): - ellipse = self.ellipse - ripple_rad = self.ripple_rad - - ellipse.size = (ripple_rad, ripple_rad) - ellipse.pos = (self.center_x - ripple_rad / 2., - self.center_y - ripple_rad / 2.) - - def on_disabled(self, instance, value): - super(MDFloatingActionButton, self).on_disabled(instance, value) - if self.disabled: - self.elevation = 0 - else: - self.elevation = self.elevation_normal - - def on_touch_down(self, touch): - if not self.disabled: - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - if self in touch.ud: - return False - self.elevation_press_anim.stop(self) - self.elevation_press_anim.start(self) - return super(MDFloatingActionButton, self).on_touch_down(touch) - - def on_touch_up(self, touch): - if not self.disabled: - if touch.grab_current is not self: - return super(ButtonBehavior, self).on_touch_up(touch) - self.elevation_release_anim.stop(self) - self.elevation_release_anim.start(self) - return super(MDFloatingActionButton, self).on_touch_up(touch) - - def on_elevation_normal(self, instance, value): - self.elevation = value - - def on_elevation_raised(self, instance, value): - if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12: - self.elevation_raised = self.elevation_normal + 6 - elif self.elevation_raised == 0: - self.elevation_raised = 12 diff --git a/src/kivymd/card.py b/src/kivymd/card.py deleted file mode 100644 index d411644b..00000000 --- a/src/kivymd/card.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.properties import BoundedNumericProperty, ReferenceListProperty, ListProperty,BooleanProperty -from kivy.uix.boxlayout import BoxLayout -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.theming import ThemableBehavior -from kivy.metrics import dp -from kivy.uix.widget import Widget - -Builder.load_string(''' - - canvas: - Color: - rgba: self.background_color - RoundedRectangle: - size: self.size - pos: self.pos - radius: [self.border_radius] - Color: - rgba: self.theme_cls.divider_color - a: self.border_color_a - Line: - rounded_rectangle: (self.pos[0],self.pos[1],self.size[0],self.size[1],self.border_radius) - background_color: self.theme_cls.bg_light - - - canvas: - Color: - rgba: self.theme_cls.divider_color - Rectangle: - size: self.size - pos: self.pos -''') - - -class MDSeparator(ThemableBehavior, BoxLayout): - """ A separator line """ - def __init__(self, *args, **kwargs): - super(MDSeparator, self).__init__(*args, **kwargs) - self.on_orientation() - - def on_orientation(self,*args): - self.size_hint = (1, None) if self.orientation == 'horizontal' else (None, 1) - if self.orientation == 'horizontal': - self.height = dp(1) - else: - self.width = dp(1) - - -class MDCard(ThemableBehavior, ElevationBehavior, BoxLayout): - r = BoundedNumericProperty(1., min=0., max=1.) - g = BoundedNumericProperty(1., min=0., max=1.) - b = BoundedNumericProperty(1., min=0., max=1.) - a = BoundedNumericProperty(0., min=0., max=1.) - - border_radius = BoundedNumericProperty(dp(3),min=0) - border_color_a = BoundedNumericProperty(0, min=0., max=1.) - background_color = ReferenceListProperty(r, g, b, a) diff --git a/src/kivymd/color_definitions.py b/src/kivymd/color_definitions.py deleted file mode 100644 index c81bd731..00000000 --- a/src/kivymd/color_definitions.py +++ /dev/null @@ -1,360 +0,0 @@ -colors = { - 'Pink': { - '50': 'fce4ec', - '100': 'f8bbd0', - '200': 'f48fb1', - '300': 'f06292', - '400': 'ec407a', - '500': 'e91e63', - '600': 'd81b60', - '700': 'C2185B', - '800': 'ad1457', - '900': '88e4ff', - 'A100': 'ff80ab', - 'A400': 'F50057', - 'A700': 'c51162', - 'A200': 'ff4081' - }, - - 'Blue': { - '200': '90caf9', - '900': '0D47A1', - '600': '1e88e5', - 'A100': '82b1ff', - '300': '64b5f6', - 'A400': '2979ff', - '700': '1976d2', - '50': 'e3f2fd', - 'A700': '2962ff', - '400': '42a5f5', - '100': 'bbdefb', - '800': '1565c0', - 'A200': '448aff', - '500': '2196f3' - }, - - 'Indigo': { - '200': '9fa8da', - '900': '1a237e', - '600': '3949ab', - 'A100': '8c9eff', - '300': '7986cb', - 'A400': '3d5afe', - '700': '303f9f', - '50': 'e8eaf6', - 'A700': '304ffe', - '400': '5c6bc0', - '100': 'c5cae9', - '800': '283593', - 'A200': '536dfe', - '500': '3f51b5' - }, - - 'BlueGrey': { - '200': 'b0bec5', - '900': '263238', - '600': '546e7a', - '300': '90a4ae', - '700': '455a64', - '50': 'eceff1', - '400': '78909c', - '100': 'cfd8dc', - '800': '37474f', - '500': '607d8b' - }, - - 'Brown': { - '200': 'bcaaa4', - '900': '3e2723', - '600': '6d4c41', - '300': 'a1887f', - '700': '5d4037', - '50': 'efebe9', - '400': '8d6e63', - '100': 'd7ccc8', - '800': '4e342e', - '500': '795548' - }, - - 'LightBlue': { - '200': '81d4fa', - '900': '01579B', - '600': '039BE5', - 'A100': '80d8ff', - '300': '4fc3f7', - 'A400': '00B0FF', - '700': '0288D1', - '50': 'e1f5fe', - 'A700': '0091EA', - '400': '29b6f6', - '100': 'b3e5fc', - '800': '0277BD', - 'A200': '40c4ff', - '500': '03A9F4' - }, - - 'Purple': { - '200': 'ce93d8', - '900': '4a148c', - '600': '8e24aa', - 'A100': 'ea80fc', - '300': 'ba68c8', - 'A400': 'D500F9', - '700': '7b1fa2', - '50': 'f3e5f5', - 'A700': 'AA00FF', - '400': 'ab47bc', - '100': 'e1bee7', - '800': '6a1b9a', - 'A200': 'e040fb', - '500': '9c27b0' - }, - - 'Grey': { - '200': 'eeeeee', - '900': '212121', - '600': '757575', - '300': 'e0e0e0', - '700': '616161', - '50': 'fafafa', - '400': 'bdbdbd', - '100': 'f5f5f5', - '800': '424242', - '500': '9e9e9e' - }, - - 'Yellow': { - '200': 'fff59d', - '900': 'f57f17', - '600': 'fdd835', - 'A100': 'ffff8d', - '300': 'fff176', - 'A400': 'FFEA00', - '700': 'fbc02d', - '50': 'fffde7', - 'A700': 'FFD600', - '400': 'ffee58', - '100': 'fff9c4', - '800': 'f9a825', - 'A200': 'FFFF00', - '500': 'ffeb3b' - }, - - 'LightGreen': { - '200': 'c5e1a5', - '900': '33691e', - '600': '7cb342', - 'A100': 'ccff90', - '300': 'aed581', - 'A400': '76FF03', - '700': '689f38', - '50': 'f1f8e9', - 'A700': '64dd17', - '400': '9ccc65', - '100': 'dcedc8', - '800': '558b2f', - 'A200': 'b2ff59', - '500': '8bc34a' - }, - - 'DeepOrange': { - '200': 'ffab91', - '900': 'bf36c', - '600': 'f4511e', - 'A100': 'ff9e80', - '300': 'ff8a65', - 'A400': 'FF3D00', - '700': 'e64a19', - '50': 'fbe9e7', - 'A700': 'DD2C00', - '400': 'ff7043', - '100': 'ffccbc', - '800': 'd84315', - 'A200': 'ff6e40', - '500': 'ff5722' - }, - - 'Green': { - '200': 'a5d6a7', - '900': '1b5e20', - '600': '43a047', - 'A100': 'b9f6ca', - '300': '81c784', - 'A400': '00E676', - '700': '388e3c', - '50': 'e8f5e9', - 'A700': '00C853', - '400': '66bb6a', - '100': 'c8e6c9', - '800': '2e7d32', - 'A200': '69f0ae', - '500': '4caf50' - }, - - 'Red': { - '200': 'ef9a9a', - '900': 'b71c1c', - '600': 'e53935', - 'A100': 'ff8a80', - '300': 'e57373', - 'A400': 'ff1744', - '700': 'd32f2f', - '50': 'ffebee', - 'A700': 'd50000', - '400': 'ef5350', - '100': 'ffcdd2', - '800': 'c62828', - 'A200': 'ff5252', - '500': 'f44336' - }, - - 'Teal': { - '200': '80cbc4', - '900': '004D40', - '600': '00897B', - 'A100': 'a7ffeb', - '300': '4db6ac', - 'A400': '1de9b6', - '700': '00796B', - '50': 'e0f2f1', - 'A700': '00BFA5', - '400': '26a69a', - '100': 'b2dfdb', - '800': '00695C', - 'A200': '64ffda', - '500': '009688' - }, - - 'Orange': { - '200': 'ffcc80', - '900': 'E65100', - '600': 'FB8C00', - 'A100': 'ffd180', - '300': 'ffb74d', - 'A400': 'FF9100', - '700': 'F57C00', - '50': 'fff3e0', - 'A700': 'FF6D00', - '400': 'ffa726', - '100': 'ffe0b2', - '800': 'EF6C00', - 'A200': 'ffab40', - '500': 'FF9800' - }, - - 'Cyan': { - '200': '80deea', - '900': '006064', - '600': '00ACC1', - 'A100': '84ffff', - '300': '4dd0e1', - 'A400': '00E5FF', - '700': '0097A7', - '50': 'e0f7fa', - 'A700': '00B8D4', - '400': '26c6da', - '100': 'b2ebf2', - '800': '00838F', - 'A200': '18ffff', - '500': '00BCD4' - }, - - 'Amber': { - '200': 'ffe082', - '900': 'FF6F00', - '600': 'FFB300', - 'A100': 'ffe57f', - '300': 'ffd54f', - 'A400': 'FFC400', - '700': 'FFA000', - '50': 'fff8e1', - 'A700': 'FFAB00', - '400': 'ffca28', - '100': 'ffecb3', - '800': 'FF8F00', - 'A200': 'ffd740', - '500': 'FFC107' - }, - - 'DeepPurple': { - '200': 'b39ddb', - '900': '311b92', - '600': '5e35b1', - 'A100': 'b388ff', - '300': '9575cd', - 'A400': '651fff', - '700': '512da8', - '50': 'ede7f6', - 'A700': '6200EA', - '400': '7e57c2', - '100': 'd1c4e9', - '800': '4527a0', - 'A200': '7c4dff', - '500': '673ab7' - }, - - 'Lime': { - '200': 'e6ee9c', - '900': '827717', - '600': 'c0ca33', - 'A100': 'f4ff81', - '300': 'dce775', - 'A400': 'C6FF00', - '700': 'afb42b', - '50': 'f9fbe7', - 'A700': 'AEEA00', - '400': 'd4e157', - '100': 'f0f4c3', - '800': '9e9d24', - 'A200': 'eeff41', - '500': 'cddc39' - }, - - 'Light': { - 'StatusBar': 'E0E0E0', - 'AppBar': 'F5F5F5', - 'Background': 'FAFAFA', - 'CardsDialogs': 'FFFFFF', - 'FlatButtonDown': 'cccccc' - }, - - 'Dark': { - 'StatusBar': '000000', - 'AppBar': '212121', - 'Background': '303030', - 'CardsDialogs': '424242', - 'FlatButtonDown': '999999' - } -} - -light_colors = { - 'Pink': ['50' '100', '200', 'A100'], - 'Blue': ['50' '100', '200', '300', '400', 'A100'], - 'Indigo': ['50' '100', '200', 'A100'], - 'BlueGrey': ['50' '100', '200', '300'], - 'Brown': ['50' '100', '200'], - 'LightBlue': ['50' '100', '200', '300', '400', '500', 'A100', 'A200', - 'A400'], - 'Purple': ['50' '100', '200', 'A100'], - 'Grey': ['50' '100', '200', '300', '400', '500'], - 'Yellow': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - '900', 'A100', 'A200', 'A400', 'A700'], - 'LightGreen': ['50' '100', '200', '300', '400', '500', '600', 'A100', - 'A200', 'A400', 'A700'], - 'DeepOrange': ['50' '100', '200', '300', '400', 'A100', 'A200'], - 'Green': ['50' '100', '200', '300', '400', '500', 'A100', 'A200', 'A400', - 'A700'], - 'Red': ['50' '100', '200', '300', 'A100'], - 'Teal': ['50' '100', '200', '300', '400', 'A100', 'A200', 'A400', 'A700'], - 'Orange': ['50' '100', '200', '300', '400', '500', '600', '700', 'A100', - 'A200', 'A400', 'A700'], - 'Cyan': ['50' '100', '200', '300', '400', '500', '600', 'A100', 'A200', - 'A400', 'A700'], - 'Amber': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - '900', 'A100', 'A200', 'A400', 'A700'], - 'DeepPurple': ['50' '100', '200', 'A100'], - 'Lime': ['50' '100', '200', '300', '400', '500', '600', '700', '800', - 'A100', 'A200', 'A400', 'A700'], - 'Dark': [], - 'Light': ['White', 'MainBackground', 'DialogBackground'] -} diff --git a/src/kivymd/date_picker.py b/src/kivymd/date_picker.py deleted file mode 100644 index 5194298e..00000000 --- a/src/kivymd/date_picker.py +++ /dev/null @@ -1,325 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivymd.label import MDLabel -from kivymd.theming import ThemableBehavior -from kivy.uix.floatlayout import FloatLayout -from kivymd.elevationbehavior import ElevationBehavior -import calendar -from datetime import date -import datetime -from kivy.properties import StringProperty, NumericProperty, ObjectProperty, \ - BooleanProperty -from kivy.uix.anchorlayout import AnchorLayout -from kivy.uix.behaviors import ButtonBehavior -from kivymd.ripplebehavior import CircularRippleBehavior -from kivy.clock import Clock -from kivy.core.window import Window - -Builder.load_string(""" -#:import calendar calendar - - cal_layout: cal_layout - - size_hint: (None, None) - size: [dp(328), dp(484)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(512), dp(304)] - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgb: app.theme_cls.primary_color - Rectangle: - size: [dp(328), dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(168), dp(304)] - pos: [root.pos[0], root.pos[1] + root.height-dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [root.pos[0], root.pos[1] + root.height-dp(304)] - Color: - rgb: app.theme_cls.bg_normal - Rectangle: - size: [dp(328), dp(484)-dp(96)] if self.theme_cls.device_orientation == 'portrait'\ - else [dp(344), dp(304)] - pos: [root.pos[0], root.pos[1] + root.height-dp(96)-(dp(484)-dp(96))]\ - if self.theme_cls.device_orientation == 'portrait' else [root.pos[0]+dp(168), root.pos[1]] #+dp(334) - MDLabel: - id: label_full_date - font_style: 'Display1' - text_color: 1, 1, 1, 1 - theme_text_color: 'Custom' - size_hint: (None, None) - size: [root.width, dp(30)] if root.theme_cls.device_orientation == 'portrait'\ - else [dp(168), dp(30)] - pos: [root.pos[0]+dp(23), root.pos[1] + root.height - dp(74)] \ - if root.theme_cls.device_orientation == 'portrait' \ - else [root.pos[0]+dp(3), root.pos[1] + dp(214)] - line_height: 0.84 - valign: 'middle' - text_size: [root.width, None] if root.theme_cls.device_orientation == 'portrait'\ - else [dp(149), None] - bold: True - text: root.fmt_lbl_date(root.sel_year, root.sel_month, root.sel_day, root.theme_cls.device_orientation) - MDLabel: - id: label_year - font_style: 'Subhead' - text_color: 1, 1, 1, 1 - theme_text_color: 'Custom' - size_hint: (None, None) - size: root.width, dp(30) - pos: (root.pos[0]+dp(23), root.pos[1]+root.height-dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (root.pos[0]+dp(16), root.pos[1]+root.height-dp(41)) - valign: 'middle' - text: str(root.sel_year) - GridLayout: - id: cal_layout - cols: 7 - size: (dp(44*7), dp(40*7)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(46*7), dp(32*7)) - col_default_width: dp(42) if root.theme_cls.device_orientation == 'portrait'\ - else dp(39) - size_hint: (None, None) - padding: (dp(2), 0) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(7), 0) - spacing: (dp(2), 0) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(7), 0) - pos: (root.pos[0]+dp(10), root.pos[1]+dp(60)) if root.theme_cls.device_orientation == 'portrait'\ - else (root.pos[0]+dp(168)+dp(8), root.pos[1]+dp(48)) - MDLabel: - id: label_month_selector - font_style: 'Body2' - text: calendar.month_name[root.month].capitalize() + ' ' + str(root.year) - size_hint: (None, None) - size: root.width, dp(30) - pos: root.pos - theme_text_color: 'Primary' - pos_hint: {'center_x': 0.5, 'center_y': 0.75} if self.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.67, 'center_y': 0.915} - valign: "middle" - halign: "center" - MDIconButton: - icon: 'chevron-left' - theme_text_color: 'Secondary' - pos_hint: {'center_x': 0.09, 'center_y': 0.745} if root.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.39, 'center_y': 0.925} - on_release: root.change_month('prev') - MDIconButton: - icon: 'chevron-right' - theme_text_color: 'Secondary' - pos_hint: {'center_x': 0.92, 'center_y': 0.745} if root.theme_cls.device_orientation == 'portrait'\ - else {'center_x': 0.94, 'center_y': 0.925} - on_release: root.change_month('next') - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72)*2, root.pos[1] + dp(7) - text: "Cancel" - on_release: root.dismiss() - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(7) - text: "OK" - on_release: root.ok_click() - - - size_hint: None, None - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - MDLabel: - font_style: 'Caption' - theme_text_color: 'Custom' if root.is_today and not root.is_selected else 'Primary' - text_color: root.theme_cls.primary_color - opposite_colors: root.is_selected if root.owner.sel_month == root.owner.month \ - and root.owner.sel_year == root.owner.year and str(self.text) == str(root.owner.sel_day) else False - size_hint_x: None - valign: 'middle' - halign: 'center' - text: root.text - - - font_style: 'Caption' - theme_text_color: 'Secondary' - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - size_hint: None, None - text_size: self.size - valign: 'middle' if root.theme_cls.device_orientation == 'portrait' else 'bottom' - halign: 'center' - - - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - size_hint: (None, None) - canvas: - Color: - rgba: self.theme_cls.primary_color if self.shown else [0, 0, 0, 0] - Ellipse: - size: (dp(40), dp(40)) if root.theme_cls.device_orientation == 'portrait'\ - else (dp(32), dp(32)) - pos: self.pos if root.theme_cls.device_orientation == 'portrait'\ - else [self.pos[0] + dp(3), self.pos[1]] -""") - - -class DaySelector(ThemableBehavior, AnchorLayout): - shown = BooleanProperty(False) - - def __init__(self, parent): - super(DaySelector, self).__init__() - self.parent_class = parent - self.parent_class.add_widget(self, index=7) - self.selected_widget = None - Window.bind(on_resize=self.move_resize) - - def update(self): - parent = self.parent_class - if parent.sel_month == parent.month and parent.sel_year == parent.year: - self.shown = True - else: - self.shown = False - - def set_widget(self, widget): - self.selected_widget = widget - self.pos = widget.pos - self.move_resize(do_again=True) - self.update() - - def move_resize(self, window=None, width=None, height=None, do_again=True): - self.pos = self.selected_widget.pos - if do_again: - Clock.schedule_once(lambda x: self.move_resize(do_again=False), 0.01) - - -class DayButton(ThemableBehavior, CircularRippleBehavior, ButtonBehavior, - AnchorLayout): - text = StringProperty() - owner = ObjectProperty() - is_today = BooleanProperty(False) - is_selected = BooleanProperty(False) - - def on_release(self): - self.owner.set_selected_widget(self) - - -class WeekdayLabel(MDLabel): - pass - - -class MDDatePicker(FloatLayout, ThemableBehavior, ElevationBehavior, - ModalView): - _sel_day_widget = ObjectProperty() - cal_list = None - cal_layout = ObjectProperty() - sel_year = NumericProperty() - sel_month = NumericProperty() - sel_day = NumericProperty() - day = NumericProperty() - month = NumericProperty() - year = NumericProperty() - today = date.today() - callback = ObjectProperty() - - class SetDateError(Exception): - pass - - def __init__(self, callback, year=None, month=None, day=None, - firstweekday=0, - **kwargs): - self.callback = callback - self.cal = calendar.Calendar(firstweekday) - self.sel_year = year if year else self.today.year - self.sel_month = month if month else self.today.month - self.sel_day = day if day else self.today.day - self.month = self.sel_month - self.year = self.sel_year - self.day = self.sel_day - super(MDDatePicker, self).__init__(**kwargs) - self.selector = DaySelector(parent=self) - self.generate_cal_widgets() - self.update_cal_matrix(self.sel_year, self.sel_month) - self.set_month_day(self.sel_day) - self.selector.update() - - def ok_click(self): - self.callback(date(self.sel_year, self.sel_month, self.sel_day)) - self.dismiss() - - def fmt_lbl_date(self, year, month, day, orientation): - d = datetime.date(int(year), int(month), int(day)) - separator = '\n' if orientation == 'landscape' else ' ' - return d.strftime('%a,').capitalize() + separator + d.strftime( - '%b').capitalize() + ' ' + str(day).lstrip('0') - - def set_date(self, year, month, day): - try: - date(year, month, day) - except Exception as e: - print(e) - if str(e) == "day is out of range for month": - raise self.SetDateError(" Day %s day is out of range for month %s" % (day, month)) - elif str(e) == "month must be in 1..12": - raise self.SetDateError("Month must be between 1 and 12, got %s" % month) - elif str(e) == "year is out of range": - raise self.SetDateError("Year must be between %s and %s, got %s" % - (datetime.MINYEAR, datetime.MAXYEAR, year)) - else: - self.sel_year = year - self.sel_month = month - self.sel_day = day - self.month = self.sel_month - self.year = self.sel_year - self.day = self.sel_day - self.update_cal_matrix(self.sel_year, self.sel_month) - self.set_month_day(self.sel_day) - self.selector.update() - - def set_selected_widget(self, widget): - if self._sel_day_widget: - self._sel_day_widget.is_selected = False - widget.is_selected = True - self.sel_month = int(self.month) - self.sel_year = int(self.year) - self.sel_day = int(widget.text) - self._sel_day_widget = widget - self.selector.set_widget(widget) - - def set_month_day(self, day): - for idx in range(len(self.cal_list)): - if str(day) == str(self.cal_list[idx].text): - self._sel_day_widget = self.cal_list[idx] - self.sel_day = int(self.cal_list[idx].text) - if self._sel_day_widget: - self._sel_day_widget.is_selected = False - self._sel_day_widget = self.cal_list[idx] - self.cal_list[idx].is_selected = True - self.selector.set_widget(self.cal_list[idx]) - - def update_cal_matrix(self, year, month): - try: - dates = [x for x in self.cal.itermonthdates(year, month)] - except ValueError as e: - if str(e) == "year is out of range": - pass - else: - self.year = year - self.month = month - for idx in range(len(self.cal_list)): - if idx >= len(dates) or dates[idx].month != month: - self.cal_list[idx].disabled = True - self.cal_list[idx].text = '' - else: - self.cal_list[idx].disabled = False - self.cal_list[idx].text = str(dates[idx].day) - self.cal_list[idx].is_today = dates[idx] == self.today - self.selector.update() - - def generate_cal_widgets(self): - cal_list = [] - for i in calendar.day_abbr: - self.cal_layout.add_widget(WeekdayLabel(text=i[0].upper())) - for i in range(6 * 7): # 6 weeks, 7 days a week - db = DayButton(owner=self) - cal_list.append(db) - self.cal_layout.add_widget(db) - self.cal_list = cal_list - - def change_month(self, operation): - op = 1 if operation is 'next' else -1 - sl, sy = self.month, self.year - m = 12 if sl + op == 0 else 1 if sl + op == 13 else sl + op - y = sy - 1 if sl + op == 0 else sy + 1 if sl + op == 13 else sy - self.update_cal_matrix(y, m) diff --git a/src/kivymd/dialog.py b/src/kivymd/dialog.py deleted file mode 100644 index cb6b7601..00000000 --- a/src/kivymd/dialog.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty, ListProperty -from kivy.metrics import dp -from kivy.uix.modalview import ModalView -from kivy.animation import Animation -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.button import MDFlatButton - -Builder.load_string(''' -: - canvas: - Color: - rgba: self.theme_cls.bg_light - Rectangle: - size: self.size - pos: self.pos - - _container: container - _action_area: action_area - elevation: 12 - GridLayout: - cols: 1 - - GridLayout: - cols: 1 - padding: dp(24), dp(24), dp(24), 0 - spacing: dp(20) - MDLabel: - text: root.title - font_style: 'Title' - theme_text_color: 'Primary' - halign: 'left' - valign: 'middle' - size_hint_y: None - text_size: self.width, None - height: self.texture_size[1] - - BoxLayout: - id: container - - AnchorLayout: - anchor_x: 'right' - anchor_y: 'center' - size_hint: 1, None - height: dp(48) - padding: dp(8), dp(8) - spacing: dp(4) - - GridLayout: - id: action_area - rows: 1 - size_hint: None, None if len(root._action_buttons) > 0 else 1 - height: dp(36) if len(root._action_buttons) > 0 else 0 - width: self.minimum_width -''') - - -class MDDialog(ThemableBehavior, ElevationBehavior, ModalView): - title = StringProperty('') - - content = ObjectProperty(None) - - background_color = ListProperty([0, 0, 0, .2]) - - _container = ObjectProperty() - _action_buttons = ListProperty([]) - _action_area = ObjectProperty() - - def __init__(self, **kwargs): - super(MDDialog, self).__init__(**kwargs) - self.bind(_action_buttons=self._update_action_buttons, - auto_dismiss=lambda *x: setattr(self.shadow, 'on_release', - self.shadow.dismiss if self.auto_dismiss else None)) - - def add_action_button(self, text, action=None): - """Add an :class:`FlatButton` to the right of the action area. - - :param icon: Unicode character for the icon - :type icon: str or None - :param action: Function set to trigger when on_release fires - :type action: function or None - """ - button = MDFlatButton(text=text, - size_hint=(None, None), - height=dp(36)) - if action: - button.bind(on_release=action) - button.text_color = self.theme_cls.primary_color - button.background_color = self.theme_cls.bg_light - self._action_buttons.append(button) - - def add_widget(self, widget): - if self._container: - if self.content: - raise PopupException( - 'Popup can have only one widget as content') - self.content = widget - else: - super(MDDialog, self).add_widget(widget) - - def open(self, *largs): - '''Show the view window from the :attr:`attach_to` widget. If set, it - will attach to the nearest window. If the widget is not attached to any - window, the view will attach to the global - :class:`~kivy.core.window.Window`. - ''' - if self._window is not None: - Logger.warning('ModalView: you can only open once.') - return self - # search window - self._window = self._search_window() - if not self._window: - Logger.warning('ModalView: cannot open view, no window found.') - return self - self._window.add_widget(self) - self._window.bind(on_resize=self._align_center, - on_keyboard=self._handle_keyboard) - self.center = self._window.center - self.bind(size=self._align_center) - a = Animation(_anim_alpha=1., d=self._anim_duration) - a.bind(on_complete=lambda *x: self.dispatch('on_open')) - a.start(self) - return self - - def dismiss(self, *largs, **kwargs): - '''Close the view if it is open. If you really want to close the - view, whatever the on_dismiss event returns, you can use the *force* - argument: - :: - - view = ModalView(...) - view.dismiss(force=True) - - When the view is dismissed, it will be faded out before being - removed from the parent. If you don't want animation, use:: - - view.dismiss(animation=False) - - ''' - if self._window is None: - return self - if self.dispatch('on_dismiss') is True: - if kwargs.get('force', False) is not True: - return self - if kwargs.get('animation', True): - Animation(_anim_alpha=0., d=self._anim_duration).start(self) - else: - self._anim_alpha = 0 - self._real_remove_widget() - return self - - def on_content(self, instance, value): - if self._container: - self._container.clear_widgets() - self._container.add_widget(value) - - def on__container(self, instance, value): - if value is None or self.content is None: - return - self._container.clear_widgets() - self._container.add_widget(self.content) - - def on_touch_down(self, touch): - if self.disabled and self.collide_point(*touch.pos): - return True - return super(MDDialog, self).on_touch_down(touch) - - def _update_action_buttons(self, *args): - self._action_area.clear_widgets() - for btn in self._action_buttons: - btn.ids._label.texture_update() - btn.width = btn.ids._label.texture_size[0] + dp(16) - self._action_area.add_widget(btn) diff --git a/src/kivymd/elevationbehavior.py b/src/kivymd/elevationbehavior.py deleted file mode 100644 index 19d7985d..00000000 --- a/src/kivymd/elevationbehavior.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.app import App -from kivy.lang import Builder -from kivy.properties import (ListProperty, ObjectProperty, NumericProperty) -from kivy.properties import AliasProperty -from kivy.metrics import dp - -Builder.load_string(''' - - canvas.before: - Color: - a: self._soft_shadow_a - Rectangle: - texture: self._soft_shadow_texture - size: self._soft_shadow_size - pos: self._soft_shadow_pos - Color: - a: self._hard_shadow_a - Rectangle: - texture: self._hard_shadow_texture - size: self._hard_shadow_size - pos: self._hard_shadow_pos - Color: - a: 1 - - - canvas.before: - Color: - a: self._soft_shadow_a - Rectangle: - texture: self._soft_shadow_texture - size: self._soft_shadow_size - pos: self._soft_shadow_pos - Color: - a: self._hard_shadow_a - Rectangle: - texture: self._hard_shadow_texture - size: self._hard_shadow_size - pos: self._hard_shadow_pos - Color: - a: 1 -''') - - -class ElevationBehavior(object): - _elevation = NumericProperty(1) - - def _get_elevation(self): - return self._elevation - - def _set_elevation(self, elevation): - try: - self._elevation = elevation - except: - self._elevation = 1 - - elevation = AliasProperty(_get_elevation, _set_elevation, - bind=('_elevation',)) - - _soft_shadow_texture = ObjectProperty() - _soft_shadow_size = ListProperty([0, 0]) - _soft_shadow_pos = ListProperty([0, 0]) - _soft_shadow_a = NumericProperty(0) - _hard_shadow_texture = ObjectProperty() - _hard_shadow_size = ListProperty([0, 0]) - _hard_shadow_pos = ListProperty([0, 0]) - _hard_shadow_a = NumericProperty(0) - - def __init__(self, **kwargs): - super(ElevationBehavior, self).__init__(**kwargs) - self.bind(elevation=self._update_shadow, - pos=self._update_shadow, - size=self._update_shadow) - - def _update_shadow(self, *args): - if self.elevation > 0: - ratio = self.width / (self.height if self.height != 0 else 1) - if ratio > -2 and ratio < 2: - self._shadow = App.get_running_app().theme_cls.quad_shadow - width = soft_width = self.width * 1.9 - height = soft_height = self.height * 1.9 - elif ratio <= -2: - self._shadow = App.get_running_app().theme_cls.rec_st_shadow - ratio = abs(ratio) - if ratio > 5: - ratio = ratio * 22 - else: - ratio = ratio * 11.5 - - width = soft_width = self.width * 1.9 - height = self.height + dp(ratio) - soft_height = self.height + dp(ratio) + dp(self.elevation) * .5 - else: - self._shadow = App.get_running_app().theme_cls.quad_shadow - width = soft_width = self.width * 1.8 - height = soft_height = self.height * 1.8 - # self._shadow = App.get_running_app().theme_cls.rec_shadow - # ratio = abs(ratio) - # if ratio > 5: - # ratio = ratio * 22 - # else: - # ratio = ratio * 11.5 - # - # width = self.width + dp(ratio) - # soft_width = self.width + dp(ratio) + dp(self.elevation) * .9 - # height = soft_height = self.height * 1.9 - - x = self.center_x - width / 2 - soft_x = self.center_x - soft_width / 2 - self._soft_shadow_size = (soft_width, soft_height) - self._hard_shadow_size = (width, height) - - y = self.center_y - soft_height / 2 - dp( - .1 * 1.5 ** self.elevation) - self._soft_shadow_pos = (soft_x, y) - self._soft_shadow_a = 0.1 * 1.1 ** self.elevation - self._soft_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation - 1)))] - - y = self.center_y - height / 2 - dp(.5 * 1.18 ** self.elevation) - self._hard_shadow_pos = (x, y) - self._hard_shadow_a = .4 * .9 ** self.elevation - self._hard_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation)))] - - else: - self._soft_shadow_a = 0 - self._hard_shadow_a = 0 - - -class RoundElevationBehavior(object): - _elevation = NumericProperty(1) - - def _get_elevation(self): - return self._elevation - - def _set_elevation(self, elevation): - try: - self._elevation = elevation - except: - self._elevation = 1 - - elevation = AliasProperty(_get_elevation, _set_elevation, - bind=('_elevation',)) - - _soft_shadow_texture = ObjectProperty() - _soft_shadow_size = ListProperty([0, 0]) - _soft_shadow_pos = ListProperty([0, 0]) - _soft_shadow_a = NumericProperty(0) - _hard_shadow_texture = ObjectProperty() - _hard_shadow_size = ListProperty([0, 0]) - _hard_shadow_pos = ListProperty([0, 0]) - _hard_shadow_a = NumericProperty(0) - - def __init__(self, **kwargs): - super(RoundElevationBehavior, self).__init__(**kwargs) - self._shadow = App.get_running_app().theme_cls.round_shadow - self.bind(elevation=self._update_shadow, - pos=self._update_shadow, - size=self._update_shadow) - - def _update_shadow(self, *args): - if self.elevation > 0: - width = self.width * 2 - height = self.height * 2 - - x = self.center_x - width / 2 - self._soft_shadow_size = (width, height) - - self._hard_shadow_size = (width, height) - - y = self.center_y - height / 2 - dp(.1 * 1.5 ** self.elevation) - self._soft_shadow_pos = (x, y) - self._soft_shadow_a = 0.1 * 1.1 ** self.elevation - self._soft_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation)))] - - y = self.center_y - height / 2 - dp(.5 * 1.18 ** self.elevation) - self._hard_shadow_pos = (x, y) - self._hard_shadow_a = .4 * .9 ** self.elevation - self._hard_shadow_texture = self._shadow.textures[ - str(int(round(self.elevation - 1)))] - - else: - self._soft_shadow_a = 0 - self._hard_shadow_a = 0 diff --git a/src/kivymd/fonts/Material-Design-Iconic-Font.ttf b/src/kivymd/fonts/Material-Design-Iconic-Font.ttf deleted file mode 100644 index 5d489fdd1a04cf2169af5e4d29d2929432a73f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99212 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 Bf0O_K diff --git a/src/kivymd/fonts/Roboto-Bold.ttf b/src/kivymd/fonts/Roboto-Bold.ttf deleted file mode 100644 index 91ec21227866ca9d1cf77ec13660b7b85ec900dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163448 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 diff --git a/src/kivymd/fonts/Roboto-Italic.ttf b/src/kivymd/fonts/Roboto-Italic.ttf deleted file mode 100644 index 2041cbc002be810c50cc6a69e4e02b39f3457318..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132440 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 diff --git a/src/kivymd/fonts/Roboto-LightItalic.ttf b/src/kivymd/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index a85444f2ecec38a4df2efd9f09b8055169909a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 133172 zcmeEucYsty)^CM-yL$q|BxZ)mu_x!5?#VgloO6ynIp+*R6c7;+5fK3q5tUV!MMXqJ zL}f9t21IlfF|mq)>F#&x&J4@?cHj5?@&4R_I=64%x^=5go%1`V&Z)i#BZPF&IHIT` zJ|;F!%Rx(uaQhATHX%MEJ$u6kDUT!E;fK(cm*TT?qwF0m|BMLz2_Y^lJ=@dgxn$=s zgm44YugHr@El^zVO-D$7Jwp7I>ekBk`^|R_A!O1554l<2GEmq0!;UC~JWnHR9MMo) zS@YZGh+4RpJx|sEU#y4}XFz-QaBknw+TCy5|M?qmeik9!(=Bb)l^3UthY@nDKuA*4 zTG`*uW#CA-o&fc&6_u^EjxTp+ARNy@|E{&Sb#-5kuP;D2`74ARIK;*Z<(bHbO3GJ; z{ERdt@C8Drf6((_$G47r{^P> z&YOJ$^cXTi8xa48>lDr@mx=9~J5m{4J{s?ZS~25`!*rmys2hk5c$E=p^?x3dJSp zB$+}Aa*ukN=AuTf8KvM^^a2zA8W%=3dIkK8I%zyjZmI}5(s50 zejHig4eG-jLCIV$YUfrW8QqKyi>*--_qqBh?hTa48=_&}3MF#gQ0n2l0L}AjP$Dry z)m%C<<-UjSZBU}l5v|2q&BGE6L4@`DGa_2Nq3|EA5Ic*e4cA-(O0O@ln z$OFHIg7I6b8}$9f&!TUT6PJoSxN4}Mul|B7LwRIB@Z(qHLDryrxYkHtMIHP#w3WWC zK2KjzAAsY}WG4#3FCja!Q{B%Opx)pdFi>5@;sF@a_kH~N6XU-8>k`GWllwJ~uKHy5!H|Ps!Exw7K#NVo)B|FeJ zbPYO3HzG^^Ao_&=3cW4TMUT*(>Mz7*>PI+JqzC+S;r5{fZaZ=o?L;Qr2GqfIp%ktZ zg>rT3ulX9}i%-M+MZmn;BO{`PEcgN7a|!YkC!u_?KZ?O`qCm1u?ap_jF|G6v*#aFzy5D-J(y_ z2f4?PJIH1#KcapazVG1QMA`gS6vO+W>*7EZFD^#$B5l+sngKmHhoYf9h1e8Ta%a^y zK*pnCT){LQ`Ew)cExby75M;`kt3xu-7k{on{R)2^1qtWy9n5z<%xwYJ1J_;AoX7{s zL@}TP-=Zr16BG>i5)9)B6&1ogk?L;+ne{@MqQmOHh@OXgN((vwEYjzr`5pcGbk74SqjAn=GqQQ7|i!BC~v^?gSa12EY}P= zm5icjJB(!pCDAY8cph{u82O3P(A&Hd>J)#3;$ZCF;(x%i9z)*z1vJ3zM^&QN&?CGB z%#|m)&ZVKFyeAg%UqT;u11_;PY>^*73A_h+;QK+ZCgHnDK-+G0D-Bjxf{a*;RwG-{ zGbm5wf{yVLsN;^#({Is1@jCToQKI?{@%<=G)CCyuF337X#rzz4m{Xxin9Fji2J8oG zw|pc=09(Pj0G1-)H6qUN`5^$_ccEwkx|^VbA~D)XH>ziGGkOlnE?l907`LdOAtmT} zQi1l8MD;@;8-rY<`X*VA_R~!uZybse??O+ILR1cA1)Wy^09epO(?He%Pej!qm-&E= zFQV7zeiX|1#9cx^azCR{{&)0-=qYpYHUseCY`J;9=4)Jg5$0Yu!guIVz$xZchv<4+Y zUry5v=r%rue&<5ehd2l1##Mmc)gw203CdYG-+@ZFmysKO59a$h#B-7G{buCGzXR7^ zg|Z2B+*vp#aSX30*a0ojVFk#N8yXT3w3V|{|Cw6>^RKDCPQL+p`3AiSMGJ}r6fu+% zDCtnvLa~9;NH<_x=xZN&U;PstDI9-+qZ1T+DA7N(5=bi$L%T~X`nE*CSfo=K-wa_n6Czl7G zjR1oy0k_LR1{(pl%0ORg;amfXHeg->@`2}cvcl{s;Cu_SaRLT2TMw8B&rfBAYXZCn zn+bMHSFpp(7XO>VY_njOnQdMw%r4(u0QUr&4A1NTmjd>f+2rLS*kfjM|5IUh7;Ny} z1%n;ByWFwA%m&|G!1glxyIcg@3-(tS6MG&T+g(RtT=2aAcx3*_4=}H6%&brU!;$$c zz<>S!cm#ij`4o(AFrJl5$JI;6Kw_refL~K9*tw_)RnzT&;o$oS_7wad=7TUFi1{Ro zNA+=bB&Cbzc!nvWS5e z&nM9GF~hfhLv|0#+PO6yn75wp9L&s<5|K|hNrAZ zM9>b?n-4&TZvY;Sq3wWS>v;pD3u_ZA@Tr`H>)^u+`T_HF$8QIj{iDCmWJH)(@XeW= z3!jj{;UPUy`jQ7|yZ&v2_E(38wSR|6=`MzCK{Zl0Sc*U8CTu zF})Dh2n?fOoxprGR%cn3|9E8MW!HuE6|B4HHlh7drsK^1vwjI{j3un%lhi+o-a(_# z&ggRAm;1#tzZZPfW&cZJfnqc`m}l@qpzfj?6a}{8#Xa z1-}(|&*mC@@?61>2EX@@xc&eA{C~jpWq$mpBjY8rPjIvW{Ql*S`1-#-UtUN3Pscyv z>e9MvdHwaDj?1$5e;xb5#`U9>g3f^aGW`|g9&~}NGnhWGIa!{oGuMlQB z(ntD04Uhp)Lu3ea70}-yKC=p_F){*bf{cN#MkeatkSSUX)C`#dHAiMZEs(kTS7eDS zfLb9-pw`F=s134K|AK6h4NyB|3)CLj0d+w3>RU*P9Dq6^DNrZm2-F$q&&UNi0d+;r zK;4iFP~$P1`1@&@XMe1Q5RU-eDkk{?hx@&_7# zWIzLvT>T>oLIFU7Q6SI|6a+LB=np6i1p^I7AwVNgD9}h0rv4s9p>UwlC<15oAnK(Rm*QJnf)l!W4eCZhzPDJT(WDoRq{Kxrr$XgW#(nt@V*W&-^N zWuY{n*(e=o4$1(Ui!#;MQ69qy7Rlp<1BL zs19fgst4MN8r0X20yP3{Lrp;2Q8UmE)S~_zb)r_FT}T168?^!LLG9|Rs26nr?L(bF z`%xFr0id6uLDUU&2=xFRM!i5sP@nn=8b$p;$It-KaWn{Y0u8A@MU!Y4=oA_OI*mqw z&Y&^%CukOp1D!(?K-Zv2pli{T`eQVYrh%?QGeFm)S)dz$egqmc2Xqr!19UT53-lf| zul^g_g4O}uiq-?&hBg4b7j0BuM%&RQp!cE8KzE>ffZmU`s6RwI(N>@jplv{Rp?iTo zh_Kp#RofbK!}1AQ3i`)DuP3G@;40MLDC7tlx1gX;ItezY6tW9T8E2hbj% z2hqdochMoV7wF^Y5uk_BKA=yaN7a|m5wsuZljt#^N6`VGPoabAzoKL45YVU5<3OK5 zhk-r|^ddTro&fqMbOh*g=t-c@qoe9~&H_*4y8KCc=*VJ#Ii|8!SzoOTHUP9-9zKh;apF{7V^FZH6 zZvy=QT>$zadQ1H}x{Tfi`Zx3r(2vkXpdSN0i#|br1^Owv1oR4e7wBi`J@sqoDtaI2 z=ja2V*U*PRzd)DOXV91EZ$ST!J_7m``WWcf=o9s;=sNlo=r`yJ&>QG8px>ga>eJ{u z^f}P)(KVnypf7;_2=op*`&-vIp;-2nO<`d0li z`W<}-^fvk)=mPoys1p6CehI12O`vM@518? zfcoZu_LhM1)`0G|fa>;u=2Ad$CqQo(Ky5cbYY#waFFKxIEbV;P`u0HALWpl%4D zZ5W_z1fXjaplS@DX&j(v0-$FSpk@l7Wg4Jl2B2dWpkfZ7VIH7h0ia(Ipk4`}T^XQU z1@JHL)f3#Ev)+N8(JJhzoHg?!=9F5KrPoe26#kCH};Z$cc;u zkU-o5XjTQtSdSHeSyO;>jd%o*tO2hB9GbvuP&;0aHvnFC<0(9Yr_sxJE#Tt-XxKC$ z&nO^l3!Z}*|2*huGaAJ05KrNWgscXHxd&I_YTSsMa4oJwvv?y3CWml09>ATr3vZz{ zxD_Jd^|%>#5HVRvL`0XYAo|3B7!o~VOiW;eM#P+0fM+!isIvzUco$&JZot%s0cRdS zoCxA-Afw|jgOE3Z+1G&Cvw?o?0pxfBbomVE+m|4-Du_YrVF&Dpy>I}Iz}dJQo;-@j z@D}_qK8k<9x3QYQS{!&&NKTN~$m`@|@(+qBr5bc4wWITNJ>5bdrbp@X^mTfHUZn4F z4xA?!%cXNwTpKsQ&2ksG_qorwpLxvd@&=aJGTd^;@<+>mSpH^}YOQ6x%G%P})>>-q zW$kMnWF2B1W8G~%X1&k)G3&!Nyp4g4k&Ug5)W*Z6%$C@SY**Uq+nU;1+Pc~%*jCuq zI-L8C+ln5vxP=cTYKmpGXdqMGm zI#~6S>hHJ*IQ1;p-$7NSDgqr+UQ#})Jgt0E`G|6_@1Kq~zgq&BAXB zw-8!*7RnP)_Cnc(km?weC*dxkbk^W*r*}8EaX(73Vf;%4*!wh7g8c7prCM~3uD8M&bk2a7#(oY7+AQ>XVWCXmUO=Oge zk#RCXCL#9;_(ismtzyUDtk3G zMNd*QYL1Rl3&@ICqGQyGTEjZZ20W8zsV(4$J$0Z`>PVfaGkTG_QaAJxbpcP~6nGe? z!Lv96QG0jrCtjxt>I>0qKXifmQyG=h0Kl@h(K|GVw$Wg8k%pkZ(oh-(QG{^t7~Vtg z(+CRrKpIJ-Xf%zXu{4gxgU@i8CeTE%`CkGud_|MM%3p^JVKU(6w_wx1rzz+MnhFv7 zA7M3jlV;F%nu(M&3#n)}&7rw84^#;jTQr|`&;m>_#T;i!J82gni~%;pt7tdvp?$O$ z+hKdoinHcc1JX(XYn`w&XU3Uh7wpOza;s=R9pFTq7`tJ2&VsYV9@vwUa2kNg-q;8G zVn6Ip2k8)}$!XDHI>I?}PMkKk0?V+R)8SSEatGod&IAYJ5YC7*rlWL>j^j`q21qQ$ z;W&b`;cPiwPLH$W>~SPrC!qEQK(bAAGmgU1oIYnjAEo=13nFXL zSOG@>-RH7;suYbrFSHIHeY)4ZvrujQf@ zrB$F+r!}m#S!=h}VQn4l679X(H&*zqs9JG$#jiRhI$1iMI^#MQbW|(jR&HB)Rac^0 zrMpGiF|z{eTxGn*c$e{2XV| z^%3hU)<0OQY$P^5HVHOWHtjYCY>wKTvbk& zmf|+(cG>NwySaOU`)>Ca+^=~c4_l7{k1ZajJ&ip3J&$oh(Q;D?1~% zm3Pax%U_UR4=@j?3D_6#YhYa93qd|Xn}aR~qhOEVZNb+=)`Z%Jj)r~^W*$}&HXF7x z>`d4PVb{Y?MVLkuL~M(=9!VliB2ywqBM(Hr9eFd#Fv>3~Cu%A|#9gaO3do9i+t|o3@+?BW=;!(U${BZougo1?QiTa6(#Fvt^lQNRFBwa~% zOKwQslS2OEKkXEg6#JB*l&qA7l=7xKT#|Ea*VAfOUaGgQZ>b-zf4jl3p`zhrqogsfac|@G zCa-E-K3Zl?am@1?SA4QlVNs*_hQYaLIidn@L#cstR#c{#g~ek3RRnCn^Bu> zn@3wvTU=XKTUlFETW{NB+s3w?ZTs7fwViA`*Y;l9)wb{2es34G>$h9ByRvGqZT{pW_-J0D--L~Bx-9g=P z-C5mb-A&!S-ILuLyLWc)?>^Rjvin^3d)-&Nzw7?JN7SR=W7*@DB2q?UnZW^oI2&_2%_f^(uN#_UZJQ_DTDE z`oj8>`ttg!`V@VGeY1UA`gZpn>O0W zoBDhEC;K<{@9f{-f2{vx|GED6`mgqX*Z=!~Xh46!a=>LkHV`#1KCpgZ$H2aUqXQ=f z&JJ7}xH4!x=r$NI7&DkLSTfi!*gZHtxPI`3!83yw2R|9SK6q=04CxG+4oQc6hQfxD zhVq80h7?1CL$gC$hIS7f8ah67YUsky<)JT!ZVsu2lZNw#tA-WBgTu4KTZVTJ9~wSB zd}{c@@a5qzhi?w6MnoezBSs^ZBhnF%5!p!CNZd%;NZv@75WXs6zkwYWL zM^25L8@V`gdF1NI^^senWK?I=bW}R(Ga5F!XY|16GovR)PmjJm`qAjM(Ho;bjV_Ey z#&pL_#;nJj#=OP?#v;ZN#xlkV#%jh|#=6H|7&|p~ZtT6Wt7F&4ZjPzOMdSM8mg6qt zvhk?#wDF?xy7A8O(ec^wjpIAV_m3YNe_{O0_{H&0#;=dxnjjPU6P6P$6S9e@iKL0F ziL!~NiQb9HiH#FGC-zSqn|NX3)Wo@o_a?4RT%Wi#NhWnBO($(9T_$CdQIlztd6QL> zipjyr*~u-FyC)A#9-llld13PM z-HeO5H9 zKWjPbGAo;nnoXN6nys7doE@E=pWQioX!iK*so4v&muJ76y*aCz)0{J!vz_yp3!00Y z%bF{jYntnwo1EJ?w{vd)+_AZnbLZyXo4Y#q-Q4eML~HcdG_2`gGreZ>nq6xSta)b5 zOKZ-r`C!epH9xFbSSwj;xYl~D+uDG&F>5o{7OdUA_R`v$^Sbjv^ELC`^V9R2=XcE? zn15#erTO#oH`eK_ldUURSF^5t-LUX)4@5{Walxck1ltcG){QW=Gm!fl3lulTWXe`m zUWmyGFs$SisyA`?>}J&)IDQmd69N%$#GT`hLIfN>!LD9A13NhcEur{QR(!>FP~dww zvmyIc?`^Hya!VJBcB^jcVax4x_hQ$3>$iWR_ucMa^i;oXsqe$C531h9J5_afXDNQZ z0`E}?r9u^73g7(#+o9nPL$=V1vlMNBNI69JJcy$Qm50%A>?^jUVmtPQRELN~mc$s& zAs&P6Z>-4b-<}yU zP!UY9G_f%lKgFW<Fm~1xf28?TPha5z~4w#1b8@pQRa-yJ$@zmh@Bu9>O2~T&r z56c7NR<`ICX6~4-bSrOY3(DQrEEkI+$~pssd`j~&>{X| zyj6&|4aXU|g-d;MLZ#H)F*CQ&GkLVw8xyC*+AzPOv}p52m2dLCvVn`mUu>3!x*B8b zU$vnqVW>XeUKxdrodT@!yDRN1Vls+-qUsYIIXh`$e6&@yk#}&6vtxvZDRzj=U6k{a zToi5-^m0inaY1;o%&3-c1uY4f6?8$NawR{ADj@>}vct=bb+9JnHFU5gH5PktGWm>- zPh#cJeMPG}5B4XoqMAC?*f%H4E~z=*afOC9Nhm+}`pbvbdu644qEf5AoiL0)_{_8W zH~FQ?w;z4!)QN2N4E40inTSN?f|l#>V#hE(9A?3TI?63Mkr;o!(mMejQM@W;v^FEe zMTgT|0T0QBhcv}G>PWOnWW~AHUp%bW8Ofl1tG%+R2Mw3x2z!wC+n#W9WLDS6KvjXsT{`Ls!bzJ zU8)a)v6t$vQHwlFL0dRi?zn(tHVk_f@raDzBZjK%ocyDul^r7@ceqAiXTjH;F6e><U8f&08MV?Fc|W!fA$wKBv(w7K=^g1(C6eoNzaDiK|E~ zHe;u)Ibm>0Dw20>7%K9iB&ck7eslD#q#f%A3qjcf%7)f%j@I*1wAE+&5aN>IMNGvMV8z9hK+nyPjcUNGj(xAZ;>Jd%Rl zkieMi5pu?IfHbD54767+!W+|LFeeW#tX)a0+-nLVBoedm>WI{lvQX_V?ac85)wvrh zy)+~Vb-gl`2l>2`n7G$=3`K`GrMVH}S3Ht{EB5w9Vj`>AP>``@w$ESX4}F8ZFV{H} z{x!(8!Vk!N05bmX$68`|ID_70bHVC(Vtk-8X0kC}B3>O{6&2rC8or`iJ9m6vNx}MZ zH;KqUt3IH;K~p1V=5R&veU1K-UXg85Yi#m(WvE0f&FG39qpOJnESVx2Q(XyhP49@t z#rHJ@5)#yKPeDXuPPmctGrd*2+kyxQZP`&0)0yoF)w27NlUn2L2qdNn*jU7^0vXX1 zG=y1JCfN`mw=odYz>oC*7TFh}Y?jdA*@er5ZVtom)~Yt+_GqeHaG-vI9>Z>tuec6q z12Q^hm?=jXUPM)4z=nXD3`Yf~h{QKelGhBCk8B9pkWjTg*H%L_Y2-;o(YkVP++iJA z6Pq_#}@SfA)~+PZ7sd$`>;;beQ&e73cQ zM$+)(O$oh45f0iCJ>BrismIO_s$TW)ZOG8omKcP$y>-iIng}dGz$}J`& zd-}10%I7xb5aO0n*E=3L(f0OpJ6c1P_hZ|LB3W(xeZyIV#C2^>h?;INvy8e8%!v51H`SI})3A~-L89t@=fpX~a^ zcki#WvdgJx3aVV2V=WKunQA5x>Dq-BhGtKd z2S~*Ffi)$$JKvpfOY}DE5sU^xdHb{1tJGE0@Q4HPw|R zfT|_-ZA%QFYfFGGL(bSjeG4~nfq*}{-@}hokS^LpA5g0q_TzH+-Vwf;rVqeegB60g zPey;Ir@3%8_Xb!DqY+;s?M6xqJ=$PG)~hZJ;E@VE1leMc>2|!A-lC6zB#7Zw5EIJE z=L?q%s9W*Ey9SWf3vE)~Zes1q(C73e`2CU~Q_w1wQ$OY8D)O`5!kjVLjy-!-GnK08 zDc0^`^)0#?`0NP#Mi7I_e~Xr2V?dejSR0%zw(*Pia7mAJ6N&V_G6F+tQhfnB6WZ>{ zNgvFx6N_b;HU6>5dM{HiJ3BW*eQfO9@RpF8{B%eAgsie)zp{82g6(6<198?|g)az5 z<#bwne^ZHzd^TTo%oY&Q%gzQ27#Jynl2k#WC-{x91Em-G$ZQmKWYPfc2QyUIm{}(b z;KG4P6hwgos|X&7k&HPkP|;7Q$QklFkkS=U$iM?L!zQ|4(?OnG-W%tZD6^s#QEA0~ z0V!TayhNhq7Ln69l9<{PI49x_eZ2yT6XZ^&5`D2v%ILF${qO$izMjlg2E1+R$Wy%q zhtiERPnJ!e-&*dm%BX1i(1q`3r{CCG>T&xtuSqq{eVzR)(t~v;t>c_R>#`%gZHOp% zbf6`}gJ5&-csIucnH2y=d{JeEbLh-iS1x#a0p7|}_Sp$w3!M|n>gwDY&OUvgBAk%O z-n}ngYOOl^+{68Gpe@oYFDHzXCyu`PS=Z3FmyV6c1H23$IQz-_W^u`hL5^TLlgd1Z z#KahkYEo588}L*86ktvkU=I8i68H%|48S}<52YKFlON7dgC4wkK-o%sH{%_u2L9;p z8IXWo1(KJjR&%3ppAl#!?0E1s-~|X;0wOKUFWWo^eo2ZP5|wyo;REeK8X}Lx$^dz` z%ot#2-P6_oXuxGjvyCwtV(Yku2-Pke9y3xM3DzvFEmHLke-snfqV-i_by=Z?deKGA z0S&tw{V+M9JdB;vdeWjA5*$eb#O4*}_!1#K z4`i3|jICi;FbgYiOjvv^GHY?&1w5LbKR4p3Yq)CQg19?v==rThuOQ$C}-S)^Ck2xkr)gtf6JLLYCFK=8=l( zhkK%EzxdG3o@XaBbXD)KF_S__$h@-VV4Q_LVI1fUj8O0r-V%G(wDks~Q?y_-JrY zIoL_uEjYul%ld218$KDsbzj(V@h|=wJwEiL zPS)7t^%eJ&IcW@vjl=2^(nd;ywfLh8xaz=AG$CP%onZ>K4T-aju^Jlo z={*Um1Efs3mtlB7(*w0>lXXc(%KLT5YuG(!ASJmg11$fdPIv>JY~o*CinDP{&6qv^ zH$gUL^6xB}=pm7jM`UWYQ_}X{7%}gaTGKHQT>eN;sAN#&lr@kPHPe8n5WcYg-K-jOi5&GUbwR%CgB|qRV5GP z!F*c9G$zJZ$9m|kj;UT(9;3()cQ(K{sC92s_E5G9hU+bY&O8l)HZkx`@XA1}81Vh1 zviN538 zIG|~nHk?zmqdQ6GAmD+t{ZA9I;Biho-AwtF4+Z$Mm7J8Niz4Lh0o1*bw6Y4}apc%mBQt~1B z9oiB6aCoSJ9WhkB+>iGZJ<`hSDBmFOE1g-Jv+4)PO}GP|$HOqlm4*HKw5Yb0webu0 zG120GV%ONj5UrY{v)soROcR0M@?58na~a43MFL_=We`|e)FEHv<R54d0uTK3V9Z zkuMQx5tUuAq9W7E`9#Y~neO_pYs!167vH72?tO=hza4+j=UKuEz1T)p&x zOh-(-izhRcKl!)#Yv&TnfDG^Nv4)YoJk`fD$=?FT;0|l`&w)W^i(Z@H+XLeG3bBKK zA|?@2!NVtVdRfCRFuiUp#j7|Y+QhaUYxQVvuyFX5(3ZR~-Hw$x1KYDYw&$5^@hdWC zpX<(Ssh-Fx5Xz9ipa1umV*FH2qgV;rt2WL)~`heHC<7Aa<)0rKGl!Vl+&%!}< zDei;%(xR&KYHlSH`X) zJw(GGsLGI(Z2NPSTiw|Q%PGxYceFUsBysy-IwgiuxlLeMB~{b##+ewrGHkdy0_F>{ zMl>AWry+RSc5+`KstC1|}Jop}6+{u2h80VSguHc{5AOl4-W+%T!c@V5SM zkJAsTW|PN@A%mhNsTNBdBJ+LbsurAtvFfW*VP9w_WKyE<@L#^<973F$tv(?V!4!~Z z=>x&IlRMKcGZ(m^)z3U=N8udoj;@sjAatZM*9Zwof z%Yj+TYUvvZa$_>>LWsFvk_Y~+vV%=rQC%yWIEWzwpI#Gmj;;8a!3DTol4ke_@Ed5G zQPL1p&=p~z(c9ZA(s0R)3TrNmHyiH-b)!@6DKZO8B3n15D#g@S7IFvu3daU=c(SJn+-~f9cDk-nNc5yrxuY>&^w?K&gXRZ097klkg63 zzv_l64nGfml!4%j2$m8v9{VySG-C;x<*+wyx}f2e(UEB3Z>D49YV4KhXC;2imUs$5 z2X9+DS1#ywEV$wzd)ks}kp{L3NO9x-j00`FScJjW17lAn%Zohu6?(tqp926b`saB4 zp7=hj)puwZzyFZ(2JV?AR&%Nb5nAx+#M@QA%B_p{2SXz#;eNnrU*O=={aC9XPKCBX zf<(=L)39d7i-Abvf5Y~>X21aF+eSav?N^rUr)if{sR%9Xi#F2e>+2P1x#vWOb(cr4 z81CyAt?5ccD;DU~pG!bm-nE=~#WkfNROv^~ z2MOUeX>7S%xta@FmIZj{1M`Z-|E^cK#NH;OwDI2x13dM4j}-ZTkOgR;Fbw73?P9Q& z5^#%2+hX<+a!E@d@z3mI`ig=LFZHxPSZ<@q=@e{uu_vjoINV-K+$Yfw?<^?Y+7hkB zY3N6E6_jpkj)HyhE$4O?QvlGHYHV9xyB`45ExERDG72Z{7|ops)AmH{;a-ZZ?Gd1d0}37Fqez#mSuYb`Hm03-lWxyrj|bHThogng+QG9k?&Caa_71bai0Gn60jm+#LlX4a;;e>B*= zy0QQi6I;krJ(a(dRDfbe7uB~y{(zu7RRyO7aw7C?3FDcAVIaT?Ll;Z7X80$plxx@r zWz>(SmGAblYgaAw)kQy1pU{%RP-H;FP$VlzR*@ZVQEW9+16>PshpyQ~uNi4c2c*x; z+4{SbNK-QyW&qL$W4D^hqF4Y8Q=d3jVp!57fJQw74M9K1Ux9Cia3Td40vH7ALnbjk zM#kh7N2h@1qG;Xm-V;6cX0e&&vQ^H8^j!(Ik1UocO}L=LZi&8T7~bt5w59%rJ^(To z3MUM9mV?)e$#vE?lMErY#I6~$%mIX!$cG~5_#&6!{_;ScOX*r4n>bbJ&-GIKs6ubg zvUHh9HuX>Pwbokc5>uU+(v=J;Vb{$5 zH2*Bn6(g@CU;h|)Gc7%jgodQdo)kNboihe9abUL046dfa`192_$RH2zd4N6(8xNKY zu2{sn2pbc84e&c&AL@PBPqCqkbhVcW9~>H%=Ay;-ozj2Fn@?ALQ>FB<3iGzYn5R{G z1be2{%E&uac$L5t$XS4%1hKV&!=f8^_tF3s_2h@>k z+5QvVYjTn)iEZDKL7r76$eMFygshfj$*Jz`GeX-P087`PZQ#BGTNyC_9$y$$zE$~I z??HOc?K5zV%?m&o|1HFgVNKw$>W^yzInHy$>*|_C&bV$&rC-;Fja5~3UG2Z+meRn5 zSL^C&(Css{C?s^@F@SW|9{k!A(f6V4J8J?etO+10QNB$TgUzO|sy1%H7gRq^lNtQ1 z^6$z|@mW;>{Csc)+z$62P{q?5a6dS^tl!N0x?=~zVHRK%Z_OxMOv5wlB22tYv{zcL z^vQ_yF-&=9ft zxUnh2IJtTt_FCJ6?#3~hMed)6byugG2z{_q-Nf6M)+7K|YihAht?H)eBpXk^s)=Na zg5g)82rMnjokKooshi6kgMj!-O!zgkTMVsMcDJ|(T1j|INF1kxS*N!|7;0ETkCOtm z2B-8ay;TpZ{_OGE{MF6}T~|eC7JGaV+EbTll4@Suzd7Rz|DtGT+Q85EURB+{w65*N z`?wFN5&Rl;G49H|WV?T+TS1cr)Z#vncxQGcx+cYhTC8&OmRtEH`&vmFBwksaNiHcd zVeqAw%o?)x))KN1HBu2su!*Ce#VTiOLoAKVb|=xpWdRtQI4ymLouYEVs1WsS)%~~! za8vL%KyB>UjEJO*`SCxs9Ua1b1e^iLLkRTP?Z5N2HeeJz?>GRkR#R)yPvBizz94H$ zzW(CI9_H>Z?fv;zkNzZW8e&^zWm{pp*cGAFOjnaOnn3hC)`k(y%w-;>1+u-F0CyWl}Aq7ESN-4PQA z|KfY3THe0oUHt`_eu>n_Mvr$muK%=DJF)kn%G}8u2MCj_k`;z0v}Jl}IN~&YGNbx7 zc}*Z`sK+`XNtyQ8r~%s+@9l?3W@!C}EN~gzA(B}(7@_*40c4TD`z@~V55T+g?BMss zi)aOVV;tokm~q?@x&~=q2r3whS+*N?(ufyVCt$c1olK6Z^UrnGJ|Fu`;-8#NSLoJe z%#=>$z0z9wbnL51uew<3=u{+6mMu(ZJ67CR+w$VQ6*}xwO~Pz%O^VM{Ts9#oNxMsS z6`!o?J)i$X*1?Dr2*bxdQFf^KbWQu|oC8^;tK^x@;29Kbd#SGE=}kqHNaJgIrh$DZ z6);W{^vFnvQ@~0^_y@KO7T)Y1L>(%L;l0W;xKdZuY>&4C4IB(qDRl8Y_NrE0T(3Gm zL#~jwm3oEe3sfg?Ou_j=^1Z+p0y_Grpra5CG6NUV08AvA?Vmf)H{GYYN$G-;o+YkKU}6zo9p@e=cd=frWgJp8Sr%9v z=cDhpsi0zgp)*KV+wSW4zI-1D7lhTs$CX7m>+9ON2PIcs(=ybS*vQiTyi)>QtxdHx z^tHrRvQ&T1q#!q2u)v65j<=&(z&|Z!F&X0d2s>eHr4C`#cX4@OD}^*MiOmMY|Sq@bRV2mYQ?o|I{0!! z^`SMjVa8h8u`L_ntmfcaI3wlpy?~D-wsmcMMe@d$2uwV)J7c`ELTur!rn$}XD)0I{ z*bZVHlH=2zvFD!QQWXQdI)X52kK*YXhOW|x| zT>v4$^&9p*3wr+sIYxbeFOHC51}_jo4*;M9L~}Xb#C8lVt|vvt4nDAtNN^NER>?*Y zb?=Dv$_looG^%DOc&!E}G52#!X)|b$1m!gch86{y@ZKvmRcAw+oh(Nkvtqq?s&DU0 zUi9+x4mOvi`NWmVjd7S=gqI~IF)5CIsm_!ZW`w#O#5#7t9@ZWfkOhHU zd=uJ6>*#|>iaWKwMPm58dttg3CvRr1uUy4bo)^ng zk38-WA1LKTMxN1*d&tG=7Z3c)1RmOOX97!?C*HewZ2Lhr@x#T-6TeCI7>&ooJg6|- zG0ewVccrUesFk}-n6<8bg1uXEDp!K>D#s8f_aIvx49*=!AMxq5f6*Tib|W+@yL8EV zKD`p;EFG9P4FPm%9jYsrUGjXl40-nbzwk-VBfV$JrT2&(cQ!PGz zTe}X%Ru8|uejD}=S+f=v_m4^Kq@v|mDs%a4$X4Yg9UN^U_qOLGiD8*Fdi4^&jQU{j z!bm%gx`!v*+{F9H{TbMJm3Kh6ZA2_CObIHBgq4N4JX7YGlN4zV&N)WCWCOVj&tkvz z^c4^s_LPe5+Nic{7lic3GV{QB$xpF~4RqwFfmCK0U8~<9@lUVv_b!T+a>U9b*eWcF zQh8pJ%)cVuiPV$Tt|7K|(K37Z8MSA)O$L{Rb#48nHs02HI3^OyvjfaAHuKMv*$27X zu2@wV9m3QLTL$I@+WXt<>p28S9sOY6jNsS9`=381IZH8VW7uADa=YrMcK#=<`exDZ zzagw+gM^p@_$!u6i&k*VglMI(;Kp^09H(LA9^(TMj9A_2z7usO!H+bhOgopsBAW|R z&N^miCI;9-2rH;Ch|=3az8K{#{xa}wEdcdH{8KFFX=A{aU<`#QaV;*Z+tcK! zrCqx9Wa~90kpNf>JXYIwbT|tC4)0z^Pm%##L~S4+50VL1!;&m+pgcx=?DQ>-v|w3b zXYWqlwDZE+##Z`vY$pm#jrv(tGQ3v?!CqQJ~2E}aA@RHMo|frhL7r3VgKS6}+}% ztiL=r)IkitYIltFljVg!%XBPB;-T#14=QM?w6x4YI?IHKWCl3SA|2Lav$hUhBv6~-fu27Fw}R@2THaz(JihV9B=1=|>i zCKtZ&Ri0LTyo1Z3Df-It1QMdJJexrd-L}NPw&EGp5P!5z`DvYUFTRKRK${re4pdDq z(6`unTCRcNzp(}uYrsop9#DOs4{M(J7*#K}$WvWY)jfw5xGWhG*rj=@M^syqaEt0* zXoJGL-4648{Ab|1`w4kh=B0r5&VIrG9*&S!fUq_QI1h@8jWJwg`+pr|Qpe>zR(BHl zWgBI)Z7-WIwGhGMF1YD|⪼!+`pB8ILOqDAf+mbV8|B%!V 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 diff --git a/src/kivymd/fonts/Roboto-MediumItalic.ttf b/src/kivymd/fonts/Roboto-MediumItalic.ttf deleted file mode 100644 index b82820554134a817749ff81922c5a4c0082abf35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134312 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

VTi)^qwc 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 diff --git a/src/kivymd/fonts/Roboto-ThinItalic.ttf b/src/kivymd/fonts/Roboto-ThinItalic.ttf deleted file mode 100644 index b79cb26da0377370ab3e41bb7a5a62943187124f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132860 zcmeFZcYIYv`aeE%&bcKw$xTm4@44yiCg-M?o8Eixz4zXG2%#ggh=>XZ2ndLXh=_=Y zEV7EMBC-}xEQ>56Vhg$VexEr>5Z&F+ety5#_xs-l<~`@!(`KG|=KVbL%$$QTLP(58 z5sgY?BBP?!UDRC>ZrKmN#>S+kWGsKmeGK;RA++IaOh%U6ZntGHqNo!HF(D}#9^S`{ zo!k+^wQzoEc4Sg+^UdxQgmhOS#Jg6}RMxuQWz(|=Eo+2_T&-#BtKPb{brd0w{RkV{ z)mD{N{`z)U6uqIHF>I5BteVT3s_t}_njsu@5z2R^wWXu;`BPdY2*>Y1$eux@u8>ZzyS%4F zE9gh0CWIdlI&(({>VVL@2fp}z{*K}UHFIGHqL3P-g+I7P(5TdaXWpB?GpDU)&fRJ8 zAjudn@(bYe$Phh>cz-xf!#>S~qd7Q&cw2ZOA}=$48J0jaB>L{2C?>+d=LJ$rq9vq$x;6 zkj_DJhO_}UARXMGdW{jF9Htm`K+e*Q=mkM2if8t#jxonj9#02N@GMXs(*1u$`{AIUY;b`(l~h1{qS)B^kM^lPY-cN6WPUsHVu z={ZP0Q?n=pZ$ysNtg4b%iKbv%$b_PLrdstY?-kg70>$A~NE^z0o9@FN{CqS-x1o3F zUNp?GXog>ox@dFsAx$9#V~NbD3#b!PFP=l6K{0Hs>*_TTlib(G4i)MczhK$?Jf2S4Ub*6)I$QATh{)5YCapbzbyt&^KsD zW)e+O?x+H;d7r)tI<^NbhwYykXVA$gB%^Pm^^7TMhdR{rWT>CthB}!}RLTURe7*xp z;+;hocv@&eSf~1nunuMOS#%7Zo5S2d>AY6ei~QZHz06*a_Y5lFb*PRrU!ycATMVxa zCGxZ|B``zD0trgyJEK~D97+ehOo#iG3;fX#vq^Oi${GyijG;52tl_FHe5^W5|AbuO zw=nt!v_ZV;4c>NW4^kIM^g-0ddlqC6i^3TLw34rnLioBU1c;-Jw-3cIHjtcAI6nif zVY$8?3j107msQ94FE88!?h^v~Jj1_?rs4b${yj9zI}iQfIn~RIf$A0h2WTDd6DY49 z3IKfw5bB^I{uQ_%gEZ-jsxP@dSc_!LQS>7HHX7vi<3OK&fP40%`Um&E1pSEyneRpQ z(6&{O?4YeZA%#QQ0O@_MykDXW=np@V_NL3AjIoe^0{MQBvksKcAAQZ-Mr}e9l*K!V zLIvNVX#OM$Ed&OxhHWR-9>+c0w#aPJ~wGr?}Tb9R{6;(w8dZRYGUvCWH#*yV@Ql1(NY@Vf-|nAnA-#MxtF zbN@|RtVa;B!%K_*BHN z`H%U64z(=m(n7u)wU9O^?eV|OiO)v-CZZ#x?KoWl-;MZB#D{x0=Yt+DQH|FA{ECN?iE}M=tT?QW=3K30E%hCE?7a#Bt{me?DA?#chsH zNqrXilyE9Zf?t4lNx%6BZRTA^JE=}|f)@w(2*>2aN8|cDoabo{TxxjDo z<;o0YfbyC0*MooeIP|5(vM-ej?8ocGS6%YIgktc~?m^!MKa>XFaf#O!o{0uIUI9Oq z_?8Q@|2-e_7yHx_&k-L9o+TlP__yS`2loaULVJY~S#tTqoB}=}$1x-aAD8%{q#cM{ z{+M&V8u4GjC+7TC&K+E{}sVO(Z15gubs^%efB?i<& zT7cR}8&C)7sO}?OqzkBr^Z@mdKA-{M9K>e~0F96#;4)+cXpEMrenlq87|;}%0Gc6F zKyzfK`UP1ab3jXE0ceFR0j-gh>Sq|?S_9f58$df`3uuq*R6ijHWDh7o4uFnG0_X(z zBXUNLfG)@h&=olYx*-?UJ>-sD0X>i#peJ$%^gMPyNE?T zfHLF@=!aN9eSstg{Zzmauf;}fx-YI zQ8-`}lB;f`XcPe$gCYTAQ50YtidOvt#iJO&1QZLHh~fZ~P`v6EN=6BQDJT&z6(s?t z0e*|pQ8Hi#N&(D7seoB1O?4AxqjbO=lmVEFG6C~Ymg?^)A7uj;pd7$LlnYpd@>JiT zVw4Y9f(igjQ6XR%DpGxo%26?31u6loM5TaLfM20%R0dds$^mOp1z;VjRDB5})GELR zR1MgOY5<#1t?CA9Ms*PfRG*=7Gzd6>h5#qgFyIs# zQGJT0(J0_@GzK_>#sOEL3DqZP7EJ=KL{osP&@|v`z>m=yv>b3PngLvgRsgO?v#P(L z4QM6cBWM-iMzk96QM5*N6>UOm0sn;70d7X?0UtvfR3D)&=n=rj(MG_n=uyBY&?eOt zv<>|U@JX~8@G0~d;M0H~qU~r4;12XS;7+s^@EP=k>N47ewgK)&PXg{iPXRuQo>qN; z_M+{8`_K-+{b(oPbLbh>`{)4L1$Yqc20VoJ06veNRs9tmMtcEYK>GlXp#6X^0$xH# z(Q|+=p#y-&&_TeL(IM4)=s0>F@D+3z@C14R@Ktm~brGFJF9N=Xjsl)SF9E)ej;Y>7 zr_sxRZ=mCVXV5EvZ=w^bchFh%D&Sk_B;Yyp8sMJ+|ANk=Q-E)y*8wk}(|~_LZ>TPy zchDI?xEk;xIt%z7dQ0^-x`fUF{uTWh@O^Y1@B{R=>O8uPE&zUr{sMRfy#x3WdRO&l zbQN6${2O`?@MCld@Dspu=u`Apz|YY8fY;CmfY;Gw)m!Lu^daCE=nCKs^bz2f=&I^0 z`U?FG@N4uj;5XvCh;1}4U91x!(R)Fj*93eXkfA~Qh{`Z0MrQ^Tl3s=&J zfjB!K3BZ1+f!$CCd!Y$-LJRDJ4%h`fum=WU2aJIKje++~p%mu8^Ond8xZMUg-43|i z0XWx+ZDLl9XQ$(xY-*x*$23o1rGKD?hOFW4FawW0gep=Zj}S4Mgo^c1Bb=} zcg6!}CIVL`14pI;H>Lw8W&#&x0|({;_vHiU6#~~41ILvDw;@VIsZ*Mi7G+48QkIkr zWlh;q_LLpvKsi#*loRDbxl-iBX1>h#&u?pbCTHFF` zH3L3n1ipKE@)P`3>45u1(;YmD=r_gCU3(VLLeQOFhX9T#l3D2O7cqR1C zMl^ui5KZwZHOd6IWdp9jmAD=^;A&ihmgBWl5Va3?;eOnKJMklQ6>dg7xE43!c1lQT zQvynd5>tAVK4n1ZQp+e~sG$*MPFYZ9z-EsFo3sGaYy*br1x|SixQF5ALzCWwvhsno z;dE$4P2ka|fH$6lo_rR1+gG5mO00!-usxPwPwa=oa0V{HHFy}0;0^d`dErZy`aP&CVjLJxCYniQDwtNLpP6CaWv(!v zGe7Yto{j~w2(cKoc*^3g#XYDiveL6Mva+(Whq`)O`9G-Z4yfzC-_^BXv93A~)wL4p zilMF;>N*c~#f%#RUJ+PT1WbVlH{fVU;gEtM1w!(NB!lDy31-Yxl=4UAH@F+5bQEmv zfU+E-%=;7{D0V5{R2)+5RP0b}Q#_`ahBK#BlSG&>VTM#y^K$62xuicR+dq zA>|8@VD4-lp893|m(Dk?eyMq*`AhX1me+F-x}JPJ>3YI-`4^to1HN#)?sc8I_6tJS zEt{}XdsA<%=v`3TNAY97 z2I_Vy^JbH~y$+K={!KK&lLLOL86Qjw9u?+h$T8uU@SO5-WjByYSW{j9+^awplkKqs;3XCKHE)QpH z7+Xe%(Piuydn^a;T1l@4{#r|~qu1jI9LeZ0`t&Y(H;%&5^d9mEK41 zCpL<4XWVcv!w1U*R*7z+oBwNB(0?t#M0yRr{H@>GFzAfJS*NfZw;&kJH$K7`9bZM6`!X0@|wN>RS3RkT%fMD(#}UfodLT|H7g zUAW?v-+GyqQ*vzYnrZ_`I;v*Z;3_XFmb84S$sl#OUqkpTi8n%J4FGC5^xW!h`H%k;46 zMbkTG8fGD8(`HxA3(bekPg~eo^jaLTxMQhrS!&sBxyo|CsIS=>#f%JY(zE=HUT!pHv4Tpw+*n}X{TZ5V7I~Uo_(}^r~M`S zUmSuQb~;>^I7)gYrzN)>tsMIuk2;w+O*&n04sz~xKI@|ElIk+*veo61E8o?}b)D;8 z*Z19!Tc%s9+ZMN@ZdcsJ?$PeO?&mxlJW4%Id+K{Sc;GtaP39a~~6*W}joejIZ2x(08-%4c3!wX3xtkWYMxl*;BGh zekOk9euw?}{{8+x1tbS-3OEsPGcZ1ITTn>Qm0-`{nc(vw{1DHO$dLAs$&gKCD-hb3EsK&h1=&ZftIE?wQ>Ay!^b@ zysdeM^RDL2A-RlBOLRa4cG)w$ItYWOuKHH|d~YUXQmYj@V(s|%@{th-R}Tt8EPtHGk7 zvEf|9#fB>l*BUJv3mZ2z9&5bUgqk#(mNnTmc{T+##WrO&l{Pgt^)^j5t!vuaw5RDv z)2XHlO;?(3G~H>MZx%M|H(NEkHv2V4Hm5chHrFAp- zzSaCo3)7_?s z&$e%B-`;+p{doH~9gZD79bp}b9l0Hq9jzUM9WxypJD%#;-*K$tOvlBJk2}8UxYvm~ zH9D7d+I4z%26e`EW_Ff#Hg@)QPIj*A+}gRP^GN5Z&I_GaI&XB|>74HpcIkInb-8x= zbwzfib`^Hjc6D}*cCG5#+_kgoP}hmBb6xLuUF*8l^-Fhj_r~t0y7zY<>ps(cvHRoh zZ@TaGpdO8$Wj%I1o;^W5u|1hRr9F*3y*-mX>w32K?CCkubE@Y;&y}7VJ$HKMdxgFF zy;i-hy?(usy{Wy0y|ulay`#OWdN=p(>^;Fy|1{hzHd+8 zk-k%X7y7RB-RQg1H{UPp*YB72C->*~SNFH~5BJaZZ|dLPf1v+(|JnXa{h#*V?Eh(i z8W0bd3^)vU4}=WF4`dIN4>S+-4@?hS9{7CV_Q2dAe^7VOV$gYz9h46y59SY654H~u z56%v57~C?reQ@vK;lbmBrw7juUK+eQ`1#47(2p49kb(hqH&vhwF#ihx>=eht~{m8s0X%YxuzM z(czQBXNTVzzC8Tt@Xg`7!*e6@k@%7Hk>Zj1k@k`Pk?D~&BU?sxjT|01IdXpF^2p~S zw@2ni`J>`d!%>@2_tAh+`DpTJ{%G}R`{?lK?C6%!U89FbPmZ1+y)=4t^sCXkqslSS znBkbsnEP13n0zdLEPbqatbVM0YDbM&pT?#O%bTiR}{yCXP>>owzjd>BP;6xk=Ha;iS!^`((gm^kn*E@nrpE|K#lC zrpfJ-2PThCo}Iij`RU}%$)BdEDe;ual*5$wlzb|Es(7k?s(WgDYR%M^sa;ctr%q0t zpSnEt`PA*HxoQ5i?zGLc_jJf~{B-to`E>Ji|Mc|qhUsn7d#8_1pPqha`s(yo(|4zp z%SFo#m)k6NUmmbLdU^Wt;^pLCS)dlCVQrQrg^4+ zW_o7B%(j`mGe>7m&%85pb>{OGRx65E46fL+;_QmMv(&8ati`PJEITWoO`gr49iH7j zdw%xr?A%KJN?q~~BB3s-IotqizG;YNBRyL^DU6w=-i87(wsprx*%w*m8QR{!$c&~P z0P%Xpa&AK3#?DaR8rwin2iAj^Q`Qg`<3Us$VcJ$tCN<&^$4b3D3}nv%8nV1b!Sj!;12}w$mBo)}w)&lq)_N=K_lsne?uTkC?VC|Qb zp9!(+djIvfc!U4?ABC!yv7SKr#X7%NapB9#r|}kLHQwSwX|VW7Wf@7V;+_xu_6`Nh z?J>+PdNKz55s0ZH%(_z&cUlI45-b&1&;ncd!PZ7h3HTP25$r=02iwZv3@Q8or_s$~ zmz>_vxam?)u|`t+`ZP||rSrr0T`R~|c6=BcTX*uFLu&M0}L z)KSA%-9C3ZCwjUm3FjuYWdOw;D{q%&aP~9=wN17Gx zqNXJfIYjwLv*oTLYMF>lC1=3N8tOi&a9uvDFJuMkk|-Y^I9VhXs5wOY`eubYixhXA z=`Lqxvwvfzk8f6^EXltiQ|go1;OCYT<>DNfDi2x7;Wfr^sB->sCyQ73dKSbJ4e$Y>a1T$gg9(YKOg))?aq8x< z0gtNYp0LdIHC~#c;OuH?KwwLCiL>%a6Mwg&v;dKYQ{K=rq0mHPbiguP<|q{EdB(c= zmBxG1w$9lFCEnp}nVyc(W&R$S@u8-Jif_`7*Y{k^|L~wwjE|*P$!xy7vpUy7;b`U^ zA;I?@9BopI>H-tH(_EMqx7^HB`ynGXG}g&2(a+j3iVNpr^Z`?jv$#Hpu)r3S83%Yv zJxpZ0^gF-o0-bMFx=?@N=a8PJ7s8VniD6xa7*^XG3EUZ0wp#2NRoJmQQ!{C_AuG&X z%u^TB#5MC$<-<_7oEEv83zasXGEa+UFrI|QZpB29JkbL>F*zyny zzNQAn7My+ag;}!=5Q#j>F&4)$ z3%o<6;7dZKTMnD83>VU!@xU*%w2op49QY3d0QdlQ4UPWS~?Mh%RF3xK@0y zjh9?(#F}QT4zQ7R$4!%G$RT2^N4*FdiZHMmrJ-bn_|Mb`3&((S;VyOL`Lc)D*5e_f zmHx)D@cxWyl8yqdgnJ2WvD7$-E)E*xyFi&JSa)!X;e-C0!>l2~VjlEpy0h+03>pYIEMD^`WchKJg7eZ4YU zh9-iQKe59@9eJ?V3VWRVupM+*J>C(Rg+tc1dOVrElrm=TDAR=aswS`Qv4FiG8$USb z4(|-im?9?#?*7&cK4s(CP#mqHX`axXl(w=lPK(t_8`xHuyQ;um zQzNCJk5!t`3`;q9HT6!!CJg0y2G`Cc=4|bb_N!i>oA$_bzf7r5+R7JXXaLU)gB|I= zej;ZLe#fkYFC@13`MS7uec4)KvxM%1)YYviI;>94=u`PQv-x&n^}w8lz_7AlLv^j3 zv1ba3911F2aQ?83xbm(L1N0?o&|r8n_3{8<}F#8Gtbt*z=!j z>%bQ%j!}mNijf`i9ckrjb1k*BEFc@boykLxp{OMx?oyYFJIAG&Y+T0&rwK~&8Q_V3rt)ffbxUI}iY@#Et znA~-)TX`;IcA!MhK+`mBMS1SphA2%<{pdm78J22&^_N*`MxbT-^uGL{-j>oB=j^pF zm+xt~@Z#pC5UhB^F}^lzG<(;03dU)pPbQ~4)*S~jgPAO_IfsZIt6^Kxy_xj+qkeSQ z{4oK&oVRAKo!8GoZ*>OQT0xy8&^HNzL7jfnBha%4wu)Xd(oi*Gwe|k6&*-WLWH$r_ zm4};(v`SV!SD62Jlee~pysS^oX87obzOYwPZRzW%F>JmX=G&^2C(Q zL%Efj_8Gm=3A3%qVlml@UD=k(goHO{hwAG`7k9`@H&*-lR&Okg?Jf-0H;Bxw3&>qp z?dM;;ZvJ}eNS>!h?r2)ZaE_~6&M<8m+n4L@k<*_L-<|H}mfj8RwgK8r33YTN9u?=Fyc=JDyP9dZ!n&_#4lx&Zv;U!OrSL7wiy`U(>>R)s$t0 zIUtxj)&U>bgK>cs8aiJA#lo77b@XYKO7)rw!z`2ww4V-IPoIYN*7}j~MGofE7Z_L4 z{(A88iVO?3Q+w4E`U1LHNNrX=8;A$IaUW4^3U%Nk^tbSi9S!$IL{(^#Zp?omq@9!J zFAHcFI)PP6$y6<3u?XgyJQwr|?uun}zM@b_-4e_{BBZwAoIvHYw{jXf2nFkr=I9nq zx5&GnpiKXox4=w6kAC3L<06rrPo%SZW`w7@x)xg!8QoPFsx8xwt6!0t(hc*5wS;5FtA4tOw@vfV!=Vd3ubK5it)s-xWmX0 zyf!^|ECFN2-=*Ooiz{r6kS4h6(^iT3wLyW2ZaP>?q~#TnT{jS8AHsSYZxk`cA$~#S zDIxAw>c%45j1{Lx20nRx`)Hx@GQK2x#mT|keaX71uM|wb`)IK%Z<$HS^uBj)Pfx$Q zvDle+f2Ep^Kwuf5(8Z+b=g2~OQyG7Xr_lpW~iM`;uegQvSw{P^?l-sl*( z`R;+CXnD`hv!DINA|p2^$`w;=ZfgLZcd^H=iIpwwM1NGrfNM;FYXrdZh>Vj!-GFjv zdaWY)??JRE953@%7*Q+t;1`rhyn}cy75|-{Ae;*C(ZRK~aIGP%K=MRLs%Op7&jJYv zFm1h{GZOoy4eLAwZpnSRL#C}RO|A(ItBy1iX%#HrQ>47sfj6W*+MA&*cFG@#R#xDo z)Q!EF+S(pfs}hy3@(y9Ayfu|!jah+O>S4v*VI_}NvzU5UQG?xbMl+Lo(ww0W+Q#=} z<@Ux~f$_qy0`V4e5%ia6?*d~GhUXmj#bFq;;G_~hlrgpDb&tH#lDE7f)Dmmhi+xjS zMjy*P0e7+9^;hod7`pNXeV_zMt#k~Hx6IAI_ zm%3hTxwyT8BK0QEI1JAqqh;U%0gP_J=vvd46oH+zgK&Pkf-V%!f7C?1L0wW*vb;mA zVhyYBoJke#O+1oMAxrv6G@Q23AwX5swDK)yeNe0||P^*_qj zXJJT4EGff@m-xR-fm{EIHDP(H>th}GnoeTBjK+!0Ii*i^giyY|6|1tlPd`$o@2o*v z1Q(5@2MqN!yCx{p1^DZ&(g-IVpZtL}k0;+wd2B^zmZx9+mhznG0?(2s&NtqPUOf)u z9W5JwC%i|tP!C?zLjA!9BsJm2`%D5mI6pYV-eOKZQWCs4P z6wZGM&VoG*E23|4eZvTjOJU8$?>!d!OZK2n>cEc5^3_?EVph{Ix-UCteN&tk@6f!c zX!l4$NbBQ;smsgRh_*+#F$|G0PYib^fdU>^GJ9-9Ec~y^AB*9k>#+uPBvYYJnae4~ zM~aW(Mkj7irC8BAf1Q*Q+LmsD>v>=aNy|#NP=6K7|1d9O7s?Cw=MOC0UyYK&1K`#K zpTgO+Z|XezkNFGE%4hz;&hrkH>q(hx zA4TCmWOKgMGq+e?_S{~$_&Ht%u@OBWpKG84=CG=8k%yVZUd9L{tUE&j14~-K$e4p- z|MbSmt@(MYY9s9!O?xfB^oFU$U0TCe1DgdDjHC~|`ADh0g9bJYC>Y8}U)xunAQe*$ zY1`KH=6Z8_kaYFo9V&X&SX+i?#m@IyK8{{Rl)*iWM_W26sC?3t)I-ISeZI?frrR1(NZ| zpU%ylE%An>L#RjjD_4JOSWU@!U*HyVrsaQ@f=*cZbk1d`8*T-j|9>P=c<`|yXXTtV z))s61f0GBqFPQxx58dBlVhe-~{xIPnZpdLxT~``5`rgMUi=S%t($jI!XE0kbk(|4{$cy7(Z_tkwpdaBN z9nc1eI}f~whbj1>NZ9ZC7X6LLz&9zs%+0&5EW_VKq*=S+KxWC)EvyEs?pC%cGv=|$ zQn6M@`MaiuH4`7Hipg1f^Dn6;0=lG&N&qh}OaHd|i0vcS!!aeGtg+9Egmq#o!8uR}keKu(-TMbrk^ z>%Ky9m%Xb{3E&GB{d3dA0q6S6O4Ti%CY);wbzGtdpqxcVTc*d;+^bi%;nmirU3E@6 z`+WCmSr@D?E#EtpuL~V%-oEjL@z}VD7wYN1&D$3~*%cAq`D6+GHz>nyD1(sqJgf*t z_C_)Yxxm02-_~@Yb_FT4!jDfn%A@wJpNre7%K>Xo&#Z(o)=J zT#fGsJ+Z6~zZay~9<;+KPH`i6YXFY^<_=SSe-mKYTpDxwk;m^x!%ZL-aT#>wI@}!W zh#HmxNpb(Bu#(LyO0gTS2vcrQ9F3q_l~dugF7<@MM`2E#P()JSQfImHya46bTPVL8 zHsWYVN+nU_k&5JEwp2MCMHSK+c)myRH_Cm%pTO|u3}Oz#<4ODj_zlLHGM*rf-Y%He zJV({?N4a(a@d&K3HC6tZ^5ahg%5PyommWX3-{53d&uDU6WBocw(=i>PqFRC z{Lx=xSwSM)2JX`gt5m;+GA@qIq$g5OzQYZR%esbQsV+*DVE#Qm;&O?64KOeC@h%a@jW)pTO##Ky>wvN)-g z7;lSeh;^`)mxoaaU8yeaxg%+c&!zP~YS!33qAU>Jeo{Ae4$ffNoDgfMF$M4J+@ddn zfXrdV`I3JwA(16mGx+Zig z%Tx0c3e~NGiz7luTe1xDH2l(Q1Le)RQBqqGr58Fr(2(X~AWN6H^5!mx06{xOLm3Z%oV}ob5f4zxnRnXfk6t1Pc|%|e z?~ER5MCU&Iz8jA!Pu3^~?qY0Vg*%E=Tz$&&Ww)%-`q*WjS@7eI|igw4J7ziribdav&x@Yo7i*R361g2x{R8i znm}Y3Tof_>t~_7ll~@;Ev9UHxi*gK`=x<2zFqftKQmg0Ca|P92nau+u0p6`GRY~r6 zxC!46sfv*lt~->uP_7`5)AJxFdr~f*jr)>m1G!i)n06=;45;)-iL8l+;^T2$`N1{< zkwD!us-Sr+wrnQFL{l{X9U~Ocranp4;nllh?c!f$^EP&68B-t8Vm*0>zH3r#?^u{? z_;_z^l55)duB=ckSHJeg;uvR~5^bKI&$!0+Y)aIOUE3MQwckqUT26cecpCydX|0%n4JCtyvVw+^cUNaw<*K2@P z&))x_VCO(wX|7FDZdl{`w5y~2Xuco*HncY0ajD%fyxW23S2=wmqj%2ef+d6I zA@NNZP*Ylf$W&_^i3PEkcZ%qtH) zYe5blLYXz8yjoy}fP}z05~sVDK9WeP`ur-&B}4INyh%>QQY(}Zd^8VlhPw&AKaPc^cg)AomI0j=M{t)PiHy3YyAX_2}PU1%YEO-y!L3K5s@}&5co!R<5 z>~Wc=O-@~ZRA^1S6J=Z2G!$9b9SZH?+pEF%EKiGC)sw43U5xC@^T9ZzdLjyQde{r~gz~^4RMY&PyBqosA{Yj+rYC<~#e5O{dJ+1K{C9 z4C6;-DSZ*jVoF+MF&-o#O)VgysfVX2{)N5qDbJ2Ftbu3(YajDg|Dv^#387Pl6i0-N zv}7CPYxt+vfVIhs^!d%&7<$BbDvt54zFyk(z}8eIxl3ZJf|dNh+yILQwg$Kz%6A*e zXY@c;hDOB6(EB}uJfL<)(4-UFv%9tRSw}lxrIM|Sd%zaIqjm43+OVZ!IhMZhWMyOB z>vIlNY+i+TMoa(iNIkeJR^k#@MywyF8`OJH9x^%M4%P*j8@K_a1+8dAozb?^i5YK5 z(j9};7@+8XZQ!01!7U&(-65y%8w_sy5vX~2ElKnGU9eaPqsw0~i)`#<{kAvE=? zhDT<-S72YUx4I~)X(BXsw8#_Yb)8e{1ALo{qtrFrGaI~u`wP9))l=J7L_|(i2MB#> zpu9k~vnn2|h2)1iYG^q|R3=2#MA$eabtZ?EgjpH;WcY_>`P*n}yT{fi#5Y9Q*u=IZ z%L@aHv8i7Ul($87izgv8I$M zYZjJZ$EZ!dE_}nASFHS4ra+R^FeeDoN(DTRq$-w1GMIb9@P_Rz`a33oj0LP0%r=;W zhsFX@no`=tobM~@3lnR0vpwnpuZq;j$+k@W3EA<3H)$`FV6`Y7tx z`)8r3@FpChKZ5Un0q@w8kpTGfD=33N#p}M``{mNt@4p4d$ay=!LX-1!VdtO507lqb zs|B~QHRe?~FHC8`_KI_rJ#23f_PO>YjptQg-K6I4zeRh$e0u&vCJU%^|VltI`dOnFP09ECqtUJIuR@TXYuo#G>WU&(_P{lJ&Ss^^pm^fz!l z#7|(_NJ?T|HouuqsKqJ~We}{$G6_yB4R&zm>)7acr^vFV|Z&F(VIcWzZ)aOQQrvW|H7x^6s>&fV*!j2=nrKWhzY*4rHrNZ_`&c- zB$>Nkh_ZpN0B#-zw*?kpK%p!kBeV4Q-Q*g7vARS}(<3uXEwn7!P2Iull|5>)?U^zS z2Q|l#Y=7SfJAuGKUDLZDN*QZb)Uzh}$DoQh7g|m`$5sUWy#Kb$-8j8*BJOAZij+WY zozRR@>5tJP4Ov9xkfZW0u7|M$*b+Tpr(zasu*$pqlSEdP$`~q$A4KNKz>-4o$n?!( zahJ-+xi%1S-@10c@x#Rtsd?r_>qFT!q3jx-S)rut?ji@X6T6f>(hnZ}(Z3=!P)9p7 zy;S;h)L3)2sf&40-`eD#gUVw`$z9?qf_~h0iwtOCz7D^_yhrolJyI^B0YeYy)*MB^ zpo7fZ!NL_XhsnIB?wMFCca018H(TcE8*JyF87vXW)IAbvBVFR<0cJ*?zCm_=I+yWbhc=aI6-z~yf^y|+p z`1QIeEwhOZGKZ+T1P?=zKqqD3*+zSreL`2V&F_4B5&gioPZ%ulr9c0i=bcj1H5lw% zcJfc9ypOK(LnV%lDNxtcX*dCT$FIhA-yrVZH~S9+;bp-a1GG5}7;9onVVn-ntd)*_N8X=YHWpm!u74%^ zWBX47>~!@T($~ArTj)79AL!`1w7X4TQ{)_1HI|sXVWKrR_;E>?yGd@=3r;VVyw^DJ zVa{p$*JATBQcpX-QF^(#``xTp9H@c1zwE3kd-~nxsFkD5Y3{BmjU!x~8oYnz7L4Ob zyv2x2D3gB+F&Y_+vw>xdq%vktq~dA3S*VP2#zz7DSU+W=5Wnb5aI12E2oBI>tYJ1| z{wLWTnesS}hK$x!cu8TpfI`~PPg}Wu3K1Yv@EFOuHSIBWY!5pQ9hSPI(5BB(KXJat zZKV#=1nrs!Ut8dM%!3)&(1)eA5c~RVM)u*gV2qIk5A3i6mh)H)d^Lj+RKse>}@6p!w-)Dt~pE)F!$)QJNa+VQ;FTY3=HtSP>dh zD0fm{7L-unmp73G(X}Vb(`PIFt)rWhd@{nk94s`%R!(eODb^N<)p!;Gxgq{JaxZ&x zO+8qakrO7%j*v>gJ*BV*FPlz>H74rBQvBxr+c?;Bnn>0P+Bm@1@9Yf8lp$Fyh+lvm zLvxz8H#9Wktue5%H8ilcFM3h!JqpiwqN`;hWJOo7xbhqo$z|P&k|#Qx#+=lnOLG(t;!Flf6ZnLN&MS z$l%f_H}(0$VlCf-p(l!p4{e>UiP92lv5R|CHPO*pam{P@oUE?eKU*EFD<*r-a(h+5 zx>QX>d!}b}%WPyy%xrU{XI8sh20m|4Nq11HUsq`ec8DtRZ_C=dWva}NEg64&e_qzJ zTPDk7z9nN@_UDzovTJ3Pe_+j;T`v`vy|Q~%wSQpUn%ysfnu1QhL%l%Tf;^nLbv#^L zNx;RGVD%vxwZpV0^Q=_Ez%hF34WN0U7>g3N@X$kGn~U1FiYHr&f2 zE81H_rV*S~>ld8mtu17=M9T9HiBSRi*4x}m(t|`oJ=ZYmlx2X0UjjDqO_7G>$c%B6 zYf7*k)_0BY@XHCba7(C?DbE(>IW2RRS-pU@BoRJNff7BKHy?&s@j!Y8Ip7Y9Pmlmc zWj^o~5sYT=DtbNjJ(&jqCmMP^oz40vd<3x6Wfk^>F#uxVt0v#_?m>M`AqJIAG+<#I zzto|{i~Eufx}=HkRK`u^Ok6tHAUE2hgfOb#oF2AWl(?egB1x6MvaR@y5B4Sx7-u+1YWUu zUY#Ac%_?(o~XF0w*xp~r(J^Q@^!#T@~TGYyeB z3xzr^p^~C;BUW9O0xO>~15JejkI-04<>&Z3wb>O*ma##R4vwMDMiqGw+O#p3rAb{= zW5UdSfk&WTYBhBUo)-o?iweSdNe?~lfhBmbT6RH=aDIeCYLvH{n!bC4y>nuyJFMQ7 zC6`FOa)Qm(__kibmNqhbZNAVyty1b!6lKTr<(aZ^&d#ZF4>dK*;8aN*BgeW9LC#Jg zP6h@pp^nm2KMN8jvh#Db(onbY47O)8{LIY*vi#g4+>8ud!d<<>9JGi6VE9J!7Zk<& zmiVC9h?d}!kza=JzQxL47xY8*6O2{wfPc-6k(L@A1~D)~DaoMNaOT z#yH&$wt~rUGMAqjtz2hW;{#v34Nwe6t?N$kuUeTwZB@Kxq_lXqzOSTI@gnakSB4Eh z&|{#3u+Gw2&z4)I1kp7rC9k7)XQPXbPWdCp>yOM+LL4=)ueN?)e*`s`O3HqMT8TZW zIWiv6dte#d@oNmXfSe(=fI9QQA;hZf$|U#>4I);BbNxUCNSKiHWm%cAZJ1VFLeX584R1=>P(lsuSn)s+!qELg)+aQ-f*@m*~2}l%CF0} zD%s0DxmpI_kWfLic0ct!{Ty&-rvXe2!Iw^8I0V0|fE<6}9YhlRI(+Y7Gvr-Z6K0tN z_zd+YQhYe)0~kkIap!cw_j-ifxpi=^0RM@4ck!IJ{cg`93?f`kx8|Vo* z7v!M2tDK;ogYSkqEyQKWf_Jhan)4(V;_YPBJNeH=LKYo;idHk0$Rs|cDgK%oI{p>W z(e1gxS~Bg(>g8#vJ#oewU~cODZ9J?EgtHG12VU|{i43uJ&9Cf?4r|Nuf+ZMXi4$eA zfXbG7%DJKznMD5wjD9xgVGYC95S!!r*czDeU|eJC(0S zFlp2e0!3ju?Ix11aGMM{P z!vZz0kOdE&TAZI)^3Hi&1Y;?PW6e59mKHrdm~5}yEcnB`dnmgPzwgmDI1#=$_nsI3BEC`Z zS^L$%?zUPNCOj&gOu$#3OTYh?m;d4fJkbGe4n7cMtWDOuV0v)|o_OrsvKOv1;*~6} z$lp}$rlnOl{cMr)(E#?oupgJFJldD3rDc~pp3FO>e2em{eYCjb(OMZ+!eR~OdPM~G z${S5f8!Pmp;8DO2GMGF2gr_1hgNXERybrb>RFC+7OVI~-EUXJ#paKVQe45xd#ev1+ z*#R|iwrXl@u%AdIiAax-h}2WsW+LrVlVZ#)q$}h>y_K;V>h=*Ck&bF=(jZ@T;WFPu zx5SPNA5EqwaZOXWb9{ABP;F&xkSsSTKCLu3x+~K|WME_L;o{^NQx)Q$pB$4?5ExWf zRTJoz8f1sDtY|QTYjY#jEq)oq(xSjyDd%QdD2d>qPQp#CERDlC7j}tPxM>*ZR1n7E zb5mJ*)(icNtY%%9l3{8?Tk_?)G-X%OH71YhNtbAd^TxJiU~_GCk+d`+Vz@Rz+ebU2 zXMK{qF4h6tcEIJK);7uK#u4&;SVpV(%?LfIvb|LQIJ%_FiJ|VK8PHV~n@)w&NAs z@rbjWIEhD=vlD0UG)>d|+F#QqZPQ_=ne8u)L685rPXdHvr|CbRkmx-RJ99qY4)_XEWguIlYme)hdRh(_#YR(Vz zyYPX$b8LM&XVdrfy6|2^&%`EU(%6coP;#}GA2#SSD|;Km=61VzVnhFeZ66NY01jic zV9;M!d=N%tU}A-tv#m8Y=5hXH6dRQL@*0~tpR)OuZMOdJoQoMkYH#9C4wQh6UvD#} zQ~GC`R#~n3?pEKj&Dy`I7QHqX30~y|OaEh+^fh|_MN>b}Dfoiu5#V<+PM5V}<}tU! zmStV_*#A7Nh1t#oUyFO47{EVSE}zY0zqR2U=~ZotuNj zM39}02ia)!Sa!o6w`s7?!xh*#fuMeXPuS>+G5QeQX2q3_-D}o9t*ySFNXWHZM(<=2 zE*7v)vtslevV3U)VGKb(d1NQ_7yHM;1vG~k6r=<03o?~;3)$PpIEdNQ)52%RwWP;N z-AYR>L%fruOClcP`V<74(*@QC&O4;V4mO$f*T(mSA8co~{9gF!Btw>$=u7ARPNGVE z74ZtDOTe131#}s->x1znRytgCtm3x-^o%ZJ|4*zgA1?4`d}W@oUTIBP3P%?JqcPVL ziL+nO7k~KPINh2o7O8|HbwwXjXG5nwNLN|gNCo@zqrg)kjsXGXaCmV*Xn_@a(TfX_ zEQ_QANV&-H?6Z?GQtdo3GYCtr^;$77B#EiRH+Gv=+D(C?_M<9nv<>U-N zcK|91bW<(k;c1mSI5!Y>V+#O9MDe%VfSVtbo-V7{+-3}=#fgAV?V37J0U_(8(hBCB z9n9U6^N-B!nZr-*G|M!Ogs-k@j6-+|oe)Z>9Nx0ugyIViZdqBbL`Wh8)ThN8350aH zkdFxS;g@>Y_c-5s98g!v{53%k%$pjr0M;!^u%62g98c&c`28_BMUL0c8Webg+i&Rz zD(9F;>6W%+VQ}-rzVhZBm3|WExo=2`lUx3V#_mT7y-Hr{FPLsj5{9-<9j>~Ge^5mD zg2&71AEXTcldS~wfWXNkXVl7GG|iievNyCRo7SGjM@#8FGt~%XWW|`WQBuqLT+@bT zEp{m0)Q^b%0_ROpuxaNC?z}-*h9G_m_yUj&)xb0tu>}Is@R3+uwlX&(%^B!IZw5@k zuc=?%fF+p4?uL00(4QB)1GE4XZ0F|YpaKh+1&<}r0IW5Nztb31ahIdx$0=HUYqi5u2uomRzsA?py`fBUPot#l8+s|229u zG`%*Fj4c_+M1@mkouKp)^DU8_c<*T8{C}Hz2=-3W;wi>;9YNQz7v~lfXg$1o4=MGP z`Y=bW*YsqVo6~>cf-cJXv1M?{>A$L<@ci zAT0?qG#R2Kj8kISXz{vRV+7yh#~1fzprUEBmT!r^C0-DGkJMkN`*6EA_dPCl=GHz) z&xAZxu%lM2$ZSeKep7$s7C}TxMIthE7sLwYHo*|t%Yfxb1@;E#h!y{6$68V9TMPW# z%>$^pIV;-nZAw2ou$*cS;`Nn-?0y&cenPR290g!xye%#Z0zI+D4#8paG(_UP6O6S; zLX$mIl^iS(fwwrjeqcjh^Uex?C-CS|5+`@l0!JyRI|yvT63MX%su%(vI!C5bGBP$z zbQi^Ni~>1jl-xU01Dql|#*{Pr%jJ9k38=4#?*OX@I7}cjEGt1&;djV*;MWF(=t%0i z1A65pr!VoD2DrZeB}p1<%y1T}!Sy6hN9gLG7&NQDfV8y3$C4lB91(XmAy?|xBtyT) zbAe|UiPr;5@g(EOly>PMHaLKS4PjwP;Zm9oRU5)W zljPE5TI3nwW;J{d+t~raCsx8f49v@j7YM=>K>+pjPYca5i1-Ovg~5cUDkUc> z3ZO5Z&Iuq88e$5KI!}-tUZVMAA^ifUQCjCNG-T1x$5|K1LSc}~7#W?Klp@z>I%@^N zDnn#c8eI9ug?b6-7s4{tfpTR;Zeo}r!A~9+;T{$Tk_gb@EOldlyk}7fUS4q_uBnt?pv2$Xm82uRgJXZ|9TO;%1;u)MM+dmN1S-7z0)$czC%-^M zz@`Q=vHXqtU-kgkH!SC=*#qhQS=9dm^Z@o@9`*bAa_e`H6H@+N_S@<7JYqjZkgBza z=Ffi&^CjS&ncIb51BBlUJW>F609>J#SWBn00Lq9vZ83BgfGVQv(s+YobKQ=iZC=`U?_h~Wyj zw=t&gs?e3JH_E8bk%;{sfd?PPBx1j^OwTuAItGef3?#Ei?CAJ^7ReZ)0@?>c>Z7m> z434=_^kK$rT7DG!4T!NQ2mDBV{59~MRi^^!8(7BTJD0pkafnz`UX}cfT^kTaw`4`+ zulb5zXwzfi19TT`V>TNk!H10M&;`hh%%cv0981Fmmh*$D-E&`mr2CK>}T2d=2~t;_6|m zE&woZ7GXiYXt^RF(*O4VA7}BXW}SU-#m|ehfbKySeQRw;Pz3-bf`iCN$`Y1B@-mQ9 z65W0M7&k!c*kGt0pE^!1ANY5)_gdTkfJxcupA2v0rguAhFq``n6m&yLPM<({yIZ=W5dz9sXwUs*Ht@{Ec6-~+M%KCgXgCZBxXq8>UwkwMNCkcKrE2H~@TBp)Y@ zYtG|2L|lvlj=c+n3)sFOS^#GS`U7jaRm|{|sfo)yPwa1#)oE(n`%b+xp3meDUs$Pd ztCdokF&@IAO=xm-<(yZ(9$xTxHqd z`kh&;Tb_UDHgz$BQjcGJzGbZF=x&Gz(wHZA9myN(fBnLNL}cYZpl4kJn+MkWa$$A= zZ4m%WfYVmEqmDZ=NO11iBw#qCIcPN}mRrw1NN4cnep=`d5e=9m$~8o$N%ltk(8`XH zjQjz>qmv@eq|iB4klt0yIFrh`KVowNz<9GZ4^_IQlk&pBtjxi>Y(NYGUh-An!kh#? zsiK97?5ZerO-5LJ*@`vmlHJp{P7RjF%X3@xu79$;uUa|KRuCIsxypc=Gp0M!V+uNl zR)aYopEFKuJLLgu5X#B$Tm(HxzL+5Kn6MoLqlVy62Xe$lRnGEd1=katku_9HyjixX zI!q$l)0f?q?(XPZzx8aRs?%KL+s>>e5F$1>7mXeXDcsbVQtNRw|W-*Ugme6VR_Db?hh|J*RXvb*#;4I?|iu7L^fWd7pSn=qg0S@5_#k=UFOH zbm?eO)@Y?Ny?blU+{fBdwRc?I#>(m~b#Vw|5U1Ey@(+Lw!%?SdtniaKWQDvZ*#a)U zyiatGc$H8|v#&#no%^W7x%&)rK7auTs8m9AAeT~^-NlbaKvVM;_4D^DA-A@hCQio;bf2`Uj60EWYQ$Zz8~JP17Lz-Ps(7JR!fnUPsu?z;1GqJI)}Dv za}}P#r)Y_fB23~fK~6qS%G7Xo!8XeBY6{UE#0M9wLgFnZoV@8TQG7w8Vh;Hlb#g=# zYKkvUFNz@MJ?A_r-9sVy=}{D+qCfzFrg?SjUM}YfJ^>;YIRr?A9BC3iCQZ%{Y0H@5 z;Yo=mH)rn{sc>@E^=?g@6pS`Ma?=6r3MA~Xkvr-v{$ssJ-7Pg zD#k^U*FRIFEKl+gN*XqwF3Z}IPPfGd7<&pzJ9KVP^Fi5ipu@bSDc!@}!83tpV4 zm4S+Ib0j^XC7*MQOfK$NYf5ab%J%GH)(9>1L&P(Y2*DH3)NLa>u~JWs_s&yY0ZfW_Kdzd z$-jR0!7y6?!w@h>wzy`3|srJD-dEtx*h+cjqse?gc zS~QVb&uD6fy_8ZE#m8Qi-L|+0IEVIJ9wb6$|6v~>A$0O8ooQ{oXML3mMIvyWY|T`3 zzif+==zR9JYRh|ew#`cGVN(Zlb{oh;-$0){phsYbT-e}z487psQ-5dcHVcq%3WN8! zIw`v{iV|&Nw+YEwpcuE9>YP{ryQ?H9p<+cc@dZ$e73+Qg&TlM#E}XJjhLEd0T&<8f zFn1xvgd?pm7quTB%8~leK^ah3!4Yyn^-Sm2uS#|luLh(@ZrXH5dd;r$)w_}J?!D|6 zdkve{^c2PB3?C>WF2j8GvBA`NXeSCwpR^S#!Wj`TZ^7pZ4)1_H4P**en8V^LLb~?B zc7HcXa?NO-ETgAHBawMjA04_~5TZ6l=JXcCdLWToAN%9vgKPws7z3BeJbT9@h{ zALh+>6Exob#z@(TU1KqE^1+S!@_HVdsSuLp@GNx@By6b|m{`kKvqc4wWNXK-SMBFMwN z?bt83<}f*%&eqFhRZNwur0CGtlVC6Vo1p&CE2}pAFuwNdP1C=*tBuc&qTRy2`#u^) zU$Cw{FCJ|bQrIps3bDwaLAzPdF4VPHJYukNuyEWgTOzql6xK4XT6Cdyi=R*+@?|Pg zl3R(YcM?{i=gVzUKh@`Rz%QqdmnCFVm5d z)RrHeP}V;>o_HGh&A^(sz**W!{|4kdJQ6@4FB(v_i=+mM4i@rkJ{?BOsUl0x9I7+6 zF<$ACH*%`0bz8Bg6Ci*kPHDq6=3O1>(uCfJMiX5q2X#rW0YFkg5=xL-Ut>A#qUb)} zoW>XM-D7gp+Ukrb2jYEaDaro3`OJ7`-sI_8lufWt747cJNb1^Gg+zSg>IVir^urK+ z2kBZG+hW;=`Mzkn^Kh4rkIEw|%ks6s%7SLh2sqtUNIwg7jAai`IAaB176J!7C;MWm zM8j6}%UDZ&jQd73E*D$LwLj1mRGrql?C&UJ`!1Se30p+dnL)@J+6DluLN2N zhI&tMqAc#(MUrsU3IJFMHGH=2cngE!mNL-`x5^V|F{|K#RZQ z2_gNvt6r`_b6&-(ylu3V(o&?yw55wDNJ2 z#z7{4Ggxh1zwB`Z(zP< zi@2zN%N>zw!{kGKEq4sUX-I0@wpTRXz9NN*umt0D082S%FoU#;=LQ5O7O^;xB?W@V z!5;-)NEtwMFvp4`f6(^?aq*6u8PC)8dCXlAM$)Z_PWC`Jq_m^yv#{#;_xVzgwT zxY|uMRU2z!aUP9oTfcA~Ay_S7R|_y9YXX<0J|Qu=Wi2y=TFs}H`ZX~(HKDoAkj6>W zQn}a>;tS#x%OrH=cIZl%1`$tK@}YBC76Ve&ZicpNp=|^e`FQjy&cil9fiRMUI30v#jc=HK)!6}d4;s1hIznN7mP~7c z2rRGMO&j3-VCMpRB{w!qcc_&4mfQk%D^{Muq_Dw|R0VQMTrXwsMvYh&gQ{y*yP_30 z1-@ddXah#FrP;uy#y-?se`;kStPxNy+dN0+%#DttmhwBMYo*ed)*VIAz2ivLcCZcp zRUw#xI7=;3RBouQny!q-Mr>mKaa$jyII1EXtg6;&Pa|AGJb;q~SW`F{Hj78IwJEdr zrZCw#?S}@6d^?F>SP0*O{=JRl{;QVb3_E}tq5lWVKAl7KYV-lC9B1dQ|FII$z{X+t z^XDL5_B)8(aEA+wQwYToWopP(u>e@0g3m(g>ANiz`NRusb0*sT#5gm4k(kJ{bb;j< znv3WDK8Hj^Rm3?mR?Z}Dp%R-Vwfu=R}b?eI_z{pX7nhteq<5~}QX0519k-28nkLGkA>s09nPIc7o zXjVs7ZE0xRP#D13LCipZB|slw4Tp4WIAssa2JOvU*Ib?5uD#BD#o0~iqU({00K75FfJN&(0EsGtZ6; zJv&oK5C!mQ)w452xK0g;Q_ZMu!^N6p;4A%GrI zpTO@hO~YE?P!*e}m-BMTs842@^=+?p4craK3v6}Z9o?^YOyJcZ-uDUBuexs#HM3_h z+X(fsVQPwDpL}iWi!j`MS*h_uPQs9RyUM<^?UjvLqx&<5~0z7*QR`I)dDvDg+6#KI|r_X9wYmbEs=Of74RxEqpZk#2U) z-N5B6A>7z7PsMm&E+5p*Tl)_!{Zu2?ebffB>qX#0K&NA?!k|>#B)<%VA=I@+xc_H+J7Olme*@!P_!z22tUEkh*n`b-o~%4Hd$7f%st~ zP$*a&7ER0~h)d8kRz~69G~@|xbIuB3WtkvC5$)ZlyP_llY5mS8`uk3GL^$zDp(HN5 zaq{*CWlv)cB*Hnd6APK42NnS15e7-HZ z^YI;J6+0hqi+0wQpF4BgNU5{XJt|9!GHbN{LZ^=X=W9Dhn5@w|YND&}TvuRPd!{bB z>i8HKlsO&@|M>;z|K7X^j6B168nL5SVB^J00>x5dwA^P=M@&OyUc9?VsLZTZk_nK9 zOCT;C-JQe!p&Sh-Pjs0i;@HX+YIZL&CQo#lB$D`sQHFgTa(y`ZM5k41)upLXkX0nF zA)$CM2Rv^gHWvA4>y7C(j29d~9-3NXPIbHs=SR2Zt5^knT=b)oy_V-6VV)sY1I)<+ zU%>hwXI~=!3LiN+1D;Rb=F!RwhJmEHF=^--nL4k{NSu6t z)i8NS&YW*X6SH&dZj{Epghq+ob(iixZb0OFc&^a=Bf$Uu0(#LcWfby`V`j#Dz;eYz zl(P4yqk=mjq4!DjeXiw8bSRUMTE6D~VhCr}5&hGOwfw^JJ9szLP5%dZ2iUFvuW2u% z*oO>ZD*<jbTBDpytBYr>s&FqD>r*nvr;0AGnU7;v`Qt_lLt+C zTiO%B0T5d`l$^f4uSnt)Q#+o#UqECbH+7BC*r@jjN^eLt4HZR(HMPo=QTquaO_l z#ezvVf}2AQkNS7`jTm0AfJfz0t{ixY!=t{6zOS@=hK`#S@u>f_T*Xra^Zzom_a*!m z%ON+&HsqJjFqc@zMn|9U#KNBJ5MhwMIwLmFUDOLUlGiAbEl6Cyd2LGyr2f)3jE=92 zLg19fW5|Ow&9e3<+%^dOZZ#C)+-Z19d%tA|#A7_nJe5~TevSw8=A4$iHs=n%u+k+S zKgjPkpR-kpS2OjNHD>S%R1-7RTH8P*=sVmV*#F5d;5T-DYEsQyvaG@M{OtlgL%w-< z?w8i*I1UWQ1i-vI9)VF#3duU|L91<+1iWkutpwY49C(Quu%8IfdmiB9#W;5rmj@Xi zClS~Y$cMmA@H|-aMZwqBtVEO`nDakia|&1=JRs-R3deA5LED6hX^E`U)W!8ALC%SA zC%%Yu4A1q2$bkq*-L!6HWkO&W`WGt>4nm1FBkQKM?kO84`pe=1f>K#g9&<-uHoEe+EZtRqYUA4dbLF_H|9X7HI4 zEYp~OS6R>AG7pzXCeqp2u%@Bx-hw)Ya0reA0l4c}=hds#TkB&9LJ@>4xF4{O>EBst zV@ciuSxb3|2!ll=d||z3{Q)Ly?FsbeHFz55qLui5{e8x6dJ zz_dek!zY`5xTqa!gY9Ie_mHVzV|}zlQZll?m|cB|JptkGrESQRIn|Xbk%SZuq!Xu5 zY}Hh0*;G{wq9}%qv%H7Gb9=M1x^uz^EWg7TOQ9W`jJA+M6QoPKc3>}kv%INim>ZhG zTV+{W`sGbojzS|aE@+S3X={&n)7Jh|OZEf0p%F|w;A^$zedEB%R_2SPu^adi{vydhA`-d7D1jg|ndI zYVcUf;#5)$<^T|=F9zRWDF!$m#!^H2N8&d2*&@5FX3k=D#c)Be9fH3`WuNElH!lfa ziC`j;k@^Q)wv_LzE_2;tR6(y6eUAd{^Pf@wU_SZ8dahIfEjDzF6} zJ^FL92zH(rHbDX`f#n?$;To0G`O}#MD`p<5WwgWnkPr*YNMIY_r@&hMJR2YRWic}4 zY-)@XOUg#~<+J0DTD~rH@C-{V?#%_;L2{h|Fp0t{BEpPJ>1(_4BocYapdLa4~#0F4B`- zHoQdwI?O&(YDYlJ)8c*dlJMnFCJY&A9(&95cr=fB>n)DQ-?eZ?+0F(SrS)upGwNyf z-c(I8dvbxdzsBB$nqbu+w*ly9?|_bjod!0yhup@RV9pkVLi>;WcP={T3>;}m?J86W z{fk?MjV;sJE|NzymmD3Ko{I9#t!YlnE-uj*XD!uttt$-8Y);WNXGN5(KU0o{jjTPx zdD$!XnwEdI()zafYy33m;eXMuv=L`R&t7v(Bpzi(9fhj4lH#>y zy#!x~RBgr93*bV{<#$Y&f}to>Vyz*paPoLDamLb|v2`HF*f*2C{4?$s!O5CC`2?4P z9&?LDsd@GvlR+fHiDCdHzjZ#sf@RnKTh3I<$%XhcWHP3MQ={X|+61%Z)ug4Y- zpO~9vosVNCmhApZ8R{o2en3|6510FtHUr-S%z5EF@r zuY=WovD>Q*3OtSBKPriseHC3nM-QFAbhjV)8J1Al9N=}Kht@+I_Yuj_3+NNv zx3;CuB4@U;2G$R?aor_Ur`>`vCYY!i_a2wJq>5bBov7_~Ovll6`<*D0iaV?@uCR5^LT3!6|1T*nO>DI0+ zX(sjT+%qV^$-x(GHP6(>BI0FBDvGI_F|%vY*0PcOP-HO?m!WLKNEy2pOw)%$Lb!Fp z{h{sy8VKhir>yc&s1-qmPkSZEYB;YK7ytmU1-N1867hFAR}v|LkxP6ERu`8$nwdtb z0y>iIEZ0UzOU94YE7|YJh7rrqKS(zbk%v3-*=JA?57JpUTK-LlAYdxgG*b52XARrx zVhHp#V%RcAP+`Gl2L7p2Fh6oGk`OWj+;na*0uvNCSP`0=C6q{>{|_^yHM*@Rw|qJQ z#6VBkCX4vTPtFtCI&?JJ0_bUGX}&WHs23w@{#AbG)@B!JeCN)5_HiLHR-YQxNgdP7!>LAa)QDY1?t0!_ z8kUz54In~=&d)t8OYOrKsPoOrlClR5^t*^%R7K7G%#;vKEX3x311HEdQD3#XAQXg{ znEKsqnFE~b#ypzcd0S&FAcTXMsE}l3n1f0Zmzp1ym>=f}j=rL)dPAp46(B)6a<47C zhnWAIogrKKvAkkl&B8b-Zk(Le4UdynV0)GQIB^bah`~?*BUv2imb7i-)lNdUIAeZ6 z5PMaKpg2l(fyPrPRGVt!l%+Z^p@=DI>+MgFhuemmky@QO?+(O00g8pw-y1JcrZQ`8^`}sRft)ZeBRl< zG6Z?=T&B~{t`1RNxl|rvXZf=F5RkPK+3MY@kZS3dm_fA*3&V3{zeId2&P4d_h(u(a5*Hu2at7gujeCDD0 zq~ZR?EDV?AJq~E08eO6i z0n#IPlSzYJgAyWxBrKdTPbPhO=p^x6P^!`oAqSB{C`7)|8n3w#f=YtiTC3-Ws81nw z2**fS{RsFN!hbic_>Ut>$tWg~VL#L)YKVgW?3A+EHgxl|Kj)B;*6VM*o%mJ9utdczt&B z7qO^O-7tMNgCJ*L;AT(ule0&?ZXO4XCdS#=y{}>9pv#hy6XTrOv%gVTyry0+iM6Ra z@G*u_z(p(8eUjn6NYh?&L9j4$Q806&8)xp<5it%hbK)EoWg-jK94%p4tRZb2TF{RW z0e+rbm^Wk3)*O~yP?eTGAtGx_ZzhFYZ#8NEwwpAdNE*WLZYf2WxeJWekK*=$*Vf2QV4Y;`2==d;gwGTy}I z|5jP0Cv>{4TiKWXE0q=O(CiuNEzlWbV0Ix|i&_jrvQr%K4)#eQz6n&p_MZ&)d$zM=c}EZ90k&tvNhE@_6*9WvRCdqc~^dM`TZwmI`!F8 z=ep`{A4p@G*6ll%u5ijuvbmv1E4*<02wg)rL zp|cMf&!J6h{)6ccK>TPY^_%%q^tag80s%7MXIBd>kGbmu&<8TDFI~Ro;T3n{wk=__ z=lq9|ivc);E$$1e5WpdUH{$Y<7ACedKhIPgn^2PIA)pwNF9}PDiY_$e7L>-y_;eWx zh)GcRho)7;`?yAACiweC#Yg!gyo_u-oy|VQ@8f)z(7vaDjrVEsiHe{<-MN3Q4>xw! zK?`zj`T}UDpQ4txlj@e}Cii|LOWi@B3P|wqB8=^q>X^+9l8{o)M#yvZ*>nPP_*>NYJhU zkOErb>Wc3uJ(nJ0SO4giCEo59{v9J`4YGCkhaS`lgx{`YBrrBMoj&)x&!$n)4t2E+5hl+Zq0thw$uMh zzXno~2z(^i8sHDMS2;*>P^R7&hmVsG`Y#BFf3-ByLP2Rbb>-nQIe4#;Clm}LN*ph? zZan6Ap=~32RD#s5>~phwCG5MdD3g4fLZy24mAOHRy`)FUO)mAO{lsNgbHTo3DSIBZ zPzCWhzI#>hI;186ds)IVdl@M2VN3QhfIi-L-`tbSt!4N; zu7Lf26nHghMR0&4Qj0+BvUOnzd;n!wuPH2V|EJn)zQL$HnEm^$E3`qIi?tz0@M3_y zi-tDCIVqLE{0C|tU}UgeA#1w|5$d?7l_+a@>ZqSvCc+Si8UlV;mOScbl!^cziQ~zC zB?#lTAYN;%6(_t6Z!)=7E5muqxcxjDiJ4&Ypx3rJbK`dTu1b-KBc#rG7#49b<)3x1i4Z zN3LzP2DMwBL*<9xpYC|>a1*7bYPX-OS^3ON5i!TY!s7nSBNF2{mbGCE0JOG&fgPqZ zedos$T_i=r`$|N4>)NxO-DCPsn$NXZ0UxXxF@tAURqX7`b5Tf*&6D{Z2U_EiyQI--28kg0yd}XB zOnksTi?S?AKp#~jHTy0B=LlyS}p zfL$P5*uNuBTXrom`%m;wc;{ciE`#w(PS9y?dcizo&CEr1{B|w#4eKu;{8s;w_=U+L zC4w`F*DXn~cPxd(qsS6ziRRV}`+5Ha{aXGGjHV!V1DfI@yF-XBRxd|XfE!ng79bVS zk19A^%IQlyY(=Gk?5%b~j1bh&!h*RkiEr$SW6H=xATjd#mZc(@2!nJuTBBcvzDVGL zqcv{Q0dz$_%gQg>10o0sraXI81pa*v`-7kt<|7a;Zbp5$XVhzN-<145+O`4_w0D#*9I;8&(`fAtKaw^2LaQt}Rg|S2zF(yL?OomeT*uInIdzu!(8bs5rDA9&W z!aQ}u{8joi$aDrCM)TrK?id9MwtlO6fk9!QMlv|C*P4YI_zg(ZkhsW`^Pj?F3y~|7 zfU?xyUsia!qV2?JaTM(oC9B!~#4y=@*P2q7XbBmb)xEpUur95jCspc{;1HqBZywIh z?#hh@^LxBBqj^JV&c1xhgHBE<{l#UQ+B2mpAuSHl*QTa)Ru~dOL>?$0G$>fty7i88 zHQ)BUdZLwLDD&Qnb^k27WA9W0MA z7^=K`|LUly(Y^Q7BLBGFo>o%~#9Z_YsDM5QUMFC%bzpP2`8+^MpT&8w#YN!q-Jpdo z%>&#A$FdxYWaR&5Z%Wrs8Vgs~rUX(BQm3@`oect2Rc?~PU+Ch1JmU-dvQ>?7$;Ht^ zM^~X=w9aJKCKao^g?zq?*UTzSzm83H6h@b%CYdwi#4=hyxP+%El|`xXp`HRU;pyie z99Ozx?G{5*>Al1;RWL@A5gdphJ@JFZp8 zz@quRapOo^Xjs$ADMN2SrMV7@l!T|1*3^Up-JJvsZXD1!mT|$fsZqOw3dMnOIiwnq z$o2}*aSeJ+z-s@7BLEhV#cLRZnCs7B8n&W~5wC-NfjS8^jBz6HF8lYOJK0wR#6i}*r;^P+PiOoviXjPnfvTkP#YeYT45aXFt6@B$Qf-dHURudEoI07-bE?8D~(l6=iLygg)m3?qZC78Bpn1DgewjqzeGcE954!fnaf@ z4rf*25=X%NFW4@Le{Hxj5#tuIZPJC2HV!#D>&kjJ9ImX{(FH|q#jbPmFj;8#!>iZ* zvBSIPE7pO$$3ct&lItgnMxNW(;_g;=;={G?I^DBnM;o)t=74h+vqccYeyWbgl zVNY4HDYl}B%u#1!bByD9Fj=YqwG%K}T;Lan)C zd?3u>gPkxgl;cALVXl;Dy$^UdZMwJhmR0!s! zX4Uz|4i!=h<@sPA)UZ!+XEf%&+U1f4K03IF4?>~e_}qw`6E#){noo>kQKRGjQT870 z(0-4&-$c^r$IO0v5rlo<(;MPH;Prr~`WuPyhCy&)ZEBI#3v7Y`aN1vVoa~B{a=hL# zZyNJ@EOJojZ4Q%oj&Q9ca`+iTXSzADBSvb#V#mR@cm#Egz?0#GzQuOcYRFrO<9UG6 zK~%;j&t<3-?r25ZCdsXn4Erxg6o|7|`nlumXHAg(Y{%SM2vvfvrxGvQXRoa6Wk@OZ z>R8WNz`x-Aw9p1;eX+}{h9?jyIpE=&9K>ZIK_*VH*3ZEbp~C=1oE^wqg0etP%04_2 zXaZ=J4nktr=7r z?o_gen_u^1n>JnR^B(-Zy87^RcWIK#>~$x1`QW4UE4>&0w&9_Q`;KmE)i&Sv$@JQ( zv5(HQl;+1)mRxUA*RI}qq%d#jjU%;q4Rhh_z_I~oPLMysDjoa?2&)87MX;9Y6{b&>Tc^vA`nC90CxrL^TER#1(So@$GjG)Arcczt2gTd`T5+}Lb6a` zd6VC95+cT-7x$PO4_kXtvA(?QHrxyUs$C6vLI|$Uvb>AZNAB)0AL)Z0;F{pjgZhnS zjR(3I0;6mpuN3<^TYzPAB7*lY+=xJLoy_C$(a|{k-6uc~Sf-BP{SCg8qqpWa&QIZQ z!GMF;(gAoQj$N_FHNf5qwmQ#zQLxR+MD8DgP_th1sR1>P<~!f~w@LPN`SJA-v=`O9 zqm+y!wu1+n={jr;+p{^}}LAsWOHt1n!gY%Tw-j5kEr#?i;!MlL%(DH@c z)1K(=rN&VI5cA!k+~F#%lMFc}I0{{yjO|;?-d@&+rPiS@n?cX2A2-%tHY4-n=7JrN z0Fk+&OE7N8^TQ|kUVxk{!`_<(L@b!kFhmUeX|}j)j;^gj8Q@|eSrNARV96r@96k(& zf3Cn<9%SJazPKHV)0Qv+WZnlGY)ODfACVG@ zU@av2v84c-`9%hVwh{puTX1rpfnMUyS%Ye@Aw`kjwsJ(<@m6Q&o1N*KCZS|)U{bld zd)%4}XfCZQPaadyv1(lBt{Pg=o*z3iA`QSIJMS5gFL91B@bhvRrvTc*DQ(M~iVL9! z+_1UjpfSc(OFScXN$DRP{?1r*+^?GL)u}`|#+1WX(cb|E*Ln;*orq`-|Pk)@) zZ#Ftg6qN%S)&jMOGdH)YB*Lh)B1M^A;`~ufW7fdV+_E#prFWK=ot!E{#MG*4ZHd~O zP$OTaJSn3wB><^VNZwFMd~upm8nC(o_!Ggq#=cBG1-3Z_MkUH@3vffOW?5e!wm7vSr7hI9Qd}y}OYSL{x5QGR6itt_Hx{1NJ+x1K};Wc};&Q z5T&tia|RV`*_M0%1E;47VV?6w51%@oL2zgB{PW;Lx(IU#GYLBHQdi(J$36gwy1-^2 zuQcp8@-{XgN8}l%DeTTl7DlJkXT}A&2}_Bh4Un}`8mfz~-rAPt>`F^C4i2u;oR!Dg zifZIY1SraW)utU=!9=ei(puN98&jZnEP(+z*%=7|d1D6)nqO#XdA_CgzRe{ld&R~S z=nk&~=IMmYXN;{Nw~Yd^+4}j*=`h z^_r(OHN-?Mv)(o@Ron2q@Fk4hybvNnV1d-;EP>dcnhcDayhgQx9TqfET%{TmYA|cT zevH6`1h`4gj|;3G5|rS4Aw*KuOlNjDUmWY+d*`nftR@O2d7;@Y(1f;)&TI}Ya~{@Cvy?nTHyLYqyXn4-RQJ9F888)v2m%Hxu{ z_t(}xW;Q=o-+Iq@CSD`(L6RFlb_W{gFv5#HuvrLbY}j8+0nK*FYO#SNQ4pwdgp`b6XsPNQsx5GQbO=nq3doL^Hz!EqT$&{dt*N9*$rpkBikba`{a&-u&6*VpTMgRXIe(QZ zgFO{|W4rcyi95Ue*g*lgO2F2w2GTVdxve7;NVEniq4s_N)dKOsC{|M;<$GO?$=x^pE{_wa4KZj9T| z=_{S7Q>$7GerQwiM6F&bORefR^c`tdBz7KYuiad&2rb#rl+l_K=PTABzx<7zhVEh} z*jd@Is{!?#>Sx@d4fSKd(jo8YBT%t-h7|B}(9Canh3{tIdwYlv=yPx{7tPEAKA@{B zgL`)V67YXOC4ww#3`JzZ9neGhQ%)7@ooYc8n_vkr-8F=YBB!`rZQQ> zoy=)gBS7!!89mgR;?04tM~}wYozMpaHI7=SdiWjmAPNEB1Kol9gWqC%4f!Y=YtR~4 zlK?$=l+EX(CzIhVzZ9^sN6{~Fx=n_BSBqb!or4nw`f(2tj4b56*vs315# zEi637{dkc6j=omMbaGyN2 zcwcV4kH078p?y9N&O3o0?3Hkk&dPY*;D6i*-NHTbShO`*RbHEJ#C>NMv4Sm{7(l^E zK_F-Y*y~4ke*BC~4%Ntl9WaSEMR`%=W-ifKrj)}^yRTjt9WGkYwYU7JzYi_th{3Qn8%Bocs#nk4+L}%B< z&3+L?tqkJUy@mG}n6n;)6@ZGPq2L(vJo`!JX9Q}@BVyR?Xheoqfg*+=PUs=@64dqL zp2PTJ@=t#t*?aR)^KZ$A+08O`A42QUX8g|iZ+TnD1GEh6ay%`}uRk8#7ThAx#}ILn z_=tXlfVy8$JMSddhmFK8Qb#|{*&PHn76~NHSp#4lvDHE6;ggTuzq4@S|`r zQGqH0btWNz2mjr`m#x`yf{F9&8Mhm%;kv&ieB1wJ!7Cv*t%w_jx`gZ<0jL@M`H)>z z+(X(ob>H1s756*cn=nI-U=R5l>|?A$gGw<iIqyf*x8uWc00zhR^jfb4byAsxM9| zZQgaM{r~<|ePX)CMH+72Q8`bZ{fUa=M5EZTnvH9K0=gx^op z8qWfGXKHaSZH7viQ*5tTKA(#@QWs|PI-BPp^J_dkl(bSS)bwj79~}&Hb9h7WM(}IG zR|THkcf7k!+s6piUCi*)yPG_O=oulK8-kuB@>D%fY%g(j);UXSkGwUa(!QVz8-MFC zBr4OpxE5@EVnu}R1z2Le5uj!Q(?*n#C6yf?^y#h2&;G*$gfk#0q$CQw(J5Rnq)5tCgTTcoJYiE)q8 zhg*g)H&|o~iBwal4wpGBMe~hq!N;2k;AFtPc=97jDW0i*W7_oU;}* z2`E^FaX18MW7zvaB&OA+1WWiLr|f+Nf`UESy&xJ!>+)hFnGjc+rfApF@ndEg6r}M^ zC}18c-rSw*A|M4w;2{r;(8mUQI@9h%RAy~^k1F5aA5@B<0HP|iqOv44JTNgcC(AFW z>&m%3>Q05Zx;Q1AB$Nr8k3DD(kumzDSU(iRWSerp`Uq=T0f)y$`bF3w-jFp4Y~@%| zypiYsc(ov;0(KA-@lgxnE$_f^*g$KQ!%nDjD1(n)B>4Yrd~sSAMq;ZKRDX)Qx$WO(ncp9eN#E{)#?jgV3iic6jdu z$dcnA&j(?xE8ObnvxWY^{vtg*F;mMxb?@kvWaD&zAwdQV6x3NFQx4 z^%Xfdh8L}=Gat$I%6_D&e{YRkC>2X2s{FRegH`<}T0)!!u1$L`4>aGsq1r|0kHHIc9fEk!)Z}tv>zevHe4tMxDZF1P8**g(n{~<(ZD}-_W9~*!>u!(|BS> zDZ^#Ss5~=Wm{>Qyb(b+AyFVYaS2$zk?AO%2Ksy4sfY2Z=Jm@%s=(!)*>l!2>SFvC7 zcm6QWe-X~KGwiq2tMDxN=y0z2aQj^Ik6Vo7=fc@{1%Non$GPS|7R(i(3q;o3pBWTQ zYRPzueqr^ChV@QHG#LDdY!HuSj{+i5$Ac22&dDFmT_Tb?vZ)c%P z?aZSC2K+^!P%*Oae79-1QWrouFi`$7Hm}2wJifBCB26k1`p9)fod&~5TUnaI@rMBT zI?mK#NEsh!FH4h&JYzB{I`xL(_R{odM}jtNp6D)AMCLU14eOZUzNVb0wi7Qj#<#tA ztjT(_{M^pESWt8~q-s{JXvvFGj3gS4+Ho49*p%e-;F}|)`VW!L|(fbZ6 zYf&aAKPUuM4@H^YuUl5xhK}XRLfKVgy8a>FCz)sir6hj~`dNupBLzc60Exv6Y(s|w z91E)|R)CI|NGLpRW z;byixP?xCk@ruV!;+u9)YC6*8x%gI&pE}YTvMdBT`MN=PMRcOC(Kiw9ILLgQoc-M; zh`Yx=Ykkbo&Chx9!HmTR1Hm|ie+p9zbUVU3MqZ=tu=>JDIZjZFXP)=*&`RoKST7gQiyp$-67LrjXx#AL z-NY62N3dn!SO^~Yy|M3G{jxTLIm2XV;JY>K3|a$oA)eRpp5Tox*N@LhQq&>xM6r`b zo;#rqQMRW5K@eQ7ieKNc%4r4G+y{$6%iXr#}B zz8MJ^s8Yzq*Z}oMdtmKW^Vag#^EUHlpg;R~2YI*i?%>@IqX)a_jq;qY)nSJ%%b0Gl z{Tpk33oZ$87+_N%XC4I)I~IVjV1OOe5VubvDEtu$oD^&AYuAHmLjI zaTSVle=d;ztvgbx1_Nf_8gr8edD6nTh)w82cO-SU47ej_cgvtVa&mwB#v5$mQ0$P~ z%9x=GL$NCbyusMP+3#!Jqr-h^S{fMPY9{9gV+Jn_#txug#h2=XgY~8HL)?etQYHH& z5ssWf^om%G%q1fZ1X5Ro^87VXUY=2!fS~|Qq?czT6M#zCZN+B74Jw2y5)ev?oO=@` zzqM-BTkNa+K;%FAzyqV~pB|W#AP2VqkLXB>%pc|c`9Zge`-hC1o4!8h{=@WK7ZL*g z*2~w4LPhuv2(r8e%SVEbg(E=oQ4lwkfNh&1l1>D{Cymr3TGw6x>jE|dcQ#Ham&(9dFh(~WD7ymG~B%LNQG%>{Gt+(DP zpeTZ(_~mm6a|z`8-*`s``#HHLrsqdxberS>hRz&cxwkkYF|o+UTcI|_o6lJaDTh-O z>^D%Bi83+>u()8Cxph5wm!DS;{->+K<8uV+pz)6I#xbwMT-+{GMLIeXx>N=Y%2;AA zec1T>3$A$wb!8v(KHm3FQ-3Dk_Aj$1P#Mf=vyKg~-`4E-1z)TI9*l z4NSelMP91hf}bbm9|iupf!YIHPz?QmtqhY6vJ=EW6RhQtD=Ea@G=y}Ptwh*PQ3$GL z&r!S4>c?BFAbHH(!nmE)38|EhYrfJf&X{f;_ z4cd42`|R$!lN`I>{(gV`(pvA`+}!N!?C$LB?CfmX3nZ&>cVB|Lb9mOG*f``Tb8@R5 zyS(hzX0j-215ZyDT(K+(rv_$cuInpyclHcPE3OQ-ex>ds^RO2kUzZc*?iyd*YOG#U z8A@oX-{jNVjd`&M;RkBI!u((`rk)hxf-j6FQN zW%JRNfomFPd-_gmxb(ik#(iD!IHMC*ySBXR*xJge^E{>(ZR@=0@A0I!VNXYV(-jYO z+|u*#<@IqLdmGEwREL&tzPagi?Ty@reKY1D^bN=dv4Q&#dx^OEuW_#aocKS;cK@7vcgedd(Fjzit*K3cQq(PcXZAK6_+)cUg@lA`su zbnR?AwV{~u`f>RqgR18Lgzn|HF~NTsZ@F)jfePDM@c`>HWG8AiF%FqAalc2w(n~8UH`WB;y5!lpOY?F@nls$hednGm-P&r3Y}im%UEz|Nh%ZK72eVI{*LuNy9?K6J#2a|ftJJi zFrG!rpM6Eekfz8v{;ledwwE`ep5OZX_R-%M4eZD1i}##aF?6JL{**cL^=Rw7DMnB4 zid{XuH*Kt$>g(xMaanKg%^Pc`ksp^ny1%yJibr~mFMag#+J-A1>7k9MwpNsGx~27G z6WYCW^XXRb!29dRqV5<+le~Nrrw^X3H9b!@RP5@AaQ9fW=9+5jL!=;Y+wxKmkAUj2 z9P8cWQ|m0~kchf1b@dx-_~hcBXD%x4FI>p;+?3g3L>=c~UgUNXP6NrvlL_zF#cJwd zTr^a8CiJKxJAaBvtM3L;-*QKN%l577S@1%@+peySS3KNvyzjC7brZGTd}>my zx$Lpp5#w9r&Xglns#Y9vM8S&_NAE8pEC zc+skC>+PBZcz{r*xjMf=IvNpQiE?4p6Sa^wHl0}9ba{KI$7RM{ZvNHl%PRJ-sPx>0 zvH#D-SN56`d#`L}-sk>VzOgYTx^ZI#<9c!`%7*kb23~ENe{4 z<`m-f*pqDJ+>XayV1s8z*_qAT&y}hBVL92JM%jU&2Y&-r=zOUp5_MBb-Y>BHO3E{= zFIYWu=^X3tv*>2(PApGa?xPDVAJ96AZic)#_Jwq{W3i|+{) z%KLON`q)pEH z@o1Ik3m<{08`UfL-VEjw9d3#xe=$93-ReYc^H6iwr0jugd{M{M;2Hjg$#yCHg@{=d z;{!Say>6BTca?n}+E$n4>gJo*n^v%~y8uZ)t46MX~Lns8K z-5~w#shj#M-QE3*%&A#xdyAlsYDV^z7HwzX*DjmQ<|GBrHAyf$cd$LN`)I@~UtS&Pmd8DUjTwzOc)!Id2 z5%rsD3YQfI`seoM$CszzmNBkJDEHp71LzYj3T7*u*W&TKfyj|T{HGh}!|yu1XEYft z*X!u#*_KE;eM=)5NVL8H`^}FT$+-{dU;0u1KGgqzKqHLrt#PwP9QwLwbZ0=2-tf?k zbiI@1o?RISimG-rg}8f^th~CZXlzk9HPHpRUFntEy0SdneM?pp)*URQ?KCRMnjN&z z*txU1;qu<3==xQKY2AgvQ4Q!xT3acXZ-?qubE@_etD(!^SBW+qEy^w7LHUF zZRpB&cb}O%s9tZPReK*Fu4+nKx~H=8iou+m;cFIcy6o$FmJn-%Z&G!9JMzS)q;zb^ z&0o`mxtS=3A?G(BBlKO2cJ8KOFI%Rj&`&McSBO@Zojt@=9#dwb9@n5Rg<>W})Fq$c z?0rYY@^2!zf@$-)45H7Vj%`FuHL^X<@ue-Xv2|&_&TdVct}Tn{s4I+~?(C9QXEsF? z$9g-tRgUZ}&fnY;xz#;-@v7v^9V=_xJ)#${NzL58qN>6zq;k0_ZB0+Hn_Fnra#PCc z-eT5mf(z1fim|vganYKpps5QI3Ku7(wHL*CPD#kGjV&Lm3JI-TW!aq9o8#w~)0$gzXJ)g=3!^VnDqf z+xXnIOXlW2wW4~{B7Zmc%GKA_FS(>-s>h6({ipuE&(E3Y5?A-vPIq>9PFc}Zvc0ds z-OVT496~B~KQY$Wmp!nryyoiRyo#+iH?H3K;f*cm#ybNtn-gP8uN*EQsa;zOve&gk z!}9(VVEchKFu(s>TZ$&SMwj;&6)lc(a`twO!E13dUK5;%UqM=GQ&xz}Y(%{lq@^`w z2D^~L%yn(4=^bm+F3nuqE?#uey)~w|>Lu}4M)%a3;_-q$b1B;YX~yGAxV|%ReV1X{ zU@?$zSNd8-LMQknzUqgpK;QEp)~CVz7^+%8hev&V4yW zcb5qVdS=E|CProiO`R5;9{xKbE?y>z4)t$G{j*@j{lDlm9CZ9NH>fH<&e?fJRBm8c zS!R@*(KWH6JwCP}-Pc(k5Su=KL1N$(y;E{^Pkcga{z9Em2d2Wps&b;8o#&@l1s9WB z$+V!fFgRDdyuvd>;;WM8%}uH{E=-E>b8}q~lOAYVl;rD+n}s5CBYnKWvm;`&f;_o8 z!#epK{&X@gsm}tT&v5qKuFuGu`<*U_=fm2kl7FRJeMwDCf+hB)m&kk?g4>_T8`+!& z4#cDG`#=NxE*H^fMt+Ee??Ukb2zAy!NbWOO*ENN<#3VMS&2e^)FJF=tSDiB7NE@o+ zYO}(eou)+>MJ2XHk!#7ucd0 zXENXaU6=7au=8{o4KcV>?O0mo9kn(;sov!6>>O9tot)8<>f_`-wPNjwo<|oJq$f;w zb@B)=j*qI!40m$&2+wD}aWuART}fO@XknYl)KwA@Rk1X=s_n$;JYs!l#=^LHX;Jk# z!GY;j;SuG@3xs@{z~p|&XF`|J-By=m@~zcFPowD%7FYUF9ACkq9zEzo!H9K%<8`tw z-}R={pKeIP1QN2)%7LBb`%CW>w^>X7S4_GbJrP6745OnjhTLCXWyjK zz|ciS@y^b3lS_j_Y766yhMBRs0YT`9PEIr9asvWOv!iIq!sJMQH@Cpp^o2<^ra7~X zi;_b!V-~o%EsRX^OQ&~AMwZ15^KFJ$7rmFi=^IPKGo!zIDjE;AD zIo(saImFSOtrLETuW{?=-v?wPi zy0s)SD6=LqtRkI<8!DUV>-6!7{Vw{DGakWh4IK3z{>#&<7ZaQ?I6f)1N>q`-u41ctfx~ zq(xht&yaCSVwj+>(%lVjgI;U&z&3X=aH!QoIPXOf;rRSh@3iS znwS6V>G~6ok!R+_2hW@t8b4=FY>sJ>W;KP0zFU5St*J7W`%`NSm9YA`cFWaW$2-CB)UI&xd;UipmWQD@l)V z?Qoh8Kg+zRu<*Gt>7FrDnsVkvhDOYt8RF+-&>c>wG|ru4tTKjYgiN0ik`emx{DdIy zIsS8vVb1AgzW#Hk_y!@sjrRjL>v3hj(#}UC-#N)Km6@!^$shQ4wwJBr%Ezz(v9^*& z$O80Ydya1)ptlC^oDn$3Rj->Hk}xkIWwy6htZzV~lL6`Br_Y#`oRPD@Hzr^PnducZ z#RoaN1N_pG68MfaRR-0M*c5#%^aEd^M8g^jjMoJO$FnI_H+|AfW|mt&PupCeencKR z^FhZeoKI$Z$y%a1VLvrnX%xAbu+_nh0Pg3-&IaawA8}@h?`}&wh;T0XVE}G1c>DNs z?IKMdp6HDRUl;?YvOgw;xvC!3qkD?{GyOt~Ty!pT!e*bz+Rzg1=A2TuY{kmBu;xXD zab8FOR@NFD;B9cu2`?*gQ#~q2_Ll`@`jc2ouF>3-<>DT@c-R=;-P2x?=;9t+vD9dN z-GzHY({OErhw8GRWLbLFy51rWRVAiN%e+fg)keBF&n}6Z8#)^|#rfwiFHLDHF$PTa z@Quu>Nl0obN%opu6qdYbLFAQ<-esGbVm)=|a&$4J9SJ#2CLfQv5gCJy_T)_Qf7i1nt`ud_rzJFvFKjRFhzEQ;|d5&iq|*xX28*A?WoY%AGjm@+p! zVA{f|bb8?QsI(v-m$g=>bh>bZ^EAJ>&}jiv>9mDv4v8wP3$`}WD=iV$>9fjj%EkbM>L)W7@~&TgN)Rs0O3=ae#?L4HQ_V!5na4eHqWuw&j}C!@O6V`}5=;#c zu|NE<64$?Sr=2aHU9)0;!*A{xuN^7$BU{q$PqkEO$BYuY8%k2b-Mn-EVebR;8Q-)L}T!zzRPnWJ*z7HA2g2jc4TAXJBj=V=9@(hbuHNs$d zIHIk!Ii$17XYzI0)0d4uGZa)37`~)`Fy6`fv8Vk`?Ws=AUXg*3t@ zN=hrEhpnF;#4Xxa;uh^kyTS$@+*yvj4wt0%hWcpJxxBhlm(*19o3u^CLw(_{o(1b} zYUBNk!cT8g??tSHIH$%P5B7Zo4A=9{=S(>K2w8>Tz27fBi94P*!xzKjQ!XfXw);kuyV037G@QGFURNlxPl(eT#1d+O zX(`Lyh4XdzEl;rFDEC|6HWP6--8Plhms$>xm-DEXZK6-&pztEIE!`-(sKU}X1h)bLAEOqem zR*HL|=gwa+m0?Nb;%f{Gi1C}MMrh@*RQ;7GC&*q761<3+jBiD2P8B(m$k~_Vb>i6UDwy9-R{#JkvkKpAawq;Au{?6C>yO zg)EpdCjgE%E}yp{+g`|a3O?vvVC@DZnr72PU7}8H-TCDouZ#0Cc|{+1@~d6v&N#74 zb?f$8U$;JFJ^t9@#SfAtq=Lk4M|D8wdW^ZB5X*^uR5=Or)Dc2S7y`8IRBlOYsR*$& zSC4vi9C~qc7y7@=-Lq|^KCXJ-qsvPZ z!PhqM^$X%S{kLaY!|1+K9UTXj=PzJj z43`4)j|as^WU`u@(zdg)@w#oxsuMYPb5hzaX==QFn;9SJBel05-@7y|bNS`RZ>da~ z{DBr;f8dgy)TEBB2alGg6<&96XD>c%J9w;I^oBSlVOCd! zjqTW#(R+Mtb%epg0P&6Ozonz&=5=}0n7ZuBhQ{l+FRw}RaB^pXh0CvMOIkCsEVPWb z>L-We@pn2C$1ta$25wZ}X3#R%?8pNfW0N&V!F|Mh`B}TR`0* z&e=kK1C3-mjR-D~`IK4m4YV{{hGrXlxV`}fXVgK^J=k}vz} z%!ZjRUSVsV=2?>x+qYeRXLHIv%kPJAJ?XEHQu95ZZB1YQ$-M&<9ZG>CnjVsVFzLfh zB(E4BwQe+!!~SaC?-KZ~JIBMm27J}W|EnMO`g5msbZ1~eYM8UTZ}Cum&DCq`kkGMx z*XhM&+nYn(on!K9!YnV*Zx@gs=H-;t#bA>nFurX^6=}YvKRu#;V|7wbW5oh%32dD8 z)*FO>d;u8Xu5pA7pC4+#4NIJnXE#_}otVkV^23r_hGVDASb57^tIdCC@u|75t^b+B z{WGRTEIZm(sj3Yol4=cNnWLwct$uP>X;Mshcue-%I|q8N>5ZpkE+22Ux2z9fKTGq! za({*Nzal|6a+h`d-sy4NtbFcwI`&J&xheGLGo?n8^+5zD1i)i>i|W_FWo3KKdQ4rQ z?w#zfK)f4Q&vtuWP7Bd)P6VEfd@U)y!ZvG!DaA>%)(ClSM%kDm#{OwJ~J?uz4? z!f*&wi|&{%+<*3w!mWGaw`l+B_To4Xub__MEd||sYv*`)*6+BZZ_$SO1Rv%a<6){W zZ#%L$e`|(M^2j^+S8nd|c5~5B2`%m~NgHUbNDFoGn3^+Yeb=~n?d}6bW?YOC*tGYq z`nHD-w2-Lkp)Gsztsht2aA-$oQs6wyVAMUPel$NL71?^qB0_ST`-V&<*Ke*tJ(fdv zFIG<=THpfhE$;Vo?6t~+k!rz=_Jhx?t=`<8wLs_U?4D5Cy>@>!K4#)$!W5sHtClan z=hCKWo-WKcanXvx{(E*dPN!jmuO07jRfJ)$Mz*t0rUp z%C4f&y8UOm&;~mds?Napozw=N=k7{kh3CFEuyWo0Uq^LocpIc6ZvI0c$=tj$WHlJu zlt}x+w@A>+`&WBViVe2Gn(}$S7S|8SPD6lAKk~ zg*lzMnOlbHyqesSYWmW0R<@KR2D;MeSv%JCS4R896vy46S1e<(Rmt;Xst49>O-~pe z>?w^5DOr+Xos!y|K0myuYj72Jz!C-LFWA$t?IWSzxwB2)lrXW$i;!Boi20e$hYL3@ zDV~uyy>{%1>Xp~k`yht7;j-VY)Gkt(Uo=>>;)P`m5S#bL>#{rs{Qp2Ow~H5GE2#oKtgkPTl}zzh-E+;ImO=g)o#SmV^n zjd!d_?y1R~K5Vl7l;BtN+^W){iWqO=ob0UgT$tUFn?1Iq-oM!;w#=NJyP~xuG02sM zbUl5v%QvycNca7!+_AVXwq|hsmNYJ&@<_k*MiV)k(OVcCR@5oQ1K#4SWyoPt0jn%S z;|-a0WMBl=@Q49K)XHzT#93u5&-m#F$>i`YL6K2srk1Zh)?IO3zR&i{8~2&>rpzz; zqn%;2sYf6fzT}nc2Ir_Ub1r8$$yhx+&dXk9(n7_C7o` zbhyRW(1L20v$Iz%sn3aarE$GaUfUW`zI4rY+zs{AwXM9NlScYG z3PTZ^Jg_P?EYbddd*y05MhnoEw}B@(zr+|70p3ykHWO{E;F1BpYDN2EDkV3jujnY7ZJg6E zv^BqMq{cW44O+eB?v?qgnoN458d1`dw&cig@l=Dn=)~VIts&7h3t2lNE0(RvrGS6ow{kFT}1R#zO*lxgWgvbB!VMO-U0U(Y(SB&g?m}ypgcXGr26?Iuro^0XbWvjD#_f^mI^sHQeV^9CpjdMN2J)#TR zHyn=1+r6rB>QomxGX{qg8m}BE^6;3Nw@&x;OyBsKvop-Qt{E?wnoyU%pl0XoP0jaS z-rRK6nYN!RZ@uxrP`2f%nA(xtj>N&fCZy)C-g>N}^4itK;C&^(a{#uturJUnp-cW> z?2FYE+m_d6MYww{Z0TR03;SZO$CNtQ7d2~YqG#w_W87m3T326LpT9k0R`SSwd3)Bi zc)7V4+!yBc6{q*Nar?r3YWAuH@pU6xcjxq)T5^LL_i5%ubnS{QyK<}_mt41hL#ruZ zUi>^i@@ZV%Xiiqr+R>$zk(0~|)PvjNuV5~ph)0BBq}k#!^E_SKs5GTbu9vUWfLuYpIh(yuO)?d^w z(9V-$sSrlaHJ|;wpd-kGr+AS5YV{h=)Rs-vZ-)LoswHOQ{eugqXM6P>d2N$;HBR$w zJuy7|*#5Q|In(B}9v?wYwze5`PTi49mIYY+iHoay<25ghk#%ccI#kzi?Tcg7eCD!> zvYik0TX&ex?5-@k^x*-?n-}`vVT_*$z7F*dGEM9cBL}rM_uIV>kPO0j1L2Fbr$?e6 zQx~VYPq*i-EcJKw?7jSSHJQ7>4fio-WoPEM2XJ=>laxVX(D%Se1 zqC;ETJYDBxv_vnC>{%LAI#{%LQ^f-EXhB!{9RHlI99p)jGAy8cRgLB8_+<&seq`$i znMP)3Ew4^#O!MP@Q!-6`o0)X4P`z?Q_)&Rn@E<<&{V*gVE zzv+Sf_pG(vI!M;j=S}n;gmA9jcdX{#t)JYrl+fpK+M?t58)Ls4dhKL4wOsQ5w`>vT z$=-u)6#xx0aR;F|49yoVSOwvz0Z*7rzp`%qU+#>%%xM?DGj4;9Skou27^II*zEV&} zOwT_LoAL?F3{Gv9v%XVfR%W*`@5@5S6RPuA~PB+HiMdCuvi+tWtHddVU;HG zgUMt?uokyVqikQ&6}mQ!Z_H~%n^@$q0n?mu_@4Pv&YzmC4`&;gw=s6EX%3xZnwwR+ zP<772vM%Kbr>Ei)`MKp(l1JBBcLi5vg%Uk}ri(7`HIdaOvM7-(#0h2V9sFF*8T6Am zh6v;@Lu3;o=W-FElj(qmIpCw@`$_N#{Bc4Z@K%Gn1OEgrf3MK!#2Hiv+^l@)z@KAS z&=Nj^N+fRUVeRi+lAFfZqKXNxY;GBO6 zA0@v|f^+^Qe4IE>f^$A4+^l>m;9Jo+?+W^GTXOogFYIu7i-FUZ@KKyK;^hLLo}Pq1 zZhOE1|3t_^;+t&;1sv`%U6qg<>@UziLAG$Y;jWf1)ejBXppX4uQLnY6)&b9Sz(=WZ z5_|%Goa9Y{FL2^#7UkM+j1(V=ho)SJz z>L$UtJSE(WjU6tZ`%vHMhWUVFZw2)lh3`25aITjR>AnIyPnN5EAoQBh*Saqp@KJL8 zB=`jWxN_PKS5@814*V0!8O1}R|E}&C2i(k~VC?1UXE@-;2z*o;{4sr&9Zp_S{$e`@ zc!4#K-$M&{f#7ouq{;hX8tj96bYB8qr1AeJ8~)Sa|8&4d$rY2}6Zqo_sB8GIihj=N z=oRxuo8SkZNRRGq(AgvD+g8~=2R`65UiT*ru2)85Keyv!J8J@e+?MUYU#Yv(LC0*H zFW{LNM>^e$fL9CpCzOW}8*fumP_Lhb{A;v&ePXjZ;GY9u!bi!;NpRj?5inXt7=vM9xL@*Y7vGG4yliKEL`I>1wWZ?oH0FYf3(tK(_uN8#;?fF2 zLve`E$1`?@Pi=Nsai-CS+-5D;-Nmmi{G4s)^R<_Cj2(haRKT_AMavd;QZP5*GIW?e z|AU>x-4y{I$X_;(vUwL{F+9D{kGi?ketK!vPpHKfKR0uOx!lv_ zS-<9r;)<>Hfo`qRf-1gbtUEaByQsb;d{f+IURLu3wF)iDG0k80dpZTUO5uKY=0Zf7bo47$zojTsn<#-<@8%6(=_*~yg{Bcq+37_{*i9fFForF&u_(!RJ68>!t z{G+675`LNk|1ha1O%8rOcHkdI1SkcZ&x21Hf&mW}{rRwB5&ezlM=8}K2NS#@J-9s(V%e+)Q-eo}GP=-(^)v&285SOtBK|AOvy2mTS| zAfhg`d0Ef(o5Vkgb8ne|OFenJ1OFbAA!Glu)KM1X zlzx#urVCBU^TSzS*5Y*T-2wU(lHvE5F6c2K1?fg_ei!3@-v86Acd>iW|I>J#c@{eR zHlDV|m+6`Hh6`CDiTcS4e|yGe*O>gpgIkL(nyNWAO@HCwb;^xQS+4m6&dcANy=~3X z@`wvEHzx*PP$g4ykcS#kwE9q)%;s!w1JNgB8yqIH9Bp>5?h{8F97et_-e%Wf4E!W) z4(|IfDC49}^ihBA6BN3#M8Yvw@i{=^^FAl>kHEIzeN^JV2DrrMeS-Hs zO`^}ofW+s0LeRIi^ZivjKDmnAWec;@*BkBlWSm@rSa}=YGuPz{+Xc}ig8x3z=PwwJWYPS~Ciw%0Utio?1GfiLIU6SgYb&k~>hEXIt)AF@3p z#>^bxZ`a-Ez#p>Z+5WBJ|4ob;iGRd)n~*cBr@Gughze#_Okv6hbk(2Kul z|DPWJpvy)2ygoLk%>U;LdwF=98Rq9K@EfF*i8d=IHwbtT^qGsn1G0lZj<+%OA<*Ca950R4Jqh@A z5^l?|y#+eW)|Yi2B0n?2`Jw-=A}zLS0nfC)&Jc0|{0a$IezYA19D0!r=(+xe_Yw3* zl{G~010ilQ^a0Kd0uJ9mHgJ5anGFc~0w46tY_Ml-FIvrHx1cZZ$yK&LaJZyD3BQm0 z!FCtms3pBu=xK@HM^fy1dNO_GC@HjT(eP(a;KPcz%yJ5Fxt`#5x?E3;(yoayAm%Y? z-;I)SF~*v$W?hxwN8p41I|ZMasMlk{&K3B8&lhk>pO1M-|1jAq`m`8hIzBH+`iGT= z#h4dxAqNiElfF}UfKR!;@dSRHkmnF76f=ReH_rer?ZhGFe#Oaw&&!qgM@X{JH4>le z8i{{IxmlD8`na))uP-J3NwQn$8sMvgI*SAUr1F!HLp|ot+r@eg`v<&zu`c2B75JwX zA-6gSSI$a&t64=3SI`mokWY$e_upHGk@1nQ4+K8i{a#x-=t%mUe@Xu^ad*hgSICXy z>y^W^;Y0&|9QfQN>=Bd3&o6@iNX)mp1V5lC_^cHCNPKRONc?f)Gzp*gXO6E|#@not zKGxH_gl?7iYslkb9TRCSX1fIclKvX>=X0DNYu#jg)VJB@2Y95lc``n^O8LYV=-{8* zFOvRYGE=mdGqD?c9d~IFD!J<1|C)`XOsOZPT>@&iAANS2hax6R=?? z;bWBEDC#wYvsIJuk=ybk0e=E>0~PB|L0>tHy@NFHIRwAU_c$+ar{71`D?WhB^)B~k zBndg6AU$Gkz{|G4& z{Xyct>A*jtoWPk0J3qWXOZ;P+JtgqP`n6H;d5rjp`f~oK88RIBCoxO%{>=F|>ue7C zCzbE;JAS|6A)Pz)Fh(`bLz0WwIxJByeNpiapY3#=`>k_s+@!nEpi$?B#?4O29k|&X zI`uZ=t)Bjiuk7f$^^)dkx9aXb7kJIzQ!kh{<|oHTdAS#Fzi%0P?_6NZv9a9j(PQoG zJ@7V+^$EWK0lZyob)s!ZV(~GFvv|g0E;fNhWf%MV6~3^xbuG?i_>dsnPqp)omJt}iwJhd<;m{U777)A@WM*Q4B@A=jPbDgE2?I+A%*9u#$RfA)G16<&X`B&l}C3jB3zXS9o{!!`wkodxOl=z3G zy|2;#Ov8u18bHV_=s$-_x(R-^$Z}bgkb@8A_f8%6f50`&^%cDx*fzyvdq7udSPJ+y z4c?BGl}$;ttzh5lIQ`2c99qKyIJ5-MqdmHf!Lhl6lVL?9^*?s1KA;_6+(d!-XQ8GLUK7l_DtI>}C7p{jjIwzDX6xgPM&ON#h zH8}hS?Xcz?^rId4$CMu&bgtI7*x~Rq-EVsY^{TTL@Vpg(9~FGAAv zyvBi#er{_Q^wFE><$^xPHz;OXx`3lMsjGzC;I9Mxgz^QKo6IpF=-evcxyt7PU*sMT zzybfvvlk?u*PU@-K2Eb+MF-oGusYypl|l4=MXi zrWda3L@pIk7uhH6Z6V=YCK7IM3jx&S;;;xWX0i-)oQ;<_`F;WH^64j!I}#BH6TNtD+Ln#?>+`C zflB;E1Sx$C`_Ip;a)BI$k3r^JvGXeGCV4uH{>SSq@~VjbcT(^=uKZERNWewiB>V{M z3HP?IRz64z8G(lhLv{CZ1ka0Q= zgd)!h=nFX7q(sn{_`IJ>{KLrp$=g=yF5b_jjv7)P6tb6at`j8u2=+Sc_$&3Z9q^ON zucBPEA?66KyY3M386{>3xAyV=Z-=A4p9+2?KIcc`AI99v>5E(-g3g^99Wf_ra6aB8 zT$>Y>+14VSJH!EBLzdglI_Plv692GrrJ%nP{+)?An#=zSVcUzjTZ|PxcN^g0+#~RX zt`>b(>ev&?>!Qy}IG3A*4=K+Gxk)&en}i>MJbAsO&gXNngdamTd#;x_e6x_Jgr6i% zLT_|icZpmfSV{gz+t?o8Fv$c(3Xz$I1}~yNRKLi?x!w^z{~@=?w%(_jbO!AL4 zs-E)?y6_dLOU36v$7lHO@O_A=uNB`TmoYwL!~>uEPV&WP_$Toh{zvZb!}susY2R~S zm7d@2CO_+Op9?<6*gp$jjh?TB@V)S%U=6S5J`Rbm9uxTS;z1SYL_}ztT5PpvrZ1r~_rw4_cZY7PjJ5f$7d=wvvy~js1 z_*B~+fM+7s@F9W!mv(H?- zjOERpk#Xiu{%R{(0_8E|Tr&xu`|wjFeKvg(KKJFK2lD<;(Qe>d(&w=@65mXf zN%%aLLE@W9mcSSK91(DKA5<%8%r^NVpUVH{rm!#)DDKA0q7PTC^6*dK2s*!yDA>I^%X#+FI)DEB4-mT$C0aBo272wOZYWaS)_nBtl-VB7^rmfJazs*tn4I z7aDvjc0G8^UiIXdJ>Wki@C&TflVhj=PZ4m@FDL91WrMYo{Z-WOAyNKs<`ElKL;CN9 zeugCj`5htO2)z$2tNTRgzkh1*W}*Ln`};FoF5>sF=lJjcw-_DXzkq*{SVj>8bdlIH z=@S)te2d^;_(FyLxkP-H{e{mjvcLSdmqiRU0#Ek=;K1YMubUB~Fi1^xFm{=x&>BYY%;KEj!5hu)Tx5eQtjTam~o# z6q*b2LadUSF6I?b2HwNCvpWalCrEi$`~6P>{**WalLGkH+VB4%;AgDgoTvX!tA_+# zFY7nw>HpKJkHp7#o@2NfbmaIyr9MiQf)8$A-KbvzxSTIesohEl_~GOKJHrY)KDmwr zl5B~uUZ;<-(TJp{rWfu{_9xjYWO-I!>11X_lZG_H}IqW zUVqAg|GsjkGDD-EYMwKPe}GvHF{+p!As?|<#p@f4Jt@R)qkl}6 z(_u#pF23h6wc`5;d4(GI-n@_(c~bev&L4YCzs6DClge%fe^~~;cO~(!SH2=xkqh~L zs^>9gLcWOTJqX)Wla~|xG8+EN%EzQw!+%o$jRXH>toxib{0zfi9Qdy&pO9(||6~1O z2mUL{J_UMG)PF+X2TOhboBB`0X7cZOY$lhFs6S#oe&I1{peyzDY4s8w>j}T|_dI?K za5;~kR;v^haH-#U|C0Ep)Tc!M67#;k*MWaZZGsNB|8=6;@!384SO@;=+B^b$-8|7B zCI0)^Gq08WsQ2r6y(Inj(SN5q_~-pm;(ve`S>7Kx|8MIrb>M%1U7{a3K9{HHj~t)( zN5tX_c~6q7Bc_`7$7A>vZx1P7%;)rOF@7UNKRv~UgnYpjP1RSTJZLuHpQ69=_E(au z-w1z;J=W+nixzUB)?dUrz#eOKn*Ji%b+z?t^+RFr$ob~9`UH9rx0^m;Ka2L3^UZ0s zQ^Zb)`NY8Wy2L-FTE(8Gn4k1LfJ^*S>T=3DJH6AMN)i z!Kb9pM;Np8Jud8|NmmvXk zuNLhzN_)h3PelD+6!tyzH}FTvF%jb;@l6i=Tyo1Ke7-J{__>N$4=56!k5@_mlrEAC zgKt4!w1>n$r7jiiA@O}2_$SCVc(gQp5xXw&PbiOx*!8Qe-{_I?#({rYeNnViqV*H? zMfG+EKd03;(LeTBzu_?!fG3H1omS2rN1@lOzBIhOo`A0A&R@lPlZiug*%M{m@7 zI`B`cSRr$K%v+zRyj+QYT9xv-&-#n-XWG}Xr*S_m^s&QlAnhftFP^h?gN|JHj)P8` zki#kULDFi+7xI+$(kV4u$W!7|2mT4fNaxz|MGTO{KcQ?vZWAi(m;3b!&Tu8evw(~n z_VfJqcw!%ZEDVRw;>E$`cz&=@o@6$tcN~7-w1A)K?=K0PraCj%kd(^a^`+v#f4=ov zC$cQS6mb37ubmApNOYUK?NuDH<|qBT4=&B})RA9pcPw5KTRXUZbBb5i_I1lEqxq?S zvL6T3&iy5B#ZYf~6yYbW`Emc2EAFlpa`m%CL66&G!-L5S~qmyh5v)RN;e0bL03b9>C88{#OG3TM4J1 z3iuPipA^G|b>Jfcz7qIv2>kCPK8fdW*ptW4vnO9==nsIu1N_PM|OAW@e6+T0RN1j&+T3CNzu|5#g~5g3-P7Ds0{QE3i|LLBF5y^EIdFTnGo4ZLH{!e z4-;_Pt=8lE?}a`5HUKDBcZ%cN?u8sa5%#cHe?e|iJ|)&@-56h25Yb=3=SJJ*pdW5s ztS0mMhonn7yXbnYrwH(ReJaa{+x@c%fX zZZ@4gYYnwDlJMFs^>v$S!w8E0|5`Tg4M)AvE;!@NYb{QE%KJ^|No(&WD;%=vGjP)5=h@O(PJhHloS#1O=!D|{5H;dbg^mi4Nf;U(ABuixPo+056gGd!$f{e zv}WVC!p{?ca%YHgwOnsJ@s2#X=}!+?UrPBqeXZCsh5F}OK0^k%-@oqkX1pn$#H!WS z+vt775@HGC8Qs)skf8*nd#3PoHhoTg2<)nx0b0R%Y$@um3>*Cjoy7^uHGPV*Mxift-ZC#(kJmAg2HW!~Ruone|9Msd1(o@+_O)p;6A3_i*7FD?fK1D<$V15b~COC)^gN z1ls8^?RJKEy5GWzj78R8oxXn~>E4-@W zmQH%a(#-pTec$RL^iVXdnUuDC*zdqku|0SJb`Ielu>gW_4 zIkx(d4~W%+x4+n@8nqO_6+6ifEc@#R&H-x^uBsv_#&oJ40pWG=N#f6 z|EtF*`A%^cMWFW1aL+}I_O9YRM|;;nKhVzn;+E z-EeQ$ZQ8p#c7=Ygy?fw<$(P#uG-Vq6o=hRCGq}qjA=*1~*pemMJ5{{Nu=dWBh2%2r zUB&zD+PhAPAg^ifdSwAQr@b4LEILnncUIhJoA&Oi%%ID(cQ+-7ZqnY}l@@xV_U@t7 zqNhmSrYLT#R(qeSc(aazp}|qVp3c!uzwV(GYlqE!OGo_*hlcw4d;Q{YC1lM|*U;!t z?NalgU-4*Xzqwm}mm=XQ6DWR@aO!)9N6bTmesNJTF)_(WNPazm7s>G?DM`c6JmS~s zH#*$e(>u^PyxebSiB^7;EK2^3>K+=%T{>(Y88vqf`r((o!=ocZgJtIK-ocUH9>1}{ zp59@<(WSk9*(*A`@zB1B@SDWU($UcsDbdlZSFeuh6j)J1!+p`H6sIu~T~?f%U$H1Z z5^QU%O{$YpfQYa`oXGG~dX!E)JMq>H*a~H>G7N8EAMQou-xdNkgirlSFFwVgH^$;t zhZ?}T@NX3VYJq76EkEp7a60|?)P3IXQqIFqxhNIC|3If6by_qf5T-r zfL({BLV6>hXa*(Du`H9-)02jl1+^V!8XLko=cmv{1FTpzYkn$PwyX}Xkgh!R#sO%;TcZVLpsetd{HM>T+ zjHoz?|1WsLZbiiMzm*^1O};|;77<)uDZ7;8*fBT*ZTvOSDen+H{KOx@XX%8yM(-ic z$cW&A>&e`3(gn8=!pHwNXm86PPlNy{_tVPy>deVS18%?B{ zEG8|a6=xsYNeAg9U8EalKYGa$cxRTv!@dlw&b^APCTqxA zvW~1L8^}iNeQZW9hpq4-Y$rR&C1fYLlw3x3;T+N)vX|^5`^n|x3UVc)0uPXbLloFq4p8_7-NW^xMtj?=ir;x=+SxdZY0cVQp#9&#_a zkK9jwM;;&#k~8EX@-TUXJW3uTzbAhnkCP|JljJG#GOx(q8+E71{Y9rxInTB7;<#M$>5q&7@g0o9575nn&|# z0WE~>Tue)7sd76lqvguyw1QUBD&-F4dF5I7W4n}YS`CfyBJ|yJ$_vV?*aLW3c?Ej+ zP31MjDc%Jw^)~!?Z$Srs0UO5*y*vP|HAuNeS_z%TXNEE8yH(I~Ym{}EyVm12u?@J( zcN6>zTVc;UOc&8wT-H@j8)&0qQLMBH*E%kyEsBjOw3W8uQlk#qNxNt_?ZNepOK2Zm zO3koBepY^=%V|Fypo4UXuAnRFFdd>cyXbDZhwi2O=ze-Ry@Fmzuc8O&L3%YkM6aRO((CB;betZhM{vXZS>+r( zMvp81P(G$7=t+75y^-ETZ>Fc{E%Y?KmEJ~gr+3gh>0R`0dJnyq-be38-l7MTN9cp} z41I_`tbC$;N*|$*(#PoU=^yCh^a=VT4st(DpP_%G&(i1U^YjJ!B7KRzOkbg|(${b! z#T)cZ`X~ApeVe|6JD}gCf2QxzztH#T2lTJ>L;5%Rclr_i2a-2^LO-RS(a-5W=@;}% z`W5|}enY>d|DxZ~@9Dqk5A;X+6aAU~LVu-a={ahlR%&AkBaAY}RHkEkWDs&<&di0m zGB@Uq%vqjn3Y*HNvFU6E^J3o2hs|WO*lae3&1Jqwayg&*A#uY37Qhy=Ko-P;SqKYd zVJw_Qut=n}k7h9}mc=1cPy#dJs?kK2#FAMGOJ!*+9eFb|Sr*G?IV_juv3yp*3Rw{= zW+kkYm9cVG!75o5t7bK95vyf&te!QnM%KidaRG7*Yh`V$oprEI*2TJ659?)1SRY%; z%xoE3&idH^8)QRl1zX96*$5kDV{8>$&DOBBY#m$AHn5Fs6Wh$Tu&rzx+s<~dOW00! zDZ7mAV!PQMwwLW=``P8}3U(#CiXC7F+12b2yM|rMu4C7;adwy;VMp09cATAHC)o|` zMs^dsnVn*{u+!{Tb{o5$-NEi;cd@(KJ?vg~AG@FZjy=F0WM|kz>|yo@dz3xKe$W2E z9%oOmC)rc%Y4!~JBYT!T$DU^|uou}&>}B=}dzHP$UT1HxH`$-qTkLK24*MVWF8eck zkNt(c&pu#(WgoJ?vA?sA*gx3E>=X7W`;2|g{>i>zU$U>**X$eiE&CVyj(yMm&3<4% zvY*(`>=*VcJIl^73$rqts;C5)88cN?b*dg`kepO!+*sg>(>d;{hw7p(&`XLYR0yRKgh`afM)L=D44Mn7WxEi5Gs!?jR8iN?< zI5l2PP>sq@stK8|lhlg3vNHWZXZP^XpvQ{dVe?QA4B^q<;ocs#sH=0>ZF%2tZ|`7# z=U|Vyo8=GovEIQxUH{Nv--xbq>Co_?ZbW};W!5b+_YHKis-CMr{TwG_;Fgfaay@?_TT4fzt7X2`Px(C zCtl+xUaLpER$jbTUc6RbyjEVkR$jbTPP|r5yjD)UR!+P|KS86LpwUav=p|_M5;S@V z8vh9z-2{zpf<`w%qnn`dpPqO&WcZM&G2-H)(vDG(JrlpC+x`M2$~4@cCd$NYu(p)XGcL=p}0O5;b~> z8ofk~UZO@XNvlVaR*xi&ev(E%Nu!^n(NEIqlcd!nNvlVaMn6fTpQO=G*61f|^piDu z$r`<6jlX2=_t_eLwuYar;b&|3*;@J8nmn^LKC(4Fay0xL4L?WwKF9vOCZ8Ow+#Idk zT&=#j+V68U`nlTg^R#Ea#$Ue1Ux7xiK+4+~BfmFlzzra)Qho@*yJOv+kiu&Ox z_`p-}fv4aDPr(PCf)6|eA9&`t3m?iz_Yfw4u73BGV^Frky{q8M>Ftqa#%VMY6PyP} z#>A8{toECSJM}AiN4W0H9~&MLsIgk{v9Xe^*jSTuFMKxxouj=y&O?K}z1-2X)NOPr zrWpA?;=07V%Kq*)f`SLNFI>8Zpr@ny2ge4S1y^8ijVtDpfzHluK4tMD3-SwuqzVcO zge39IGmNetiUOl<-EeI6!_UK~n(5u<;qI}4CH=i?9J7%}7q6&enwmO^_AsV{(O!La z)W|^h3Vn`z~Cx~3W2$2BdB1A9ImJE#zYj0=*i8o?iBVJrY zOUPHz9ujfTY$qto7+YZwMU1VGvUG^nSu1C3g_A6Xzlc)s6H&<63TLehylF)MNtS>Y z*e4?+ut%JGI!DZ%Lu<^P&co)xK2d_ZXgJ=i+`N!QJ1h%Vd$W(4yQkRSIc|UNlF>=s zz|royzNpUrQIG!4;Xar{yn_N+h>rI?L-$fM|K3^H6XH!668ue9BmS0(zsvbwy?Bq) ziw|+rCOVy+*+~pIIMxKg2^I<>=x8G`CO!HFf1qpe2l@top!eY+*c$?SPP}FLi`KII z)meyKzHyn0ucfdBP{>%kiB_ESHLtL~OBU2EA3gHXCm-lnoQW0ku~I$+W}+TlXe1_4 zFEA5DBcn#LLGhyIMRgCV)%;H<{ZK%Fs!9`aCpy=cu|A4X@VnKco2LlI>`D zmrlp4AzK=;hEDm^XA4sLPDwF)s1IFpxuH`&U2`Ye!nJ$iU6dTFspZ(19B|MH%UItd z9)^6a3^=K|!K}}hW%P=NOFryYsf%2C9j}Ibt>j+$)aOfzz2f0oI8nB1-^9D*BTh~; zv2n3(g_E?ATi>J)u0<2Sa$P#{t}hlHN^ceqL$Ss=l&|2tSaNQb(ka$>G|Q(;v4eeD zTtdyuTuUYhyDpn}cPpL5i5nk&c5Mt(oLl*@q4~qDY|>Y5{gXcE%cMB^#X~Ja!D>JL z=qu#!2j%Z8CjG>1aMA~Th5Y@X6z5>)ilLGJ)83iDS5aj9zq;xsgzO|CgaBbtA>u|b zVG|L^!oJAj!Z1E@Ma2!l4M9|f=lF5daoolgMQ0QRg5m-yA`(P2$gW`6lY4KH3-@MI z|2~KQf2+Df0s_hS7$44f`}6CnuCA`CbLyN^Rj2!QPnmqm7uTa_XM!1f!j+ZZSdB=sGS% z-BK4f9osd-nFn;uaOMGBGn{!q*9>PKkkQSVpJjAAJA8~&_!K7?>vZZ=r&Gte6i#(1 z9P3ax)dXQ)%%#S_34Y5TK}lYShw@1I$_j>b*+uMtzP`%dht8z;^E^Qy6-eW zI{iFj>*3K$}5;6OfW}Lx%Db@ns3tMa}TR5 zHusPUq6XEwZcx2O4m$k0L5E&9ysphrBkGkgqFxyz4l5&SMBPQPBMvQZY`rqZ)+=M| zVP(XQJ@mSZ>+(jsM%7`6V^K{!+O?<7iR`*7;_De!C#SaMSX4Ks5o0Irm{uo~YgnBV zj#V}BxH_BaW^{zq%~)4jd_6_K|UCZg7 zs8^_KG|h>)I*VzJcfoaV9;!o`o|BF{2MrpV4)fH5*gUYC45F zX3dE^M$N>dU6baXsN;5|v1TSY;SgiyURF;m;_DeOb2h%7| zIgT1vM@AeI!s~H_T{h_!b1t%<_9+>!RCKQ63^E51xvUn9uWFE9H|QAMag82#orAIU zGDnWkZX=W4OnaSbTV_(iObwp?EUTKhHF(Bxps2y43lAGI;ij7=$YE3E@Tm-VrVce~ z;*Dwy4l1`Al|AvAXq~yX=s5R8?Qx`;%Q{VS{bA-Hf|^XEscx8wCAm(o+DlDh*mb%Q zO>T6mHzVBH{j=o_Qx%it==wy(9d>!NdyOe3+C6CwB8@lAL`{L2&QiBarn}V6beGtf z?h-rGU1DdtOYBT{NX_ixx&Yjzbf&X}?vk0|x+;BO zT^{b-EVHZYBIxRt=PZxAWS;HJ-7@)jx3)f+XS=S6v)yts-Se65^_i|~BGb*E<)&x3 z=~=buu4^RAbzNk+E{iO;y;-^87aGGKew!0qXpD3CZ6;`XVQtSfy{$GDezBAB4kx(& znj7@Q?H2s9H(b&5%G)o;4T{KXD)Rcf4v&mHr}bSO2TMk-LlvRnPDZZdpdd6*sR6pWBPsZu!}6`PptSX1nKe-1DwOH`8_KX6CrPlH<~m+kQ@U#ky}!;yS${r%ng9eK;hb>xlE zt>1A>a_rKd?be^|*6%nfIq%Y+?be^|)}QUxpY770?b4s^*6+x3My?~zgf9J#Jag>Q z@5nR9ZvBotbL`UZI7m5m>v!avW4C@st~qw=cjTI5mwv~wnvv@`Rta7D9XaRNrQeZr zj$Qg4Ip^4=-;r~UUHTn4=h&s+k#mk+`W-pX$aUnL(52szYmQxd^W6IKTzVZj=X_6G z0NNL!#k*^lT65CVRNp1Dry;*frX$XTuG%=_$g!gqnU1)1$#lex&{Rigs_T;JbR(gw zu1<4MEBAa)H-As}*by(Tch%St!!DUU-0R(SWM)spX4>httEXWL$L@7KTsnHVbU5Ng zJKS_foH%x`bHtP5+V;C<(orkg>*jO3v0bv9`&c~xXV{GU+G!8|XY=G_wEOUr>_4~2dGN6*9gF0dr_+U%lQ(n>CF#Ee z=x0y$8SA<$C*MFCF$2DXKt6GDN!AxMn;W`x+&^`s7Ipa zMde4m6BUT6jQTOUbM(mQTce+fUK(8#6B#op=H8f>V^+n+$99b!6FWQhjo1ybMX}yE z5tk6xnok(?jvEy>CvIunrns{B==d|^2gVPNzbXFF_{GgSHXGUO)@F}2Taa*5!kr1L z6O$9$C3Z|aJ+W(IkHkKSS0vt$czfa#iLWLuP5dHpOJXQVCZ#70PnweSbn{uwzfGQ) zysgF17Ryq)q`Z`}IAu-Bu9R zRa&dwt;V&wz10(~7Ps2aD%9$S)}Gd}ty5ZeXg##`t*z&@Uemg|O+uS4ZC+}#JgsZm z$g~w{yV5G#dfFzpO>aBA?G|qrUi&HSUuwUueP#O}JEV0;?=ZN-m=2e8nAKrHhfN(0oOJR@!%rH2(zPeu ze)46f4CQ(B-W~gQ9N2Mq$1xqpb)4BLp;MPmD>@aYho`5fKb@YRz9GH()YMbo=$zI$ zy>p+=mv+9l^UIwpPfI$j+iBxZyZ7`-ryn@u(lhQoGwIBE7-MpDL>j6m1eu3frb(Dkma51oDc+1t+kK2v6%o|%_~mf|XMgYL-Z%7~ z(%XBk=iFP*eXLJ-pOgDM(P!~_9nZ@-@165D_08*hMc*xbtNUHmZ&tr=`zQ6E-T&q6 z#Hzl`E z?!?@Oa^K6{kr$D7X5K}4GxA=|+mQEl-i`q`4R~l^yMcWMt{b?2Q13yP3?4Xm-r)Qp zlZV_jWXF)=A^V3W4c#*A;h3~ud%w=FIYY8^ZBRzG~S@R#yZ#DZuPe-`Dgo7-W9!u ze~6CYU-1v}J(wD69$099YUSG%)*`#mdXv11?Ug**6(gd^=|#Vz+4r@p#ie$Tvi9*T z>8fD97H?E*=3X)qTGFy8^V5!wY}t7 zj#b&r)0d^9Ic+VbttGUzm^SXEje97mxDh!lN-Br)arVb>qySDV=Iz#B!G$GOnEj@e zVsEfo+pFQo9BL?l3&s3j@(XJi7;Asde=~#D^R^#Oc;ST4dc*d?`EmBkyz?`WGgX|a z;7lcFD&W&O@M#ll>Z9PjK;y$V&3F5hq|Wl&a9bm_)YQu?CHF{WTyCs zeTSv&>2UmRIQ|qI-)5!T_gI~YpGkTb`z_vHqkG^k`uJ&NXc9f)rOnsT8;{Z(^Z8f! zG;55AqgVb+uT(6gZ-ZZZ#Kc3kXVMSJNmT? zp7`KN2|U@4+$O+}Qh4wcw0#9#8=-3pbZH6mS%XE4HI)A@j3rIea%c^uJXPG3R_YeV z*k96~1T>|LHhqnTm+97vN%YP%yO186Lyvt-k1eNF>%@DUUrGz!r>8&QS>|Q5;v@dW zvcmS$drRrPQd;^sE!{>-KecY8WzX_Wi|5hom!NeXcmpg%vfl)6A^)4XHUc>*p$2_r zF%lHR75liNoGSuc5#Sl>O0+l(&bQ{eE`&n}hrzqC_C}tuUPa4FX<4P6&)EQ}0aLOh zrN+A2&gW@tr;id0g*tt?Nk397(k<^ja+OhQh*~Qsx13sQOxcu3`DMqbS@Fzu96Hk# zYub$V4}xD>b5@|?pK#?W+Ea>cNUHuA@FtrwLeVH#fgs&`025>;*$d<(3vMzAJ`{8JMa&&=D=3;Z4~+zhJ1a9 zz6}zk2M(ZbiPSI=eTzlk64AFN=vyp&X-2zy!<#qIx8~?uZ}cq|K3$8x4MHxXk<0U} za}QJ?m&>gI{JVaLok6et7y1^7zJ%lFHVeinKk!&tT0UO_CL zv3NNeYaut4I*x@swyY@nb)S*&&FD^~tFvD8wH$pd6(3_=R$x(9*?ZB~wP@WY^z|ER ztksGz@&>3Wj(o@}BeJ$Y;aG}N&g?g>T0xFgc02lRn`u?tA=>czA$q7~bTheDA^kDv zLNsmKXLJEQz(#z8#_vbt18Dp{t?^h}W(L^EMOcHyT%$|)+O%*UHSVUIJ+!*g{tP)R zK?e6y-%7^v-HhRzjGhj~7LH*A9?Lk>l-!??`%7}IC6^D$+)2*$jP?O?%^}zNM&^p3 ztj{QGCpGV*=5os1NqMENb=cLYQF#xuno4_}+a5n{@zIujw8cwX)-{zGF| zyCYE$83{5st|TQ4P3dCBr5g036pcthL%9n1sYJ`Zr^GHuRxdD?V`sDpBUd?ESB}<| zqIKnHou11&<5WJj=5?`>aep;>TWZfE_a3V?x;lh;`7qEJojv-PRol7{|5Avibs<`( zu#&Y(xpi zqZPmWXwvxEOylOU#~yo*&gEbK45d!Hj_;c9_?A}J%Gx!2{q=lZyeZmWiS}2b{d$F2 z$-I0yE6e~Z%uku0f6WT>BUa*z7@6N>hA9tPi6+E?ToK}m_uVVrCC_HASj^uc7IMWR zMvAv6YccZ&ol;6lIe98bDKROPCJ!Z(vR~KZj`Ykj82y}eMkV&Ag1HIn1m+??*B8*Z zdEW8N^`El>{^jl2Z#DiaJZ`^n^b>6&&V~%&P@pIo_OU`4@zK?zOm$&i9ma^a4b8P66d>A&ke`=8F>>!)Z>Xv6pFPsBO@vF>W==Hy`mH_39+!XP z&u{!W_J56kD##2)N z8H8Wks{Ob2{%_xdaO@S^@x9y8u$BAGpMCt^x#4(|e*O1m>b&2-)Ox$lyaywNFI_&R)_4Yb-t<)Su8Z!xC1Neu!2egz0vyZ7!IR*x z_Sb5l{k12G^Ue8YW)lB2PvEPW$yRf|#oJCK%fE{R`5NKtd|x*Kvksu00gZB0g*#VpcP6nrd zj-V4rx69?JpfflPoDRBzvq2`v0@N?N+hwu`=m~m(b8Nrt4bG+fK9qAFVPC?2g#8I~ zxCUNH+AQId914bmkpP}acqT6Z7lCnLJh%i*I`F-mNq8@q1siyGQy7td2^Tgm~aK* zCxj~rS5e1mum*eq)`E3l1K0$%fg-R2>;ij0G4KLEC<6hoAA|sJO;Xk1Tkt*j0sIIK z*kvAJ`#lnP0AIl7Yq#Bb!vybO6TNt!OmBNT+PfL;-E1}IT~KEca$dHxx1+_I(c;Z$ z@n-pVJ0M>p?R9&*N&xM_$zY(pS&g#;YCO0ETuRzhyI4&pwC(L43n&m}Z}#v;5x%vX&p7Kqo#G#w2qqcsc9W=@i~Kkx%aU5%hsR`NCR!bB=8J)4!i(f1arYF_I}k9 zRDde39l*OW;<0e?*b+as#E&iUV@v$l5p6sC*bYDTLfZ;Iw!)8n@M9meP4HtA{MZ9O zw!n`q@M8=7eBC_Wx*A*qt_9bLc=XzjUi;B&KYHy)ul?wxAD#50lYVs4k52m0Nk2O2 zM<@O0q#vF1qmzDg(vMF1(Mdl#1cF$ZG1#4d<`tXX8UqQnD9i<486H?;A{ZS2HhC)06QDN&IYiT0qkS|dl_q^35x`yquonUBMF4vdz+MEf5dq#!6KBt2l$^zAG>g$_7NgNDMx$9qO9E&~04)ii zB>}V~fR+T%k^ou~KuZE>NdPSgpd|scB!HF#(2@XJ65tEkVZ4_p5?st1BFBRzyeTdj zT*VtMt_IhDYr%DPC8JRlqfr$jK^0cN3Ts}4C9lGgSE1(08+0WjDnASD}X&?u1jhX~*2h+e4;3@Dl z*b2S@+rdsidlYR^CBO$tK{?n5g3zR?_CmE6s=ZL{g=#NUd!gD3)n2IfLbVsFy-@9i zYA;lKq1p@8Ua0m$wHK+6&cQsP;m&7plEb?S*PDRC}S?3)Nnz_CmE6 zs=ZL{g=#NUd!gD3)n2IfLbVsFy-@9iYA;lKq1p@8Ua0m$wHK+6&cQ zsP;m&7plEb?S*PDUtB+#(dry~17pTU=4r*u(~89w-c{AqE@nPe%zUbt`BX9Usbc0+ z#muLQnNJlnmTY9+Q_P&FnE6gIW64Iwl8wwkiWyHfG7l+cOxdV9*c%vEHZtcZR)dIN zO8iGt(=@0ogvvswEQHEJs4RraLZ~c+ z!a^u4gu+57D}<^-C@F-3LRwx(%L{37AuTSX#f7xEkQNux;zC+nNQ(<;aUm@(q{W4_ zxKR8JD_n#XE)oO5V1TBI^T8Bgv&Mr*Ier2>McTWBOGx{Wd@G3; zfKN&Ha~uH3v(WM!0u`W&^VNjkg73f&;74HFMV5tbCh=y?WZuM<%5fS%=dt!hRzJc# zKpV08MOghJtbP$zzX+>egw-#?>KDlj^s=kH1-rThySfFtx&^zsg}L%}=E~cdD{p76 zydCSb8|$>2QKE=ZqKHwVh*6@5QKE=ZqKHwVh*6@5QKE=ZqKHwVh*6@5QKE=ZqDbCB zJ?OZc4zOO>?Jd~tE!gcX%!#)%C*IDScsq0A?aYa{Gbi4TCEU&EQlvVe(>1Hi2zi zR|Ix|U0@F=243Ljd>IIU{Tzn~E1{0cMH9-i?LdjfLOsiNMlFf+Wx$ zoCHomCT?cD*~WOY4G9e)p&=wRgoK8W$Pf}4L?Vlj$RZ>%ghYmr$RH9KLL!Th#t_mN zLK=feT?h#aAz4L8RtU)oAypxyDTFkIkfxAz6>q$|8e9Xe1=rczkgyOE7DB>8NLUC7 z3n58CBq@j_1(Bp6l2n8w6(LC>Bq@X>g^;8Wk`zLcLP$~wNeUrJAtWh;B!!Tq5Rw!^ zl0ryJ5NQb_EkUFuh_nQemLSqngtUZ^lps=4gp>r4kRTEgLMlQ?MG;aFLK=#Yh9bt) zZH%eg7*n?)6(J;|2#E+G5g{a^2#E+G5g{ZZgcO93fFdNI2ni^n_e1o4h~5v;`yqNi zMDK^_{Sdt$qW44eaEKlb(ZeBnH$?9S>D?f`8>DxG^lp&e4brc=9GT@{Cee}PNzW34hKKkBA z-}~rqAN}p4zkT$#kN)=2-#+@=M}Pb1Z@$$I%0K{wpaX5>pPP~3@HNsX{3d#xbTRK1 z8xQKQmzHpR_?jt+H~%K{p2MTBouXMgMYDE_X6+Qs+9?`N{dDbw{{TB*hMh0N&X-~5 z@qvga*&F=Kbrp8J3_D(i9mj_uqTs3@J6)#EAf7>}*IdI0^}1^$X?pDi-D(23OhmH= zi)IZL4fp-(R?=$MVKa!=UyD6S8G1eT4B-o$dlAe9jai><p(sTA(>^$xUX)eHQc9t{l@2<}d4+zpTg3t-;Q%!OpG0&aJ`D ztub@g40}DC@xmFeyo2~OFdfVQkJ}sYk!-+6vcb%2=aEOxZS}m?nbTIAIc+C&m3C!RM5aA1(3H z5-)x1qZM9S;iVN``q4)p`shO+eduFdQb`~B=)3*2%uC;C{i>jkeDsBne(=!;THh+@ z1Fdrv@P0ph-w)6C!*4&l)_Pb0uYK^@2akQU+6!N`ZdSloKYaDWQ>~{J@X;sk=biQO ztTp|tHT|M1$OPSaTX0Xno1DeH9RC?S4i=DiAz?n@TF!q-T>IZP5Z_9uHD*6y4Q~+^ zc)dJ$!kQ8$5;iBT1z}6j3bX-dk(NbBeb#XDVNI>wU=P>}in03Pc+Q%D2tZj9FP)46 z(IAHNl*xM5FDaMxtY1<#+}7|{ldGTiBS%Z7@*iO})I9@+`ZYRCAQ&AUdVLxkOKfSk$UfZeg`mrwd z(|fyE8~a%s`{~7<>ORu{0PrZXPWH1-_8V<^g?z7*{sx#27J^0KE$}vY7c2qqgAc(+ z;A8L!*h(4S03?rfwqL^{g;>X1OE(Z|Te+3^Hr8h7Dm_|3Z&p~t?HYO^ z1UD<-W(C}=fSVz>8G?f$I2S_ZwcQFK^Hp%I!q}@zIi5=TbV6-&w7ubL9mshVa$aTZ z$?J9v6ojB41O*`|s4%ue+lr2M4Xq9_7de@?OgP%=73c6?cPuON8;9)18I4^>n$cRq ztza9Y<96Pkx}Wnk$e!Sv6-_~NW66ycBcrj%V;u4rhdjn1k8#Lj9P${4JjOw>7rBc= z?&6TUxWhDFTWv3L6bA>q$WR{rxH#FGfBIT<3E6h zh(AyMIp8JmvR$HHpY3W1Y2S_BvKW z#3C0Zo_J$5N{|aI2WcHaClLpiz2ZzbycfABfxE?UbuV&J0$2AU7bVC=335>?n1@&b zoW&cb$&YN5z^P)mvlrRei)`#gHj3en_SI-VO);`j0#}NWjZ!$W7uhI*Bl>PbF>+CY zT$CUerN~7oa#4z0l&IIi8_aoZyBOIhhLU0^*^6wHVDn0ljS^2M?vtd`*7me~4=vZN z-b1U4Y4sjjT}-Qs-By>=YVP*&c5d?0YTe>Jw0I9K-a`v(TepYS=~ij4QSo7|DyCJ% zw5ptz?4c#aw4|7p6w{J&e8Jt>BmcCboEGTXxUa}Pwsy>l9w+496}6SapDOrM1%ImG zPZhk;I#Ui$s^Cc#G*>}$6*N~-Q#mwN@!bl>H)cFRW;{Vgst~iBATydEqf>|(O^_K) zkQq&o8BLHGO^_K)kQq&o8BLHGO^_K)kQq&oSxk@_OpqB&5D!aG-T|h8=|GQ}oxo5q z9Gs8lQXjL7AhU@evxy+1R)`TR#H=C6tRaZUA;?G-V)PF(`Ue@ELX7r7Mx_uVeUOnp z$VeYN#N%AUNMFN9U&9Dr!#wIp9_JcH`x-|08bsalr_vLb-nuEku}WUYM8&(Fn`l!*D!yo zVg6Jj#;`g%)K|eBOyjS3lyvQ*(Ef>9-$bonLf>INieKW0K8UVJ#Nl^?f3E+b-kn|J zZ_syX_1#(RXK?PshK!#<`xI*Z2@epj^(8oWS3~CR>O9gL@*^Dkj%S^Z!MWoZ5)ZTP zjG+f&1Qf#Ed{*B1ti1DCdFLA+06yS&8Sf63<7Y7dk#h zv;NFyRi1Bk1C+QBhWqs)?$?L7UmxOreTe(@A@0|Q zxL+Tlhw@p)=d+5>XBD5%Dn4Hx$p=}xHtoYTeL;VaLtbcNwV%&wKcCfpKCAtFR{QyK z6o58)0k{Z^1LMIZpuWG+S*PZ+PQ{0>(zWb2Kh>_S7(tv8$7`AgWylV@ge3rK1A}=ty}Z4atqZ0^5=s$0bd1E z?|}CJUtQvUc}Oh-%fSk;60D-k)nEgTWZ^D0l+A3s!;xu%9Pl zst9ZB?}UwCLWmSAl`su-16*$n0;9FR0-OpugVVt2AO}#FB%h=n$(N+$a4-^#0@N!n z02hIAU_7`4U&1M12p9p#r)~zffxEy1;6d;w@K^AP{hgXe_=ZSPeE&tQ25Z0-}5_U9gnrGUAt?4~ z$Mzq(cBda0sSaJghm8HlJ8tal7VPa7?Clop?H26q7VPa7?Clop?H26q7VIr~8f}@| ziy@+&7!F2&QGDI(0{anc!Ax{@Cf0N&ex#ZBk!IpYnu&hRl=p&J;6eKl`4D&nJPIDO zA3@h$abx9?^IkG5a4U*ao7|J09}EYY27i3ls}!+vg^WjxcP&zIX}_S4L^8}X~Hv*E1F@elr( z2MNI}?O?*eh&glcNJs3??f2}v>=}k8VL!*3D&BsPZ(YT+>GO*~NAR5emYrh%#SYmI z+Yj2Dvmdo5+tGF$UrE#Xa?qD1_7HovXu_sb`Ur90PJPC{_P}NK+4g$-bi0#2>fueuPz;L{84|p3`#K)ilil&&UDuAfa(W$2)E)Y^~Qwm9LDuQc@@)y}wA8hQ^ct)Vlf z+{gK<-eEuce)q}(lY^QW!LT}q{&=$apZL|6IKD~7?|@??R@?J!pYDm;9{TB+Xm3Ag zzwS6zmG$c&pTz4N#-_hd9w{ti2_*iyQ-u=Zo8{g?yXw4vX)0iaV{{)*dm< zDzQq$bZJQ`W=N0ph?z26b`tl|_`5tuW{deUSLTX$9u#cFxAyjpxFuaVb?HFA=iBtDln$Q#5L@+Ntc zD3p`sWU*FGkyFH%@>Y4PSSN3nv&4EiTh10cQ|mbyioaN!FR_Ms=f=scu#` zTUlzVy4C8Yrm1OG4>euQwtA{Rst2rW^`Ls#%2iLOC#^y18TE`cL_MeGT0_;V>NRV$ zny)rnW7SvcD{F?@s=U_SYQNfV{Yh1*3hNJ zCTK?#lAS5CL?3j*LgI%bo8wqhJdMo1B^D#|A0Xk&k?~bX_-A4b623uf5}UmwvxCvjlhBsmbETu5^YOf=ql-(#>1g7I+*kO7?M(D6vGqVN_n@_YwqEFF8D4#!C*waR-?N>IUjC2hWAw7G(aZiuFSCta z<`}&kVDxgZ(aRx5FNdO+lf*FVChKM~#%S9GM%ykj+IF$gw%?&`r;G7M&+bFdhKN5J zeR|sH)5}Jm{%-W?RijU@8GV{(^yzh@Pj47~ns4-JfzhXhMxXMHJ}ol(w9M$!M@FBP z8-4oN=+g?LPoEflT50sD!06K|qfeh2eOhhw=`*8GYtW}f;&Y=zn~V-^(>f&h_k}u5 z@c#=uL_AfjGQ>WuLt?+yA#@HM50b-dt|<<_e=Xla1coV)SN;(VMA8 zZ>AZ&xy$IybfY&jjNZ&NdNa%D%^!^3{I}7Y`;FfG(df+seEaSkBhzinSknfHj$<6r zGM&b_aSB@0k#N`#|hbtLo&~$wj8!Z#g8DDU5KV z$)m@(RHH>L(W2jpR*ZAw(YN2TwKf{noRMxmR$(EVGJ4h0=v51&SIv!HwKaMrjb6o~ zS6gZSHns$#UD9ZmG}_hHXjfaKT@gmRS{dzXZnUc%+Vz8Ihlc%+Xl`_@ozby&Xjc+m zu;%>BE5=G@1Z;_>rIY7W>r~Oi>da^uVYIHP(YmHa>mtl(*v6V@O%!QnOl)IKLJxTc z7ClTu4|nqw!##|B%4nl9+Ng{+hRYZkBRn!zHWOhoK_&|+TgX;I$=0$h{<3!b*DOx9 zXM9YQ>3HFi%qW?R_GX9{vMXa{3Od|dw3K~hAM*5-ecAVy{n=;BY)a0NIb5YjQjg5T zUzcRYQ;!^o-!93FsvbF54koV0R)sAXMoWg{$xD_a5^bzWQ)5jcjWvlh z)+EwclSr(|?UZnbyo1v2ly?%JCZ`d`|(*N8!dEg&TVmZtPLCu}9Iy9z`2_6m9HLw6RCg#va9Ek6xok z=E-^R{B{2Q7bo9f#BV0&%lV?U8TXsXg>oTrJ^DA3i?Cm&R9V=^CfLUwa-KSmJbkgDVc5`Ya^_%36_zxQ+6Sls!lMSNfwWGNh2*HwYP5*J7GF&II5iF*HuD+w%xBnNsxF0! z32FjoFH@I`HdyDY*-umxX~{L}8qq>sr>>*MNoo?UV$MT5ne$NcRQ_ohqi$8VaxF6- z+IbfqW&V4qrc>q&HG}lK)!mdcQ|Wup_o#bl)xGLoQf8@HlsQ|?X8%X^N6LIaJwTZc zsz0%R$lRZPSUpVsC)5+v`=ojjN|`~ie@;CIz0Y(1Izhd_vu`cc95sjdi|R$I3%6)H3$V z)pGVL)C%@1)k^jSs({w6!Z)6*K2@I*UyYAES$(EHBfbV-d9wOkeNOxfeCEljP!$qi zi|;&HeW|`Az78LHvRbd!6W@R@Jy~s38;Nhir=F}fE9OypY-7JwZH4x2Y8zC4qrM?t zq>6}dSKEp2P&#d5JT_WX}u}X=H}U z-sYdOaUO;+(b8k_kJ&hu2$HzspR;iue#Du73TB_4rb6m*RD?5*#&92>O|)V(O%zQ$ zNuDGT;c0H}@h5wdNoQUvS}?x05^X)LJ*~;Z?38ktol*|7Q})bG8RIMw=IP8>RQs!o zB{HrZ)dyCa-Gtg-rq_h}=Y*}D1NT^`wPX|yXOwNq2o}p2TK|{IL36X|uL0e zS}PF67$^ke24nW|`qj4k$mNB(?Qz1WBWF5dDq|dThx$KFg>Jw8r8t4R*R*Tu>i@Vq zLf`0hw)1m*A(rEVrQeS9)1@W@%{PzP>y+lilsVGZ=oF{+<|dC$tK-3;E!OAs*$Dbg znp~O>I(IE!OopTEoR&Lv>HM{n)X(mm)hRmW@WDB+Y1hAoYifa<>i@hqL0a`*ht4nY zV9ZVUw+pl{MsGjwr}u>EAg@o%(vNhwn zS~xPL<;sC$1GGjQirVwFVQtHQ8rE5#!_R3cbC5!P5eHE}UrTJw;n1>Mi*RT-5}J}H z7TUCRi#`Zl@{zcy(@)%AtsMx18vS#Q>sxJyrdX`Grds!u=Bu`05x}u?QN$0mYEI9@ zyXBG5{G77F;BW$Rq3xAp^(EF!A8FgKe<_r!xm*j)ZLROlPlwDZDWQ(v`fB~t_RFzc zjz!T|>iYuPTGq;;&Q~jQ&E0c4#gP|BT67tjK0MNtP>VS1tIns(YmU|S94xc8?1sYH zdXFBON)O6wec7#x*XdAgYis4y=^5P@b#P==%WM5nDaFXSrbJU!pE9QfhwdHTXxcT^ z_3tQY+v1F0nRv9UoV=l9;2cvOywW^@Va`fw@IX^IeHcNn>U-;B=oVOp zKFdgrWvFw;7R&USZnw^(WyYcly?Cq2U{?C$#AV`IF_}C% z-=$6otY^(Jt5_%OaM*F0d)(R$YmaO5cXQKo+%S)o-(XRM&-pp)d3?@utQW19thv_9 z)+^fgY`to|hWGh(?R&Ns;Cs%u7FlmvZ&{12w|~wxDq6lP-vRHjEs;y*`|<<%pNr@^krxER<{ImvWt4FE_}IKkq6PAvdvYX4}H{72DTr z+t|KgD`MNuwu5aa+b*`*-F^FY(6$WTPa(aEN2U_?PJ@|7Gw*tRj^gERk2mG z)v$fb_8r^zZ2yn#2e$uV`;qM*@*g%o$)*q&WwA*%{nOL*Ft%{ECTtO^DO)64l!}t? z(2F}j1n^jYK?a9{4S2OSS^G&_XWei1ZOwiz=hkst zgBL1Q%wo$Fv)QtYho&0~k37)>AIUf|P5z#{3V*_HF^0Ki#wbDAF4;FKmY&$ diff --git a/src/kivymd/grid.py b/src/kivymd/grid.py deleted file mode 100644 index db310193..00000000 --- a/src/kivymd/grid.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf-8 -from kivy.lang import Builder -from kivy.properties import StringProperty, BooleanProperty, ObjectProperty, \ - NumericProperty, ListProperty, OptionProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.floatlayout import FloatLayout -from kivymd.ripplebehavior import RectangularRippleBehavior -from kivymd.theming import ThemableBehavior - -Builder.load_string(""" - - _img_widget: img - _img_overlay: img_overlay - _box_overlay: box - AsyncImage: - id: img - allow_stretch: root.allow_stretch - anim_delay: root.anim_delay - anim_loop: root.anim_loop - color: root.img_color - keep_ratio: root.keep_ratio - mipmap: root.mipmap - source: root.source - size_hint_y: 1 if root.overlap else None - x: root.x - y: root.y if root.overlap or root.box_position == 'header' else box.top - BoxLayout: - id: img_overlay - size_hint: img.size_hint - size: img.size - pos: img.pos - BoxLayout: - canvas: - Color: - rgba: root.box_color - Rectangle: - pos: self.pos - size: self.size - id: box - size_hint_y: None - height: dp(68) if root.lines == 2 else dp(48) - x: root.x - y: root.y if root.box_position == 'footer' else root.y + root.height - self.height - - - _img_widget: img - _img_overlay: img_overlay - _box_overlay: box - _box_label: boxlabel - AsyncImage: - id: img - allow_stretch: root.allow_stretch - anim_delay: root.anim_delay - anim_loop: root.anim_loop - color: root.img_color - keep_ratio: root.keep_ratio - mipmap: root.mipmap - source: root.source - size_hint_y: 1 if root.overlap else None - x: root.x - y: root.y if root.overlap or root.box_position == 'header' else box.top - BoxLayout: - id: img_overlay - size_hint: img.size_hint - size: img.size - pos: img.pos - BoxLayout: - canvas: - Color: - rgba: root.box_color - Rectangle: - pos: self.pos - size: self.size - id: box - size_hint_y: None - height: dp(68) if root.lines == 2 else dp(48) - x: root.x - y: root.y if root.box_position == 'footer' else root.y + root.height - self.height - MDLabel: - id: boxlabel - font_style: "Caption" - halign: "center" - text: root.text -""") - - -class Tile(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, - BoxLayout): - """A simple tile. It does nothing special, just inherits the right behaviors - to work as a building block. - """ - pass - - -class SmartTile(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, - FloatLayout): - """A tile for more complex needs. - - Includes an image, a container to place overlays and a box that can act - as a header or a footer, as described in the Material Design specs. - """ - - box_color = ListProperty([0, 0, 0, 0.5]) - """Sets the color and opacity for the information box.""" - - box_position = OptionProperty('footer', options=['footer', 'header']) - """Determines wether the information box acts as a header or footer to the - image. - """ - - lines = OptionProperty(1, options=[1, 2]) - """Number of lines in the header/footer. - - As per Material Design specs, only 1 and 2 are valid values. - """ - - overlap = BooleanProperty(True) - """Determines if the header/footer overlaps on top of the image or not""" - - # Img properties - allow_stretch = BooleanProperty(True) - anim_delay = NumericProperty(0.25) - anim_loop = NumericProperty(0) - img_color = ListProperty([1, 1, 1, 1]) - keep_ratio = BooleanProperty(False) - mipmap = BooleanProperty(False) - source = StringProperty() - - _img_widget = ObjectProperty() - _img_overlay = ObjectProperty() - _box_overlay = ObjectProperty() - _box_label = ObjectProperty() - - def reload(self): - self._img_widget.reload() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, IOverlay): - self._img_overlay.add_widget(widget, index) - elif issubclass(widget.__class__, IBoxOverlay): - self._box_overlay.add_widget(widget, index) - else: - super(SmartTile, self).add_widget(widget, index) - - -class SmartTileWithLabel(SmartTile): - _box_label = ObjectProperty() - - # MDLabel properties - font_style = StringProperty("Caption") - theme_text_color = StringProperty("") - text = StringProperty("") - """Determines the text for the box footer/header""" - - -class IBoxOverlay(): - """An interface to specify widgets that belong to to the image overlay - in the :class:`SmartTile` widget when added as a child. - """ - pass - - -class IOverlay(): - """An interface to specify widgets that belong to to the image overlay - in the :class:`SmartTile` widget when added as a child. - """ - pass diff --git a/src/kivymd/icon_definitions.py b/src/kivymd/icon_definitions.py deleted file mode 100644 index 5b717356..00000000 --- a/src/kivymd/icon_definitions.py +++ /dev/null @@ -1,1569 +0,0 @@ -# -*- coding: utf-8 -*- - -# Thanks to Sergey Kupletsky (github.com/zavoloklom) for its Material Design -# Iconic Font, which provides KivyMD's icons. - -# GALLERY HERE: -# https://zavoloklom.github.io/material-design-iconic-font/icons.html - -# LAST UPDATED: version 2.2.0 of Material Design Iconic Font - -md_icons = { - '3d-rotation': u'', - - 'airplane-off': u'', - - 'address': u'', - - 'airplane': u'', - - 'album': u'', - - 'archive': u'', - - 'assignment-account': u'', - - 'assignment-alert': u'', - - 'assignment-check': u'', - - 'assignment-o': u'', - - 'assignment-return': u'', - - 'assignment-returned': u'', - - 'assignment': u'', - - 'attachment-alt': u'', - - 'attachment': u'', - - 'audio': u'', - - 'badge-check': u'', - - 'balance-wallet': u'', - - 'balance': u'', - - 'battery-alert': u'', - - 'battery-flash': u'', - - 'battery-unknown': u'', - - 'battery': u'', - - 'bike': u'', - - 'block-alt': u'', - - 'block': u'', - - 'boat': u'', - - 'book-image': u'', - - 'book': u'', - - 'bookmark-outline': u'', - - 'bookmark': u'', - - 'brush': u'', - - 'bug': u'', - - 'bus': u'', - - 'cake': u'', - - 'car-taxi': u'', - - 'car-wash': u'', - - 'car': u'', - - 'card-giftcard': u'', - - 'card-membership': u'', - - 'card-travel': u'', - - 'card': u'', - - 'case-check': u'', - - 'case-download': u'', - - 'case-play': u'', - - 'case': u'', - - 'cast-connected': u'', - - 'cast': u'', - - 'chart-donut': u'', - - 'chart': u'', - - 'city-alt': u'', - - 'city': u'', - - 'close-circle-o': u'', - - 'close-circle': u'', - - 'close': u'', - - 'cocktail': u'', - - 'code-setting': u'', - - 'code-smartphone': u'', - - 'code': u'', - - 'coffee': u'', - - 'collection-bookmark': u'', - - 'collection-case-play': u'', - - 'collection-folder-image': u'', - - 'collection-image-o': u'', - - 'collection-image': u'', - - 'collection-item-1': u'', - - 'collection-item-2': u'', - - 'collection-item-3': u'', - - 'collection-item-4': u'', - - 'collection-item-5': u'', - - 'collection-item-6': u'', - - 'collection-item-7': u'', - - 'collection-item-8': u'', - - 'collection-item-9-plus': u'', - - 'collection-item-9': u'', - - 'collection-item': u'', - - 'collection-music': u'', - - 'collection-pdf': u'', - - 'collection-plus': u'', - - 'collection-speaker': u'', - - 'collection-text': u'', - - 'collection-video': u'', - - 'compass': u'', - - 'cutlery': u'', - - 'delete': u'', - - 'dialpad': u'', - - 'dns': u'', - - 'drink': u'', - - 'edit': u'', - - 'email-open': u'', - - 'email': u'', - - 'eye-off': u'', - - 'eye': u'', - - 'eyedropper': u'', - - 'favorite-outline': u'', - - 'favorite': u'', - - 'filter-list': u'', - - 'fire': u'', - - 'flag': u'', - - 'flare': u'', - - 'flash-auto': u'', - - 'flash-off': u'', - - 'flash': u'', - - 'flip': u'', - - 'flower-alt': u'', - - 'flower': u'', - - 'font': u'', - - 'fullscreen-alt': u'', - - 'fullscreen-exit': u'', - - 'fullscreen': u'', - - 'functions': u'', - - 'gas-station': u'', - - 'gesture': u'', - - 'globe-alt': u'', - - 'globe-lock': u'', - - 'globe': u'', - - 'graduation-cap': u'', - - 'group': u'', - - 'home': u'', - - 'hospital-alt': u'', - - 'hospital': u'', - - 'hotel': u'', - - 'hourglass-alt': u'', - - 'hourglass-outline': u'', - - 'hourglass': u'', - - 'http': u'', - - 'image-alt': u'', - - 'image-o': u'', - - 'image': u'', - - 'inbox': u'', - - 'invert-colors-off': u'', - - 'invert-colors': u'', - - 'key': u'', - - 'label-alt-outline': u'', - - 'label-alt': u'', - - 'label-heart': u'', - - 'label': u'', - - 'labels': u'', - - 'lamp': u'', - - 'landscape': u'', - - 'layers-off': u'', - - 'layers': u'', - - 'library': u'', - - 'link': u'', - - 'lock-open': u'', - - 'lock-outline': u'', - - 'lock': u'', - - 'mail-reply-all': u'', - - 'mail-reply': u'', - - 'mail-send': u'', - - 'mall': u'', - - 'map': u'', - - 'menu': u'', - - 'money-box': u'', - - 'money-off': u'', - - 'money': u'', - - 'more-vert': u'', - - 'more': u'', - - 'movie-alt': u'', - - 'movie': u'', - - 'nature-people': u'', - - 'nature': u'', - - 'navigation': u'', - - 'open-in-browser': u'', - - 'open-in-new': u'', - - 'palette': u'', - - 'parking': u'', - - 'pin-account': u'', - - 'pin-assistant': u'', - - 'pin-drop': u'', - - 'pin-help': u'', - - 'pin-off': u'', - - 'pin': u'', - - 'pizza': u'', - - 'plaster': u'', - - 'power-setting': u'', - - 'power': u'', - - 'print': u'', - - 'puzzle-piece': u'', - - 'quote': u'', - - 'railway': u'', - - 'receipt': u'', - - 'refresh-alt': u'', - - 'refresh-sync-alert': u'', - - 'refresh-sync-off': u'', - - 'refresh-sync': u'', - - 'refresh': u'', - - 'roller': u'', - - 'ruler': u'', - - 'scissors': u'', - - 'screen-rotation-lock': u'', - - 'screen-rotation': u'', - - 'search-for': u'', - - 'search-in-file': u'', - - 'search-in-page': u'', - - 'search-replace': u'', - - 'search': u'', - - 'seat': u'', - - 'settings-square': u'', - - 'settings': u'', - - 'shape': u'', - - 'shield-check': u'', - - 'shield-security': u'', - - 'shopping-basket': u'', - - 'shopping-cart-plus': u'', - - 'shopping-cart': u'', - - 'sign-in': u'', - - 'sort-amount-asc': u'', - - 'sort-amount-desc': u'', - - 'sort-asc': u'', - - 'sort-desc': u'', - - 'spellcheck': u'', - - 'spinner': u'', - - 'storage': u'', - - 'store-24': u'', - - 'store': u'', - - 'subway': u'', - - 'sun': u'', - - 'tab-unselected': u'', - - 'tab': u'', - - 'tag-close': u'', - - 'tag-more': u'', - - 'tag': u'', - - 'thumb-down': u'', - - 'thumb-up-down': u'', - - 'thumb-up': u'', - - 'ticket-star': u'', - - 'toll': u'', - - 'toys': u'', - - 'traffic': u'', - - 'translate': u'', - - 'triangle-down': u'', - - 'triangle-up': u'', - - 'truck': u'', - - 'turning-sign': u'', - - ' ungroup': u'', - - 'wallpaper': u'', - - 'washing-machine': u'', - - 'window-maximize': u'', - - 'window-minimize': u'', - - 'window-restore': u'', - - 'wrench': u'', - - 'zoom-in': u'', - - 'zoom-out': u'', - - 'alert-circle-o': u'', - - 'alert-circle': u'', - - 'alert-octagon': u'', - - 'alert-polygon': u'', - - 'alert-triangle': u'', - - 'help-outline': u'', - - 'help': u'', - - 'info-outline': u'', - - 'info': u'', - - 'notifications-active': u'', - - 'notifications-add': u'', - - 'notifications-none': u'', - - 'notifications-off': u'', - - 'notifications-paused': u'', - - 'notifications': u'', - - 'account-add': u'', - - 'account-box-mail': u'', - - 'account-box-o': u'', - - 'account-box-phone': u'', - - 'account-box': u'', - - 'account-calendar': u'', - - 'account-circle': u'', - - 'account-o': u'', - - 'account': u'', - - 'accounts-add': u'', - - 'accounts-alt': u'', - - 'accounts-list-alt': u'', - - 'accounts-list': u'', - - 'accounts-outline': u'', - - 'accounts': u'', - - 'face': u'', - - 'female': u'', - - 'male-alt': u'', - - 'male-female': u'', - - 'male': u'', - - 'mood-bad': u'', - - 'mood': u'', - - 'run': u'', - - 'walk': u'', - - 'cloud-box': u'', - - 'cloud-circle': u'', - - 'cloud-done': u'', - - 'cloud-download': u'', - - 'cloud-off': u'', - - 'cloud-outline-alt': u'', - - 'cloud-outline': u'', - - 'cloud-upload': u'', - - 'cloud': u'', - - 'download': u'', - - 'file-plus': u'', - - 'file-text': u'', - - 'file': u'', - - 'folder-outline': u'', - - 'folder-person': u'', - - 'folder-star-alt': u'', - - 'folder-star': u'', - - 'folder': u'', - - 'gif': u'', - - 'upload': u'', - - 'border-all': u'', - - 'border-bottom': u'', - - 'border-clear': u'', - - 'border-color': u'', - - 'border-horizontal': u'', - - 'border-inner': u'', - - 'border-left': u'', - - 'border-outer': u'', - - 'border-right': u'', - - 'border-style': u'', - - 'border-top': u'', - - 'border-vertical': u'', - - 'copy': u'', - - 'crop': u'', - - 'format-align-center': u'', - - 'format-align-justify': u'', - - 'format-align-left': u'', - - 'format-align-right': u'', - - 'format-bold': u'', - - 'format-clear-all': u'', - - 'format-clear': u'', - - 'format-color-fill': u'', - - 'format-color-reset': u'', - - 'format-color-text': u'', - - 'format-indent-decrease': u'', - - 'format-indent-increase': u'', - - 'format-italic': u'', - - 'format-line-spacing': u'', - - 'format-list-bulleted': u'', - - 'format-list-numbered': u'', - - 'format-ltr': u'', - - 'format-rtl': u'', - - 'format-size': u'', - - 'format-strikethrough-s': u'', - - 'format-strikethrough': u'', - - 'format-subject': u'', - - 'format-underlined': u'', - - 'format-valign-bottom': u'', - - 'format-valign-center': u'', - - 'format-valign-top': u'', - - 'redo': u'', - - 'select-all': u'', - - 'space-bar': u'', - - 'text-format': u'', - - 'transform': u'', - - 'undo': u'', - - 'wrap-text': u'', - - 'comment-alert': u'', - - 'comment-alt-text': u'', - - 'comment-alt': u'', - - 'comment-edit': u'', - - 'comment-image': u'', - - 'comment-list': u'', - - 'comment-more': u'', - - 'comment-outline': u'', - - 'comment-text-alt': u'', - - 'comment-text': u'', - - 'comment-video': u'', - - 'comment': u'', - - 'comments': u'', - - 'rm': u'F', - - 'check-all': u'', - - 'check-circle-u': u'', - - 'check-circle': u'', - - 'check-square': u'', - - 'check': u'', - - 'circle-o': u'', - - 'circle': u'', - - 'dot-circle-alt': u'', - - 'dot-circle': u'', - - 'minus-circle-outline': u'', - - 'minus-circle': u'', - - 'minus-square': u'', - - 'minus': u'', - - 'plus-circle-o-duplicate': u'', - - 'plus-circle-o': u'', - - 'plus-circle': u'', - - 'plus-square': u'', - - 'plus': u'', - - 'square-o': u'', - - 'star-circle': u'', - - 'star-half': u'', - - 'star-outline': u'', - - 'star': u'', - - 'bluetooth-connected': u'', - - 'bluetooth-off': u'', - - 'bluetooth-search': u'', - - 'bluetooth-setting': u'', - - 'bluetooth': u'', - - 'camera-add': u'', - - 'camera-alt': u'', - - 'camera-bw': u'', - - 'camera-front': u'', - - 'camera-mic': u'', - - 'camera-party-mode': u'', - - 'camera-rear': u'', - - 'camera-roll': u'', - - 'camera-switch': u'', - - 'camera': u'', - - 'card-alert': u'', - - 'card-off': u'', - - 'card-sd': u'', - - 'card-sim': u'', - - 'desktop-mac': u'', - - 'desktop-windows': u'', - - 'device-hub': u'', - - 'devices-off': u'', - - 'devices': u'', - - 'dock': u'', - - 'floppy': u'', - - 'gamepad': u'', - - 'gps-dot': u'', - - 'gps-off': u'', - - 'gps': u'', - - 'headset-mic': u'', - - 'headset': u'', - - 'input-antenna': u'', - - 'input-composite': u'', - - 'input-hdmi': u'', - - 'input-power': u'', - - 'input-svideo': u'', - - 'keyboard-hide': u'', - - 'keyboard': u'', - - 'laptop-chromebook': u'', - - 'laptop-mac': u'', - - 'laptop': u'', - - 'mic-off': u'', - - 'mic-outline': u'', - - 'mic-setting': u'', - - 'mic': u'', - - 'mouse': u'', - - 'network-alert': u'', - - 'network-locked': u'', - - 'network-off': u'', - - 'network-outline': u'', - - 'network-setting': u'', - - 'network': u'', - - 'phone-bluetooth': u'', - - 'phone-end': u'', - - 'phone-forwarded': u'', - - 'phone-in-talk': u'', - - 'phone-locked': u'', - - 'phone-missed': u'', - - 'phone-msg': u'', - - 'phone-paused': u'', - - 'phone-ring': u'', - - 'phone-setting': u'', - - 'phone-sip': u'', - - 'phone': u'', - - 'portable-wifi-changes': u'', - - 'portable-wifi-off': u'', - - 'portable-wifi': u'', - - 'radio': u'', - - 'reader': u'', - - 'remote-control-alt': u'', - - 'remote-control': u'', - - 'router': u'', - - 'scanner': u'', - - 'smartphone-android': u'', - - 'smartphone-download': u'', - - 'smartphone-erase': u'', - - 'smartphone-info': u'', - - 'smartphone-iphone': u'', - - 'smartphone-landscape-lock': u'', - - 'smartphone-landscape': u'', - - 'smartphone-lock': u'', - - 'smartphone-portrait-lock': u'', - - 'smartphone-ring': u'', - - 'smartphone-setting': u'', - - 'smartphone-setup': u'', - - 'smartphone': u'', - - 'speaker': u'', - - 'tablet-android': u'', - - 'tablet-mac': u'', - - 'tablet': u'', - - 'tv-alt-play': u'', - - 'tv-list': u'', - - 'tv-play': u'', - - 'tv': u'', - - 'usb': u'', - - 'videocam-off': u'', - - 'videocam-switch': u'', - - 'videocam': u'', - - 'watch': u'', - - 'wifi-alt-2': u'', - - 'wifi-alt': u'', - - 'wifi-info': u'', - - 'wifi-lock': u'', - - 'wifi-off': u'', - - 'wifi-outline': u'', - - 'wifi': u'', - - 'arrow-left-bottom': u'', - - 'arrow-left': u'', - - 'arrow-merge': u'', - - 'arrow-missed': u'', - - 'arrow-right-top': u'', - - 'arrow-right': u'', - - 'arrow-split': u'', - - 'arrows': u'', - - 'caret-down-circle': u'', - - 'caret-down': u'', - - 'caret-left-circle': u'', - - 'caret-left': u'', - - 'caret-right-circle': u'', - - 'caret-right': u'', - - 'caret-up-circle': u'', - - 'caret-up': u'', - - 'chevron-down': u'', - - 'chevron-left': u'', - - 'chevron-right': u'', - - 'chevron-up': u'', - - 'forward': u'', - - 'long-arrow-down': u'', - - 'long-arrow-left': u'', - - 'long-arrow-return': u'', - - 'long-arrow-right': u'', - - 'long-arrow-tab': u'', - - 'long-arrow-up': u'', - - 'rotate-ccw': u'', - - 'rotate-cw': u'', - - 'rotate-left': u'', - - 'rotate-right': u'', - - 'square-down': u'', - - 'square-right': u'', - - 'swap-alt': u'', - - 'swap-vertical-circle': u'', - - 'swap-vertical': u'', - - 'swap': u'', - - 'trending-down': u'', - - 'trending-flat': u'', - - 'trending-up': u'', - - 'unfold-less': u'', - - 'unfold-more': u'', - - 'apps': u'', - - 'grid-off': u'', - - 'grid': u'', - - 'view-agenda': u'', - - 'view-array': u'', - - 'view-carousel': u'', - - 'view-column': u'', - - 'view-comfy': u'', - - 'view-compact': u'', - - 'view-dashboard': u'', - - 'view-day': u'', - - 'view-headline': u'', - - 'view-list-alt': u'', - - 'view-list': u'', - - 'view-module': u'', - - 'view-quilt': u'', - - 'view-stream': u'', - - 'view-subtitles': u'', - - 'view-toc': u'', - - 'view-web': u'', - - 'view-week': u'', - - 'widgets': u'', - - 'alarm-check': u'', - - 'alarm-off': u'', - - 'alarm-plus': u'', - - 'alarm-snooze': u'', - - 'alarm': u'', - - 'calendar-alt': u'', - - 'calendar-check': u'', - - 'calendar-close': u'', - - 'calendar-note': u'', - - 'calendar': u'', - - 'time-countdown': u'', - - 'time-interval': u'', - - 'time-restore-setting': u'', - - 'time-restore': u'', - - 'time': u'', - - 'timer-off': u'', - - 'timer': u'', - - 'android-alt': u'', - - 'android': u'', - - 'apple': u'', - - 'behance': u'', - - 'codepen': u'', - - 'dribbble': u'', - - 'dropbox': u'', - - 'evernote': u'', - - 'facebook-box': u'', - - 'facebook': u'', - - 'github-box': u'', - - 'github': u'', - - 'google-drive': u'', - - 'google-earth': u'', - - 'google-glass': u'', - - 'google-maps': u'', - - 'google-pages': u'', - - 'google-play': u'', - - 'google-plus-box': u'', - - 'google-plus': u'', - - 'google': u'', - - 'instagram': u'', - - 'language-css3': u'', - - 'language-html5': u'', - - 'language-javascript': u'', - - 'language-python-alt': u'', - - 'language-python': u'', - - 'lastfm': u'', - - 'linkedin-box': u'', - - 'paypal': u'', - - 'pinterest-box': u'', - - 'pocket': u'', - - 'polymer': u'', - - 'rss': u'', - - 'share': u'', - - 'stackoverflow': u'', - - 'steam-square': u'', - - 'steam': u'', - - 'twitter-box': u'', - - 'twitter': u'', - - 'vk': u'', - - 'wikipedia': u'', - - 'windows': u'', - - '500px': u'', - - '8tracks': u'', - - 'amazon': u'', - - 'blogger': u'', - - 'delicious': u'', - - 'disqus': u'', - - 'flattr': u'', - - 'flickr': u'', - - 'github-alt': u'', - - 'google-old': u'', - - 'linkedin': u'', - - 'odnoklassniki': u'', - - 'outlook': u'', - - 'paypal-alt': u'', - - 'pinterest': u'', - - 'playstation': u'', - - 'reddit': u'', - - 'skype': u'', - - 'slideshare': u'', - - 'soundcloud': u'', - - 'tumblr': u'', - - 'twitch': u'', - - 'vimeo': u'', - - 'whatsapp': u'', - - 'xbox': u'', - - 'yahoo': u'', - - 'youtube-play': u'', - - 'youtube': u'', - - 'aspect-ratio-alt': u'', - - 'aspect-ratio': u'', - - 'blur-circular': u'', - - 'blur-linear': u'', - - 'blur-off': u'', - - 'blur': u'', - - 'brightness-2': u'', - - 'brightness-3': u'', - - 'brightness-4': u'', - - 'brightness-5': u'', - - 'brightness-6': u'', - - 'brightness-7': u'', - - 'brightness-auto': u'', - - 'brightness-setting': u'', - - 'broken-image': u'', - - 'center-focus-strong': u'', - - 'center-focus-weak': u'', - - 'compare': u'', - - 'crop-16-9': u'', - - 'crop-3-2': u'', - - 'crop-5-4': u'', - - 'crop-7-5': u'', - - 'crop-din': u'', - - 'crop-free': u'', - - 'crop-landscape': u'', - - 'crop-portrait': u'', - - 'crop-square': u'', - - 'exposure-alt': u'', - - 'exposure': u'', - - 'filter-b-and-w': u'', - - 'filter-center-focus': u'', - - 'filter-frames': u'', - - 'filter-tilt-shift': u'', - - 'gradient': u'', - - 'grain': u'', - - 'graphic-eq': u'', - - 'hdr-off': u'', - - 'hdr-strong': u'', - - 'hdr-weak': u'', - - 'hdr': u'', - - 'iridescent': u'', - - 'leak-off': u'', - - 'leak': u'', - - 'looks': u'', - - 'loupe': u'', - - 'panorama-horizontal': u'', - - 'panorama-vertical': u'', - - 'panorama-wide-angle': u'', - - 'photo-size-select-large': u'', - - 'photo-size-select-small': u'', - - 'picture-in-picture': u'', - - 'slideshow': u'', - - 'texture': u'', - - 'tonality': u'', - - 'vignette': u'', - - 'wb-auto': u'', - - 'eject-alt': u'', - - 'eject': u'', - - 'equalizer': u'', - - 'fast-forward': u'', - - 'fast-rewind': u'', - - 'forward-10': u'', - - 'forward-30': u'', - - 'forward-5': u'', - - 'hearing': u'', - - 'pause-circle-outline': u'', - - 'pause-circle': u'', - - 'pause': u'', - - 'play-circle-outline': u'', - - 'play-circle': u'', - - 'play': u'', - - 'playlist-audio': u'', - - 'playlist-plus': u'', - - 'repeat-one': u'', - - 'repeat': u'', - - 'replay-10': u'', - - 'replay-30': u'', - - 'replay-5': u'', - - 'replay': u'', - - 'shuffle': u'', - - 'skip-next': u'', - - 'skip-previous': u'', - - 'stop': u'', - - 'surround-sound': u'', - - 'tune': u'', - - 'volume-down': u'', - - 'volume-mute': u'', - - 'volume-off': u'', - - 'volume-up': u'', - - 'n-1-square': u'', - - 'n-2-square': u'', - - 'n-3-square': u'', - - 'n-4-square': u'', - - 'n-5-square': u'', - - 'n-6-square': u'', - - 'neg-1': u'', - - 'neg-2': u'', - - 'plus-1': u'', - - 'plus-2': u'', - - 'sec-10': u'', - - 'sec-3': u'', - - 'zero': u'', - - 'airline-seat-flat-angled': u'', - - 'airline-seat-flat': u'', - - 'airline-seat-individual-suite': u'', - - 'airline-seat-legroom-extra': u'', - - 'airline-seat-legroom-normal': u'', - - 'airline-seat-legroom-reduced': u'', - - 'airline-seat-recline-extra': u'', - - 'airline-seat-recline-normal': u'', - - 'airplay': u'', - - 'closed-caption': u'', - - 'confirmation-number': u'', - - 'developer-board': u'', - - 'disc-full': u'', - - 'explicit': u'', - - 'flight-land': u'', - - 'flight-takeoff': u'', - - 'flip-to-back': u'', - - 'flip-to-front': u'', - - 'group-work': u'', - - 'hd': u'', - - 'hq': u'', - - 'markunread-mailbox': u'', - - 'memory': u'', - - 'nfc': u'', - - 'play-for-work': u'', - - 'power-input': u'', - - 'present-to-all': u'', - - 'satellite': u'', - - 'tap-and-play': u'', - - 'vibration': u'', - - 'voicemail': u'', -} diff --git a/src/kivymd/images/kivymd_512.png b/src/kivymd/images/kivymd_512.png deleted file mode 100644 index 7dbae604b08b210b328811e55eaa07a4ac208161..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30694 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�Yr6^*!j4`?xt=1o7 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

{o3)qC%_NL=ZyH!i#uU@H7YaP~Sij5YY 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 diff --git a/src/kivymd/images/quad_shadow-0.png b/src/kivymd/images/quad_shadow-0.png deleted file mode 100644 index 5d64fde5abd43c793c2fe2dd0bbdf9ddcfd923d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29962 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 B=*s{A diff --git a/src/kivymd/images/quad_shadow-1.png b/src/kivymd/images/quad_shadow-1.png deleted file mode 100644 index c0f1e22642060aec1971849ac7fc73c3c4a1f6ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30186 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 l{J(65`hR_|Q9i1{Yp%_~=~Fq;?y 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�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 Vs`!V~6-HfPW?}VP6KRr*>ly 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 diff --git a/src/kivymd/images/rec_st_shadow-1.png b/src/kivymd/images/rec_st_shadow-1.png deleted file mode 100644 index 759ee65285764c0619509c5b8cb27f972b2ab3fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32265 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 G;{P8x^pl$a diff --git a/src/kivymd/images/rec_st_shadow.atlas b/src/kivymd/images/rec_st_shadow.atlas deleted file mode 100644 index d4c24abe..00000000 --- a/src/kivymd/images/rec_st_shadow.atlas +++ /dev/null @@ -1 +0,0 @@ -{"rec_st_shadow-0.png": {"11": [262, 138, 128, 256], "10": [132, 138, 128, 256], "13": [522, 138, 128, 256], "12": [392, 138, 128, 256], "15": [782, 138, 128, 256], "14": [652, 138, 128, 256], "16": [912, 138, 128, 256], "0": [2, 138, 128, 256]}, "rec_st_shadow-1.png": {"20": [522, 138, 128, 256], "21": [652, 138, 128, 256], "17": [2, 138, 128, 256], "23": [912, 138, 128, 256], "19": [262, 138, 128, 256], "18": [132, 138, 128, 256], "22": [782, 138, 128, 256], "1": [392, 138, 128, 256]}, "rec_st_shadow-2.png": {"3": [132, 138, 128, 256], "2": [2, 138, 128, 256], "5": [392, 138, 128, 256], "4": [262, 138, 128, 256], "7": [652, 138, 128, 256], "6": [522, 138, 128, 256], "9": [912, 138, 128, 256], "8": [782, 138, 128, 256]}} \ No newline at end of file diff --git a/src/kivymd/images/round_shadow-0.png b/src/kivymd/images/round_shadow-0.png deleted file mode 100644 index 26d984051562b2baf7d39cb92639aae94d222bda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39635 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 HcaHmiYza5P diff --git a/src/kivymd/images/round_shadow-1.png b/src/kivymd/images/round_shadow-1.png deleted file mode 100644 index d0f4c0fd4a6f9ac07d583e28e27e20a2495c392f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40767 zcmce-g;QM36D|xv7I#@}AqxQli`xPVBzSOw6CjHPLLj&;?hYXkBsjddyUXGMg1f^8 z_u#=UzpuXk;8xwKI#s9UOilIF>FVxz`gtNW)D#HuXz|d{&Kb0{}-z^b?(%B4Y0HeY%<@8qgg)DyRo4PB#xe_tIPfUnws~yI{2^7g; z8gZmg{nI*f&jH8lx@_^(2+N!qB{bD@)6V{H%A2Lgu0S$U~_un9`DA$i}N9b`TbZ*uk=9WyTS1Jmr zqV3uS^=DCr39Tl|y!<>hRxjE%#?Q6qe7K7iUwx6H1jOddq`2oF!YDbw2#wuq%26Ub;#QjHd}pDdk%~YC95J=)b#YG!V_ja7L8;W%8_$ z-#~BP@HYsBd}PUKcoU~@A-y3BM)gc8GFMF-Sl2(vIH|cytlyqyQ;DXKr4Q#GBv=wB4i}^2N)zGB*MQ(jKs!z)w~UNl)es z3t+Q*;uJf^OC!Pv5+ylMj{&snlZiqo<1!zJma+9>juuU9tPGdN@CG7z)Ag;xj$*(Z z7&-l$cwI5+0_Pk8Jtnvz0#tEm#|cN}yBPY{P|u3tQf(7oY zD?-6b$@#3yy$&WOugG94aDIYom#@O0YTtUpxCoR{GZodrj2W!J+;z9Fg|uL0a(%WAd@;Nz?AjoF!1Xj-;fo|q>=vizYz zoE^7o{y+wO7*%wVNHL)<4XzbII()b0TzjTxdNg&bSRgJw86{Tz07|>2!nAN{;O2xk2{VEy!EaeyeqiX2bl6vbsNIU)&T^!w_ zTUaW_5P;gQR~X)IoRwyMs0^9z#}qLsD@aB&nfUwL=JADqlz(%UU-m5k?L_a~z3zzU zfaq1#f{A896lIJIZfIo4(kfY$3d=klTn34~F*}mMx1m;=Qz%bjieu&*q?(7s4rHSw z4nd@F(8g+8$>hFJgSfOSKQ}7$#PB-`$cS4ZkE=d zS29+&S%rB1&ua%7*e;T+x=5D!@D~>=>WMZ%@gBR&3Qh8(Y8LtpMS^uOysf*%2Yp+T z!R!n@0eT8sqAOUZ}L zmWa<|i6`0XE7G5{$HYeEo}xv1Vu`oWgd9PqjDsxV1Y66}XbbuetE!6~a!~PE<=g-h zfZjywoM<0k+#rN}0t|R1`zb7|>>OUdb^|hZ-{972c;m0zm)^Rk1heGExw{Z$GuWlO zemMTX%Wv;QSFOSGUSg1!EIr}R>A8@wjM~+Efs?g-CVk#jGa@O^)IJn;t$&l(SZ=I> zm~c3`W+-UD)%z>UuvkMHNA+N^G@C1x**~1x9uk;FVE`fYTinOsiSRuJ)$~~S8641E z@6(SF16^_avC&LX*PB~Ue@RB~5%c;dPQZ?&R)m2&VgPUh`eL05 zuuj|%CBW}pg&r*H9~oFpZz*fndp*5md+PVzEqP`I#(ScV!mF$nP^u-=#X)+ErlXpn zifsi)m4A$Ei<-**-K3Mf%8leDA@!9fN+28%V*RfDB0gYBb6@qvPR38CeqLvKL?4(u z;*?!95^fd15E{oTPUv0E4oEik%pS#1_-P6=!}Dz$C_rUnzgCuD2gQpMaql-_UdU2? z6`wPX)@<))q4Sc(mlkq5RN!j3oyx1zD=!u9m8>6xi%a@eB=mBqp$Lk^m_ z!^&?Dc<~s`$)e^`+G0q)kq{;O?o!6_l4(*219y%Mbo-g2gbkql)o`L^vsjLv*Ek?d z>fDDQ&QyJiiOk4Q6jFQy7QTnYO0-+w-BY%hB|1pTCWYpxD{p~+5iYmw-w(sClj^4s z@{W1O^f+MikNH#e4I%5-VDk;|@Q53_b6Q*1NLU=N4y7{PPK`8Z<1lJTC0aaS5~H9x>EuyMz7 zy_B0%-J$byo0h&mZ!9(wadp=F4*`GA2-aa9RTRp-V2{6eT7FM>U5se=>S#|@Kc7go zX!o5}gaftIMO-?{K3Z;}1RZe{WueISaF-6F-+2U;d~%F)DNUs6T37=Oq%nCYlGm?| z#|T0tu~1+FVT$yxI5{`6Neg+?0TY}*o$+$<-mW;`@bKaT=(s^Lju_U;Z9^#+zcNO8 zVEFvy<0zQ5n3C4_RDA~q1wc#@e^Srq^|xPr|Glcfx&bi0hz0xusj1L!IYdS?0NT|c zt!{I#uUcy|If?l%Xm^w#-3IrxT7qYBXpgwh{?1TPH*J+N6>mUSS3w8Q8y)Bs202&( zwzWnkRG~i_Q~E`~a$DFvwQexa&b2VO1$JPvP`5_j#w3X;doH;R^L^;7=tGyhw1oc7 zo=#|BADE#3w~cYu;08{3UkRmYm1a1b?YzFVQebj(npW<7vBDtuQm z|8+2UGQM)R@n>ksWUx)RaWLr=*LLAYK|CVKrUO0AToVyzP(?M!$3!VHUi3%HbLtr5 zl_Pn==#s*?`IsV$ic0~H zr|bhdFI|YMW6{}2{6!`uP`YZ6>CZSh;c7J4X}5pgf47yr*#O8VWk%m}ZCeW{=bcG3 zRBV9pC1V+|cb?1aO`|Gh3sP^~>Klmy>rFq58>y7u%@f}I0JE}9DrcXwTZEkQobi9u z2lStL8&|Z_k+|b0Yskji1yPJvJbAenUu`cBr}a<&yWJ;=8YJ|Mz2uDp2pY4^9Mr^H zdp^)w%DRxozkxj#ZT?rx^A*lUQZ9&@RrrdikV#uN&Oo*pWndr{nH6YOePb&W0zbtd z`ll8e#l0*8B;wc|39x>007(l9&J4Y-0*F<9IXL_|gzoBwn55ppW+V9O=kSNJpy7#u zHQ?sSlq|}xn}zBl-1kK!^E_06RaSX;_;ScDXVe5I2_?Mr^6Prd6;yI^vBqT3pm#H8dLhJ}3Q?$#;wfF^d1iu~dV+sJc)TW#ok z?H{MCNkxkZxqe(qC*kAgB=af93<+~E+nD^$-Mt$lC^{7FHpIFGnj`-hq-CTANx>Mw z71mBBv#iSwg)Q#AVzt_6OqtYp!q;*+8+(5F2nSV;Q&g4Sy^@~bC@d(S=aP_ z8CVNE*8Hb+ee@*dMjE}koBN6){@gikw0}xH%iI`Z22aTH*Nl5Fhf>;}@qt!{dxp!p zY^wk%i3R7*O8}+)0q=foNrtiKv9*L>+Kfo|1rA_JLpI5YAyofZw5g1tpr)($L1}Wp zdm3Wj1aShnSJE~ti5PKxzA?PqFNekvMQuLy3_QG-*F5O=60GshKGC_eQiGQ+22GIU%RNhqGgNVze@dXBS*FG^Th)Bx_Bt>Pa!;A|Kh)w z^rX%Df~5u6-LT_-~iVn z={edpBd=(@gqbGpEccdM_Zic$W&ufuwSo^RbQRN2pDXKC17$QQ4qg9x*JZ&o%O`HRaDX92Jz7k(cIP z^aibsxlxd@O4883OqrpZd{K~=L620QPK&5ImW^v z{tlhY-RcSRvW#=8D<)9ZLsm*Zr-%QY`5&{5(S`la}Ttp7P+MMQ3KS>o0e-H zW8C;zx}@mD*<7tkqd6y^*#!cAwbHQSZk)u`Vs z|DvEDpVnIrLYXFx(IhyB(YkD@0_S*maeJl83KV6|&_o(vXZ0BKa4M)9U>FXJIt(~+ z(DLXlb@o~SHmAV$ytoQD{RUSjKGCKY8ESnp65_(Zdws5*vfB`ds!Xx9b=_tz{#=gn zf+$yCX1lV?E?bH5XlhKbFRL+DP#yt;w!1kEf^k5Y{)fm8bUhbOWd7kr0ie zbLBYBiu^jD4__v)Cfo=>O}n|Y>$BDPpxtfcE@bZa_!Y+Xzc^P{ri<&ZoA#Q0*F~#S z!c>Fv-k8!p6vs=tK|ZoJv%`~CWA&?Fddf7ldi*aVd4(E1^)fV6jOcz9%kP-k%SD(x zM%VED@Q_0{W4Q1*fS7{2W<5-7vnM3JGj?qB6hBw&>vk~nkRNw^h)iWpNB{k3-&_i2 zP$wZ})?AV7lyT+tza@{8QTZZk%-k4{H&5;0o}Q?h1l_rBkdl=cL501YH^ma>7?o6t4 zfb{ftFsis|XWDxusUp|Wyq=TljR#e9IRDKC(Id|fYJGL}exo}wso5iN%%O=IVYxs> z>zA@lcT)KaP8CvspQ46eTD@GUPjW8V2B_zEdSvxabzVQ$>#@>3aTOvvu$&BlOGa>0l3AgWaR}9UrOiyY z^^2A3j&EaMI4ym!_Pi?#Z|6y{7`uUi*d<%snVthwROk`ndbS<@&95*JX|yw)cn9f- z`lb&p@pY?lkqZC;xE47d3HFp#Fjha7&!W`F`7^nikAY`>doX^z5!;L)Mc9fBOZT@DeG70rjXoQ#4kA~qKSQhX2QHZB zd|mR1Ih!_$BR|)~sZ^DSa7Xaesq9PSw-cV+s2g7(-DEUiM)_x|evwQ(E`20QfEx

(Ig{HG6T4&}_d3cF!08sm%T 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 diff --git a/src/kivymd/images/round_shadow-2.png b/src/kivymd/images/round_shadow-2.png deleted file mode 100644 index d5feef2c8a5a7bedd94cfce29af5cea57fab701f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26510 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 diff --git a/src/kivymd/images/round_shadow.atlas b/src/kivymd/images/round_shadow.atlas deleted file mode 100644 index f25016dc..00000000 --- a/src/kivymd/images/round_shadow.atlas +++ /dev/null @@ -1 +0,0 @@ -{"round_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "round_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "round_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}} \ No newline at end of file diff --git a/src/kivymd/label.py b/src/kivymd/label.py deleted file mode 100644 index 844f2a07..00000000 --- a/src/kivymd/label.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.lang import Builder -from kivy.metrics import sp -from kivy.properties import OptionProperty, DictProperty, ListProperty -from kivy.uix.label import Label -from kivymd.material_resources import DEVICE_TYPE -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - disabled_color: self.theme_cls.disabled_hint_text_color - text_size: (self.width, None) -''') - - -class MDLabel(ThemableBehavior, Label): - font_style = OptionProperty( - 'Body1', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - # Font, Bold, Mobile size, Desktop size (None if same as Mobile) - _font_styles = DictProperty({'Body1': ['Roboto', False, 14, 13], - 'Body2': ['Roboto', True, 14, 13], - 'Caption': ['Roboto', False, 12, None], - 'Subhead': ['Roboto', False, 16, 15], - 'Title': ['Roboto', True, 20, None], - 'Headline': ['Roboto', False, 24, None], - 'Display1': ['Roboto', False, 34, None], - 'Display2': ['Roboto', False, 45, None], - 'Display3': ['Roboto', False, 56, None], - 'Display4': ['RobotoLight', False, 112, None], - 'Button': ['Roboto', True, 14, None], - 'Icon': ['Icons', False, 24, None]}) - - theme_text_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - - text_color = ListProperty(None, allownone=True) - - _currently_bound_property = {} - - def __init__(self, **kwargs): - super(MDLabel, self).__init__(**kwargs) - self.on_theme_text_color(None, self.theme_text_color) - self.on_font_style(None, self.font_style) - self.on_opposite_colors(None, self.opposite_colors) - - def on_font_style(self, instance, style): - info = self._font_styles[style] - self.font_name = info[0] - self.bold = info[1] - if DEVICE_TYPE == 'desktop' and info[3] is not None: - self.font_size = sp(info[3]) - else: - self.font_size = sp(info[2]) - - def on_theme_text_color(self, instance, value): - t = self.theme_cls - op = self.opposite_colors - setter = self.setter('color') - t.unbind(**self._currently_bound_property) - c = {} - if value == 'Primary': - c = {'text_color' if not op else 'opposite_text_color': setter} - t.bind(**c) - self.color = t.text_color if not op else t.opposite_text_color - elif value == 'Secondary': - c = {'secondary_text_color' if not op else - 'opposite_secondary_text_color': setter} - t.bind(**c) - self.color = t.secondary_text_color if not op else \ - t.opposite_secondary_text_color - elif value == 'Hint': - c = {'disabled_hint_text_color' if not op else - 'opposite_disabled_hint_text_color': setter} - t.bind(**c) - self.color = t.disabled_hint_text_color if not op else \ - t.opposite_disabled_hint_text_color - elif value == 'Error': - c = {'error_color': setter} - t.bind(**c) - self.color = t.error_color - elif value == 'Custom': - self.color = self.text_color if self.text_color else (0, 0, 0, 1) - self._currently_bound_property = c - - def on_text_color(self, *args): - if self.theme_text_color == 'Custom': - self.color = self.text_color - - def on_opposite_colors(self, instance, value): - self.on_theme_text_color(self, self.theme_text_color) diff --git a/src/kivymd/list.py b/src/kivymd/list.py deleted file mode 100644 index 36162329..00000000 --- a/src/kivymd/list.py +++ /dev/null @@ -1,531 +0,0 @@ -# -*- coding: utf-8 -*- -''' -Lists -===== - -`Material Design spec, Lists page `_ - -`Material Design spec, Lists: Controls page `_ - -The class :class:`MDList` in combination with a ListItem like -:class:`OneLineListItem` will create a list that expands as items are added to -it, working nicely with Kivy's :class:`~kivy.uix.scrollview.ScrollView`. - - -Simple examples ---------------- - -Kv Lang: - -.. code-block:: python - - ScrollView: - do_scroll_x: False # Important for MD compliance - MDList: - OneLineListItem: - text: "Single-line item" - TwoLineListItem: - text: "Two-line item" - secondary_text: "Secondary text here" - ThreeLineListItem: - text: "Three-line item" - secondary_text: "This is a multi-line label where you can fit more text than usual" - - -Python: - -.. code-block:: python - - # Sets up ScrollView with MDList, as normally used in Android: - sv = ScrollView() - ml = MDList() - sv.add_widget(ml) - - contacts = ["Paula", "John", "Kate", "Vlad"] - for c in contacts: - ml.add_widget( - OneLineListItem( - text=c - ) - ) - -Advanced usage --------------- - -Due to the variety in sizes and controls in the MD spec, this module suffers -from a certain level of complexity to keep the widgets compliant, flexible -and performant. - -For this KivyMD provides ListItems that try to cover the most common usecases, -when those are insufficient, there's a base class called :class:`ListItem` -which you can use to create your own ListItems. This documentation will only -cover the provided ones, for custom implementations please refer to this -module's source code. - -Text only ListItems -------------------- - -- :class:`~OneLineListItem` -- :class:`~TwoLineListItem` -- :class:`~ThreeLineListItem` - -These are the simplest ones. The :attr:`~ListItem.text` attribute changes the -text in the most prominent line, while :attr:`~ListItem.secondary_text` -changes the second and third line. - -If there are only two lines, :attr:`~ListItem.secondary_text` will shorten -the text to fit in case it is too long; if a third line is available, it will -instead wrap the text to make use of it. - -ListItems with widget containers --------------------------------- - -- :class:`~OneLineAvatarListItem` -- :class:`~TwoLineAvatarListItem` -- :class:`~ThreeLineAvatarListItem` -- :class:`~OneLineIconListItem` -- :class:`~TwoLineIconListItem` -- :class:`~ThreeLineIconListItem` -- :class:`~OneLineAvatarIconListItem` -- :class:`~TwoLineAvatarIconListItem` -- :class:`~ThreeLineAvatarIconListItem` - -These widgets will take other widgets that inherit from :class:`~ILeftBody`, -:class:`ILeftBodyTouch`, :class:`~IRightBody` or :class:`~IRightBodyTouch` and -put them in their corresponding container. - -As the name implies, :class:`~ILeftBody` and :class:`~IRightBody` will signal -that the widget goes into the left or right container, respectively. - -:class:`~ILeftBodyTouch` and :class:`~IRightBodyTouch` do the same thing, -except these widgets will also receive touch events that occur within their -surfaces. - -Python example: - -.. code-block:: python - - class ContactPhoto(ILeftBody, AsyncImage): - pass - - class MessageButton(IRightBodyTouch, MDIconButton): - phone_number = StringProperty() - - def on_release(self): - # sample code: - Dialer.send_sms(phone_number, "Hey! What's up?") - pass - - # Sets up ScrollView with MDList, as normally used in Android: - sv = ScrollView() - ml = MDList() - sv.add_widget(ml) - - contacts = [ - ["Annie", "555-24235", "http://myphotos.com/annie.png"], - ["Bob", "555-15423", "http://myphotos.com/bob.png"], - ["Claire", "555-66098", "http://myphotos.com/claire.png"] - ] - - for c in contacts: - item = TwoLineAvatarIconListItem( - text=c[0], - secondary_text=c[1] - ) - item.add_widget(ContactPhoto(source=c[2])) - item.add_widget(MessageButton(phone_number=c[1]) - ml.add_widget(item) - -API ---- -''' - -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty, NumericProperty, \ - ListProperty, OptionProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.gridlayout import GridLayout -import kivymd.material_resources as m_res -from kivymd.ripplebehavior import RectangularRippleBehavior -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' -#:import m_res kivymd.material_resources - - cols: 1 - size_hint_y: None - height: self._min_list_height - padding: 0, self._list_vertical_padding - - - size_hint_y: None - canvas: - Color: - rgba: self.theme_cls.divider_color - Line: - points: root.x,root.y, root.x+self.width,root.y - BoxLayout: - id: _text_container - orientation: 'vertical' - pos: root.pos - padding: root._txt_left_pad, root._txt_top_pad, root._txt_right_pad, root._txt_bot_pad - MDLabel: - id: _lbl_primary - text: root.text - font_style: root.font_style - theme_text_color: root.theme_text_color - text_color: root.text_color - size_hint_y: None - height: self.texture_size[1] - MDLabel: - id: _lbl_secondary - text: '' if root._num_lines == 1 else root.secondary_text - font_style: root.secondary_font_style - theme_text_color: root.secondary_theme_text_color - text_color: root.secondary_text_color - size_hint_y: None - height: 0 if root._num_lines == 1 else self.texture_size[1] - shorten: True if root._num_lines == 2 else False - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height/2 - self.height/2 - size: dp(40), dp(40) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(40), dp(40) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height/2 - self.height/2 - size: dp(48), dp(48) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) -''') - - -class MDList(GridLayout): - '''ListItem container. Best used in conjunction with a - :class:`kivy.uix.ScrollView`. - - When adding (or removing) a widget, it will resize itself to fit its - children, plus top and bottom paddings as described by the MD spec. - ''' - selected = ObjectProperty() - _min_list_height = dp(16) - _list_vertical_padding = dp(8) - - icon = StringProperty() - - def add_widget(self, widget, index=0): - super(MDList, self).add_widget(widget, index) - self.height += widget.height - - def remove_widget(self, widget): - super(MDList, self).remove_widget(widget) - self.height -= widget.height - - -class BaseListItem(ThemableBehavior, RectangularRippleBehavior, - ButtonBehavior, FloatLayout): - '''Base class to all ListItems. Not supposed to be instantiated on its own. - ''' - - text = StringProperty() - '''Text shown in the first line. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` and defaults - to "". - ''' - - text_color = ListProperty(None) - ''' Text color used if theme_text_color is set to 'Custom' ''' - - font_style = OptionProperty( - 'Subhead', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - theme_text_color = StringProperty('Primary',allownone=True) - ''' Theme text color for primary text ''' - - secondary_text = StringProperty() - '''Text shown in the second and potentially third line. - - The text will wrap into the third line if the ListItem's type is set to - \'one-line\'. It can be forced into the third line by adding a \\n - escape sequence. - - :attr:`secondary_text` is a :class:`~kivy.properties.StringProperty` and - defaults to "". - ''' - - secondary_text_color = ListProperty(None) - ''' Text color used for secondary text if secondary_theme_text_color - is set to 'Custom' ''' - - secondary_theme_text_color = StringProperty('Secondary',allownone=True) - ''' Theme text color for secondary primary text ''' - - secondary_font_style = OptionProperty( - 'Body1', options=['Body1', 'Body2', 'Caption', 'Subhead', 'Title', - 'Headline', 'Display1', 'Display2', 'Display3', - 'Display4', 'Button', 'Icon']) - - _txt_left_pad = NumericProperty(dp(16)) - _txt_top_pad = NumericProperty() - _txt_bot_pad = NumericProperty() - _txt_right_pad = NumericProperty(m_res.HORIZ_MARGINS) - _num_lines = 2 - - -class ILeftBody: - '''Pseudo-interface for widgets that go in the left container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - ''' - pass - - -class ILeftBodyTouch: - '''Same as :class:`~ILeftBody`, but allows the widget to receive touch - events instead of triggering the ListItem's ripple effect - ''' - pass - - -class IRightBody: - '''Pseudo-interface for widgets that go in the right container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - ''' - pass - - -class IRightBodyTouch: - '''Same as :class:`~IRightBody`, but allows the widget to receive touch - events instead of triggering the ListItem's ripple effect - ''' - pass - - -class ContainerSupport: - '''Overrides add_widget in a ListItem to include support for I*Body - widgets when the appropiate containers are present. - ''' - _touchable_widgets = ListProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, ILeftBody): - self.ids['_left_container'].add_widget(widget) - elif issubclass(widget.__class__, ILeftBodyTouch): - self.ids['_left_container'].add_widget(widget) - self._touchable_widgets.append(widget) - elif issubclass(widget.__class__, IRightBody): - self.ids['_right_container'].add_widget(widget) - elif issubclass(widget.__class__, IRightBodyTouch): - self.ids['_right_container'].add_widget(widget) - self._touchable_widgets.append(widget) - else: - return super(BaseListItem, self).add_widget(widget,index) - - def remove_widget(self, widget): - super(BaseListItem, self).remove_widget(widget) - if widget in self._touchable_widgets: - self._touchable_widgets.remove(widget) - - def on_touch_down(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, 'down'): - return - super(BaseListItem, self).on_touch_down(touch) - - def on_touch_move(self, touch, *args): - if self.propagate_touch_to_touchable_widgets(touch, 'move', *args): - return - super(BaseListItem, self).on_touch_move(touch, *args) - - def on_touch_up(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, 'up'): - return - super(BaseListItem, self).on_touch_up(touch) - - def propagate_touch_to_touchable_widgets(self, touch, touch_event, *args): - triggered = False - for i in self._touchable_widgets: - if i.collide_point(touch.x, touch.y): - triggered = True - if touch_event == 'down': - i.on_touch_down(touch) - elif touch_event == 'move': - i.on_touch_move(touch, *args) - elif touch_event == 'up': - i.on_touch_up(touch) - return triggered - - -class OneLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(16)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 1 - - def __init__(self, **kwargs): - super(OneLineListItem, self).__init__(**kwargs) - self.height = dp(48) - - -class TwoLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - - def __init__(self, **kwargs): - super(TwoLineListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineListItem(BaseListItem): - _txt_top_pad = NumericProperty(dp(16)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 3 - - def __init__(self, **kwargs): - super(ThreeLineListItem, self).__init__(**kwargs) - self.height = dp(88) - - -class OneLineAvatarListItem(ContainerSupport, BaseListItem): - _txt_left_pad = NumericProperty(dp(72)) - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(19)) # dp(24) - dp(5) - _num_lines = 1 - - def __init__(self, **kwargs): - super(OneLineAvatarListItem, self).__init__(**kwargs) - self.height = dp(56) - - -class TwoLineAvatarListItem(OneLineAvatarListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineAvatarListItem(ContainerSupport, ThreeLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class OneLineIconListItem(ContainerSupport, OneLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class TwoLineIconListItem(OneLineIconListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineIconListItem(ContainerSupport, ThreeLineListItem): - _txt_left_pad = NumericProperty(dp(72)) - - -class OneLineRightIconListItem(ContainerSupport, OneLineListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class TwoLineRightIconListItem(OneLineRightIconListItem): - _txt_top_pad = NumericProperty(dp(20)) - _txt_bot_pad = NumericProperty(dp(15)) # dp(20) - dp(5) - _num_lines = 2 - - def __init__(self, **kwargs): - super(BaseListItem, self).__init__(**kwargs) - self.height = dp(72) - - -class ThreeLineRightIconListitem(ContainerSupport, ThreeLineListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class OneLineAvatarIconListItem(OneLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class TwoLineAvatarIconListItem(TwoLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) - - -class ThreeLineAvatarIconListItem(ThreeLineAvatarListItem): - # dp(40) = dp(16) + dp(24): - _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS) diff --git a/src/kivymd/material_resources.py b/src/kivymd/material_resources.py deleted file mode 100644 index 46270e5c..00000000 --- a/src/kivymd/material_resources.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy import platform -from kivy.core.window import Window -from kivy.metrics import dp -from kivymd import fonts_path - -# Feel free to override this const if you're designing for a device such as -# a GNU/Linux tablet. -if platform != "android" and platform != "ios": - DEVICE_TYPE = "desktop" -elif Window.width >= dp(600) and Window.height >= dp(600): - DEVICE_TYPE = "tablet" -else: - DEVICE_TYPE = "mobile" - -if DEVICE_TYPE == "mobile": - MAX_NAV_DRAWER_WIDTH = dp(300) - HORIZ_MARGINS = dp(16) - STANDARD_INCREMENT = dp(56) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - dp(8) -else: - MAX_NAV_DRAWER_WIDTH = dp(400) - HORIZ_MARGINS = dp(24) - STANDARD_INCREMENT = dp(64) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - -TOUCH_TARGET_HEIGHT = dp(48) - -FONTS = [ - { - "name": "Roboto", - "fn_regular": fonts_path + 'Roboto-Regular.ttf', - "fn_bold": fonts_path + 'Roboto-Medium.ttf', - "fn_italic": fonts_path + 'Roboto-Italic.ttf', - "fn_bolditalic": fonts_path + 'Roboto-MediumItalic.ttf' - }, - { - "name": "RobotoLight", - "fn_regular": fonts_path + 'Roboto-Thin.ttf', - "fn_bold": fonts_path + 'Roboto-Light.ttf', - "fn_italic": fonts_path + 'Roboto-ThinItalic.ttf', - "fn_bolditalic": fonts_path + 'Roboto-LightItalic.ttf' - }, - { - "name": "Icons", - "fn_regular": fonts_path + 'Material-Design-Iconic-Font.ttf' - } -] diff --git a/src/kivymd/menu.py b/src/kivymd/menu.py deleted file mode 100644 index f4c96ac8..00000000 --- a/src/kivymd/menu.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.garden.recycleview import RecycleView -from kivy.metrics import dp -from kivy.properties import NumericProperty, ListProperty, OptionProperty, \ - StringProperty -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -import kivymd.material_resources as m_res -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' -#:import STD_INC kivymd.material_resources.STANDARD_INCREMENT - - size_hint_y: None - height: dp(48) - padding: dp(16), 0 - on_release: root.parent.parent.parent.parent.dismiss() # Horrible, but hey it works - MDLabel: - text: root.text - theme_text_color: 'Primary' - - - size_hint: None, None - width: root.width_mult * STD_INC - key_viewclass: 'viewclass' - key_size: 'height' - - - FloatLayout: - id: fl - MDMenu: - id: md_menu - data: root.items - width_mult: root.width_mult - size_hint: None, None - size: 0,0 - canvas.before: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: self.size - pos: self.pos -''') - - -class MDMenuItem(ButtonBehavior, BoxLayout): - text = StringProperty() - - -class MDMenu(RecycleView): - width_mult = NumericProperty(1) - - -class MDDropdownMenu(ThemableBehavior, BoxLayout): - items = ListProperty() - '''See :attr:`~kivy.garden.recycleview.RecycleView.data` - ''' - - width_mult = NumericProperty(1) - '''This number multiplied by the standard increment (56dp on mobile, - 64dp on desktop, determines the width of the menu items. - - If the resulting number were to be too big for the application Window, - the multiplier will be adjusted for the biggest possible one. - ''' - - max_height = NumericProperty() - '''The menu will grow no bigger than this number. - - Set to 0 for no limit. Defaults to 0. - ''' - - border_margin = NumericProperty(dp(4)) - '''Margin between Window border and menu - ''' - - ver_growth = OptionProperty(None, allownone=True, - options=['up', 'down']) - '''Where the menu will grow vertically to when opening - - Set to None to let the widget pick for you. Defaults to None. - ''' - - hor_growth = OptionProperty(None, allownone=True, - options=['left', 'right']) - '''Where the menu will grow horizontally to when opening - - Set to None to let the widget pick for you. Defaults to None. - ''' - - def open(self, *largs): - Window.add_widget(self) - Clock.schedule_once(lambda x: self.display_menu(largs[0]), -1) - - def display_menu(self, caller): - # We need to pick a starting point, see how big we need to be, - # and where to grow to. - - c = caller.to_window(caller.center_x, - caller.center_y) # Starting coords - - # ---ESTABLISH INITIAL TARGET SIZE ESTIMATE--- - target_width = self.width_mult * m_res.STANDARD_INCREMENT - # If we're wider than the Window... - if target_width > Window.width: - # ...reduce our multiplier to max allowed. - target_width = int( - Window.width / m_res.STANDARD_INCREMENT) * m_res.STANDARD_INCREMENT - - target_height = sum([dp(48) for i in self.items]) - # If we're over max_height... - if 0 < self.max_height < target_height: - target_height = self.max_height - - # ---ESTABLISH VERTICAL GROWTH DIRECTION--- - if self.ver_growth is not None: - ver_growth = self.ver_growth - else: - # If there's enough space below us: - if target_height <= c[1] - self.border_margin: - ver_growth = 'down' - # if there's enough space above us: - elif target_height < Window.height - c[1] - self.border_margin: - ver_growth = 'up' - # otherwise, let's pick the one with more space and adjust ourselves - else: - # if there's more space below us: - if c[1] >= Window.height - c[1]: - ver_growth = 'down' - target_height = c[1] - self.border_margin - # if there's more space above us: - else: - ver_growth = 'up' - target_height = Window.height - c[1] - self.border_margin - - if self.hor_growth is not None: - hor_growth = self.hor_growth - else: - # If there's enough space to the right: - if target_width <= Window.width - c[0] - self.border_margin: - hor_growth = 'right' - # if there's enough space to the left: - elif target_width < c[0] - self.border_margin: - hor_growth = 'left' - # otherwise, let's pick the one with more space and adjust ourselves - else: - # if there's more space to the right: - if Window.width - c[0] >= c[0]: - hor_growth = 'right' - target_width = Window.width - c[0] - self.border_margin - # if there's more space to the left: - else: - hor_growth = 'left' - target_width = c[0] - self.border_margin - - if ver_growth == 'down': - tar_y = c[1] - target_height - else: # should always be 'up' - tar_y = c[1] - - if hor_growth == 'right': - tar_x = c[0] - else: # should always be 'left' - tar_x = c[0] - target_width - anim = Animation(x=tar_x, y=tar_y, - width=target_width, height=target_height, - duration=.3, transition='out_quint') - menu = self.ids['md_menu'] - menu.pos = c - anim.start(menu) - - def on_touch_down(self, touch): - if not self.ids['md_menu'].collide_point(*touch.pos): - self.dismiss() - return True - super(MDDropdownMenu, self).on_touch_down(touch) - return True - - def on_touch_move(self, touch): - super(MDDropdownMenu, self).on_touch_move(touch) - return True - - def on_touch_up(self, touch): - super(MDDropdownMenu, self).on_touch_up(touch) - return True - - def dismiss(self): - Window.remove_widget(self) diff --git a/src/kivymd/navigationdrawer.py b/src/kivymd/navigationdrawer.py deleted file mode 100644 index 42aa9a62..00000000 --- a/src/kivymd/navigationdrawer.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.icon_definitions import md_icons -from kivymd.label import MDLabel -from kivymd.list import OneLineIconListItem, ILeftBody, BaseListItem -from kivymd.slidingpanel import SlidingPanel -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - canvas: - Color: - rgba: root.theme_cls.divider_color - Line: - points: self.x, self.y, self.x+self.width,self.y - - - _list: list - elevation: 0 - canvas: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: root.size - pos: root.pos - NavDrawerToolbar: - title: root.title - opposite_colors: False - title_theme_color: 'Secondary' - background_color: root.theme_cls.bg_light - elevation: 0 - ScrollView: - do_scroll_x: False - MDList: - id: ml - id: list - - - NDIconLabel: - id: _icon - font_style: 'Icon' - theme_text_color: 'Secondary' -''') - - -class NavigationDrawer(SlidingPanel, ThemableBehavior, ElevationBehavior): - title = StringProperty() - - _list = ObjectProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, BaseListItem): - self._list.add_widget(widget, index) - widget.bind(on_release=lambda x: self.toggle()) - else: - super(NavigationDrawer, self).add_widget(widget, index) - - def _get_main_animation(self, duration, t, x, is_closing): - a = super(NavigationDrawer, self)._get_main_animation(duration, t, x, - is_closing) - a &= Animation(elevation=0 if is_closing else 5, t=t, duration=duration) - return a - - -class NDIconLabel(ILeftBody, MDLabel): - pass - - -class NavigationDrawerIconButton(OneLineIconListItem): - icon = StringProperty() - - def on_icon(self, instance, value): - self.ids['_icon'].text = u"{}".format(md_icons[value]) diff --git a/src/kivymd/progressbar.py b/src/kivymd/progressbar.py deleted file mode 100644 index 6d3a2ca8..00000000 --- a/src/kivymd/progressbar.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import ListProperty, OptionProperty, BooleanProperty -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.progressbar import ProgressBar - - -Builder.load_string(''' -: - canvas: - Clear - Color: - rgba: self.theme_cls.divider_color - Rectangle: - size: (self.width , dp(4)) if self.orientation == 'horizontal' else (dp(4),self.height) - pos: (self.x, self.center_y - dp(4)) if self.orientation == 'horizontal' \ - else (self.center_x - dp(4),self.y) - - - Color: - rgba: self.theme_cls.primary_color - Rectangle: - size: (self.width*self.value_normalized, sp(4)) if self.orientation == 'horizontal' else (sp(4), \ - self.height*self.value_normalized) - pos: (self.width*(1-self.value_normalized)+self.x if self.reversed else self.x, self.center_y - dp(4)) \ - if self.orientation == 'horizontal' else \ - (self.center_x - dp(4),self.height*(1-self.value_normalized)+self.y if self.reversed else self.y) - -''') - - -class MDProgressBar(ThemableBehavior, ProgressBar): - reversed = BooleanProperty(False) - ''' Reverse the direction the progressbar moves. ''' - - orientation = OptionProperty('horizontal', options=['horizontal', 'vertical']) - ''' Orientation of progressbar''' - - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class ProgressBarApp(App): - theme_cls = ThemeManager() - - def build(self): - return Builder.load_string("""#:import MDSlider kivymd.slider.MDSlider -BoxLayout: - orientation:'vertical' - padding: '8dp' - MDSlider: - id:slider - min:0 - max:100 - value: 40 - - MDProgressBar: - value: slider.value - MDProgressBar: - reversed: True - value: slider.value - BoxLayout: - MDProgressBar: - orientation:"vertical" - reversed: True - value: slider.value - - MDProgressBar: - orientation:"vertical" - value: slider.value - -""") - - - ProgressBarApp().run() diff --git a/src/kivymd/ripplebehavior.py b/src/kivymd/ripplebehavior.py deleted file mode 100644 index 21dd3463..00000000 --- a/src/kivymd/ripplebehavior.py +++ /dev/null @@ -1,169 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.properties import ListProperty, NumericProperty, StringProperty, \ - BooleanProperty -from kivy.animation import Animation -from kivy.graphics import Color, Ellipse, StencilPush, StencilPop, \ - StencilUse, StencilUnUse, Rectangle - - -class CommonRipple(object): - ripple_rad = NumericProperty() - ripple_rad_default = NumericProperty(1) - ripple_post = ListProperty() - ripple_color = ListProperty() - ripple_alpha = NumericProperty(.5) - ripple_scale = NumericProperty(None) - ripple_duration_in_fast = NumericProperty(.3) - # FIXME: These speeds should be calculated based on widget size in dp - ripple_duration_in_slow = NumericProperty(2) - ripple_duration_out = NumericProperty(.3) - ripple_func_in = StringProperty('out_quad') - ripple_func_out = StringProperty('out_quad') - - doing_ripple = BooleanProperty(False) - finishing_ripple = BooleanProperty(False) - fading_out = BooleanProperty(False) - - def on_touch_down(self, touch): - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - - if not self.disabled: - if self.doing_ripple: - Animation.cancel_all(self, 'ripple_rad', 'ripple_color', - 'rect_color') - self.anim_complete() - self.ripple_rad = self.ripple_rad_default - self.ripple_pos = (touch.x, touch.y) - - if self.ripple_color != []: - pass - elif hasattr(self, 'theme_cls'): - self.ripple_color = self.theme_cls.ripple_color - else: - # If no theme, set Grey 300 - self.ripple_color = [0.8784313725490196, 0.8784313725490196, - 0.8784313725490196, self.ripple_alpha] - self.ripple_color[3] = self.ripple_alpha - - self.lay_canvas_instructions() - self.finish_rad = max(self.width, self.height) * self.ripple_scale - self.start_ripple() - return super(CommonRipple, self).on_touch_down(touch) - - def lay_canvas_instructions(self): - raise NotImplementedError - - def on_touch_move(self, touch, *args): - if not self.collide_point(touch.x, touch.y): - if not self.finishing_ripple and self.doing_ripple: - self.finish_ripple() - return super(CommonRipple, self).on_touch_move(touch, *args) - - def on_touch_up(self, touch): - if self.collide_point(touch.x, touch.y) and self.doing_ripple: - self.finish_ripple() - return super(CommonRipple, self).on_touch_up(touch) - - def start_ripple(self): - if not self.doing_ripple: - anim = Animation( - ripple_rad=self.finish_rad, - t='linear', - duration=self.ripple_duration_in_slow) - anim.bind(on_complete=self.fade_out) - self.doing_ripple = True - anim.start(self) - - def _set_ellipse(self, instance, value): - self.ellipse.size = (self.ripple_rad, self.ripple_rad) - - # Adjust ellipse pos here - - def _set_color(self, instance, value): - self.col_instruction.a = value[3] - - def finish_ripple(self): - if self.doing_ripple and not self.finishing_ripple: - Animation.cancel_all(self, 'ripple_rad') - anim = Animation(ripple_rad=self.finish_rad, - t=self.ripple_func_in, - duration=self.ripple_duration_in_fast) - anim.bind(on_complete=self.fade_out) - self.finishing_ripple = True - anim.start(self) - - def fade_out(self, *args): - rc = self.ripple_color - if not self.fading_out: - Animation.cancel_all(self, 'ripple_color') - anim = Animation(ripple_color=[rc[0], rc[1], rc[2], 0.], - t=self.ripple_func_out, - duration=self.ripple_duration_out) - anim.bind(on_complete=self.anim_complete) - self.fading_out = True - anim.start(self) - - def anim_complete(self, *args): - self.doing_ripple = False - self.finishing_ripple = False - self.fading_out = False - self.canvas.after.clear() - - -class RectangularRippleBehavior(CommonRipple): - ripple_scale = NumericProperty(2.75) - - def lay_canvas_instructions(self): - with self.canvas.after: - StencilPush() - Rectangle(pos=self.pos, size=self.size) - StencilUse() - self.col_instruction = Color(rgba=self.ripple_color) - self.ellipse = \ - Ellipse(size=(self.ripple_rad, self.ripple_rad), - pos=(self.ripple_pos[0] - self.ripple_rad / 2., - self.ripple_pos[1] - self.ripple_rad / 2.)) - StencilUnUse() - Rectangle(pos=self.pos, size=self.size) - StencilPop() - self.bind(ripple_color=self._set_color, - ripple_rad=self._set_ellipse) - - def _set_ellipse(self, instance, value): - super(RectangularRippleBehavior, self)._set_ellipse(instance, value) - self.ellipse.pos = (self.ripple_pos[0] - self.ripple_rad / 2., - self.ripple_pos[1] - self.ripple_rad / 2.) - - -class CircularRippleBehavior(CommonRipple): - ripple_scale = NumericProperty(1) - - def lay_canvas_instructions(self): - with self.canvas.after: - StencilPush() - self.stencil = Ellipse(size=(self.width * self.ripple_scale, - self.height * self.ripple_scale), - pos=(self.center_x - ( - self.width * self.ripple_scale) / 2, - self.center_y - ( - self.height * self.ripple_scale) / 2)) - StencilUse() - self.col_instruction = Color(rgba=self.ripple_color) - self.ellipse = Ellipse(size=(self.ripple_rad, self.ripple_rad), - pos=(self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.)) - StencilUnUse() - Ellipse(pos=self.pos, size=self.size) - StencilPop() - self.bind(ripple_color=self._set_color, - ripple_rad=self._set_ellipse) - - def _set_ellipse(self, instance, value): - super(CircularRippleBehavior, self)._set_ellipse(instance, value) - if self.ellipse.size[0] > self.width * .6 and not self.fading_out: - self.fade_out() - self.ellipse.pos = (self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.) diff --git a/src/kivymd/selectioncontrols.py b/src/kivymd/selectioncontrols.py deleted file mode 100644 index b918428a..00000000 --- a/src/kivymd/selectioncontrols.py +++ /dev/null @@ -1,240 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, NumericProperty -from kivy.uix.behaviors import ToggleButtonBehavior -from kivy.uix.label import Label -from kivy.uix.floatlayout import FloatLayout -from kivy.properties import AliasProperty, BooleanProperty -from kivy.metrics import dp, sp -from kivy.animation import Animation -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors -from kivymd.icon_definitions import md_icons -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import RoundElevationBehavior -from kivymd.ripplebehavior import CircularRippleBehavior -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.widget import Widget - -Builder.load_string(''' -: - canvas: - Clear - Color: - rgba: self.color - Rectangle: - texture: self.texture - size: self.texture_size - pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.) - - text: self._radio_icon if self.group else self._checkbox_icon - font_name: 'Icons' - font_size: sp(24) - color: self.theme_cls.primary_color if self.active else self.theme_cls.secondary_text_color - halign: 'center' - valign: 'middle' - -: - color: 1, 1, 1, 1 - canvas: - Color: - rgba: self.color - Ellipse: - size: self.size - pos: self.pos - -: - canvas.before: - Color: - rgba: self._track_color_disabled if self.disabled else \ - (self._track_color_active if self.active else self._track_color_normal) - Ellipse: - size: dp(16), dp(16) - pos: self.x, self.center_y - dp(8) - angle_start: 180 - angle_end: 360 - Rectangle: - size: self.width - dp(16), dp(16) - pos: self.x + dp(8), self.center_y - dp(8) - Ellipse: - size: dp(16), dp(16) - pos: self.right - dp(16), self.center_y - dp(8) - angle_start: 0 - angle_end: 180 - on_release: thumb.trigger_action() - - Thumb: - id: thumb - size_hint: None, None - size: dp(24), dp(24) - pos: root._thumb_pos - color: root.thumb_color_disabled if root.disabled else \ - (root.thumb_color_down if root.active else root.thumb_color) - elevation: 4 if root.active else 2 - on_release: setattr(root, 'active', not root.active) -''') - - -class MDCheckbox(ThemableBehavior, CircularRippleBehavior, - ToggleButtonBehavior, Label): - active = BooleanProperty(False) - - _checkbox_icon = StringProperty( - u"{}".format(md_icons['square-o'])) - _radio_icon = StringProperty(u"{}".format(md_icons['circle-o'])) - _icon_active = StringProperty(u"{}".format(md_icons['check-square'])) - - def __init__(self, **kwargs): - super(MDCheckbox, self).__init__(**kwargs) - self.register_event_type('on_active') - self.check_anim_out = Animation(font_size=0, duration=.1, t='out_quad') - self.check_anim_in = Animation(font_size=sp(24), duration=.1, - t='out_quad') - self.check_anim_out.bind( - on_complete=lambda *x: self.check_anim_in.start(self)) - - def on_state(self, *args): - if self.state == 'down': - self.check_anim_in.cancel(self) - self.check_anim_out.start(self) - self._radio_icon = u"{}".format(md_icons['dot-circle']) - self._checkbox_icon = u"{}".format(md_icons['check-square']) - self.active = True - else: - self.check_anim_in.cancel(self) - self.check_anim_out.start(self) - self._radio_icon = u"{}".format(md_icons['circle-o']) - self._checkbox_icon = u"{}".format( - md_icons['square-o']) - self.active = False - - def on_active(self, instance, value): - self.state = 'down' if value else 'normal' - - -class Thumb(RoundElevationBehavior, CircularRippleBehavior, ButtonBehavior, - Widget): - ripple_scale = NumericProperty(2) - - def _set_ellipse(self, instance, value): - self.ellipse.size = (self.ripple_rad, self.ripple_rad) - if self.ellipse.size[0] > self.width * 1.5 and not self.fading_out: - self.fade_out() - self.ellipse.pos = (self.center_x - self.ripple_rad / 2., - self.center_y - self.ripple_rad / 2.) - self.stencil.pos = ( - self.center_x - (self.width * self.ripple_scale) / 2, - self.center_y - (self.height * self.ripple_scale) / 2) - - -class MDSwitch(ThemableBehavior, ButtonBehavior, FloatLayout): - active = BooleanProperty(False) - - _thumb_color = ListProperty(get_color_from_hex(colors['Grey']['50'])) - - def _get_thumb_color(self): - return self._thumb_color - - def _set_thumb_color(self, color, alpha=None): - if len(color) == 2: - self._thumb_color = get_color_from_hex(colors[color[0]][color[1]]) - if alpha: - self._thumb_color[3] = alpha - elif len(color) == 4: - self._thumb_color = color - - thumb_color = AliasProperty(_get_thumb_color, _set_thumb_color, - bind=['_thumb_color']) - - _thumb_color_down = ListProperty([1, 1, 1, 1]) - - def _get_thumb_color_down(self): - return self._thumb_color_down - - def _set_thumb_color_down(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_down[3] = alpha - else: - self._thumb_color_down[3] = 1 - elif len(color) == 4: - self._thumb_color_down = color - - thumb_color_down = AliasProperty(_get_thumb_color_down, - _set_thumb_color_down, - bind=['_thumb_color_down']) - - _thumb_color_disabled = ListProperty( - get_color_from_hex(colors['Grey']['400'])) - - def _get_thumb_color_disabled(self): - return self._thumb_color_disabled - - def _set_thumb_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_disabled[3] = alpha - elif len(color) == 4: - self._thumb_color_disabled = color - - thumb_color_down = AliasProperty(_get_thumb_color_disabled, - _set_thumb_color_disabled, - bind=['_thumb_color_disabled']) - - _track_color_active = ListProperty() - _track_color_normal = ListProperty() - _track_color_disabled = ListProperty() - _thumb_pos = ListProperty([0, 0]) - - def __init__(self, **kwargs): - super(MDSwitch, self).__init__(**kwargs) - self.theme_cls.bind(theme_style=self._set_colors, - primary_color=self._set_colors, - primary_palette=self._set_colors) - self._set_colors() - - def _set_colors(self, *args): - self._track_color_normal = self.theme_cls.disabled_hint_text_color - if self.theme_cls.theme_style == 'Dark': - self._track_color_active = self.theme_cls.primary_color - self._track_color_active[3] = .5 - self._track_color_disabled = get_color_from_hex('FFFFFF') - self._track_color_disabled[3] = .1 - self.thumb_color = get_color_from_hex(colors['Grey']['400']) - self.thumb_color_down = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self.thumb_color_disabled = get_color_from_hex( - colors['Grey']['800']) - else: - self._track_color_active = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self._track_color_active[3] = .5 - self._track_color_disabled = self.theme_cls.disabled_hint_text_color - self.thumb_color_down = self.theme_cls.primary_color - - def on_pos(self, *args): - if self.active: - self._thumb_pos = (self.right - dp(12), self.center_y - dp(12)) - else: - self._thumb_pos = (self.x - dp(12), self.center_y - dp(12)) - self.bind(active=self._update_thumb) - - def _update_thumb(self, *args): - if self.active: - Animation.cancel_all(self, '_thumb_pos') - anim = Animation( - _thumb_pos=(self.right - dp(12), self.center_y - dp(12)), - duration=.2, - t='out_quad') - else: - Animation.cancel_all(self, '_thumb_pos') - anim = Animation( - _thumb_pos=(self.x - dp(12), self.center_y - dp(12)), - duration=.2, - t='out_quad') - anim.start(self) diff --git a/src/kivymd/slider.py b/src/kivymd/slider.py deleted file mode 100644 index 1166bea7..00000000 --- a/src/kivymd/slider.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.properties import StringProperty, ListProperty, NumericProperty,AliasProperty, BooleanProperty -from kivy.utils import get_color_from_hex -from kivy.metrics import dp, sp -from kivymd.color_definitions import colors -from kivymd.theming import ThemableBehavior -from kivy.uix.slider import Slider - - -Builder.load_string(''' -#:import Thumb kivymd.selectioncontrols.Thumb - -: - id: slider - canvas: - Clear - Color: - rgba: self._track_color_disabled if self.disabled else (self._track_color_active if self.active \ - else self._track_color_normal) - Rectangle: - size: (self.width - self.padding*2 - self._offset[0], dp(4)) if self.orientation == 'horizontal' \ - else (dp(4),self.height - self.padding*2 - self._offset[1]) - pos: (self.x + self.padding + self._offset[0], self.center_y - dp(4)) \ - if self.orientation == 'horizontal' else (self.center_x - dp(4),self.y + self.padding + self._offset[1]) - - # If 0 draw circle - Color: - rgba: [0,0,0,0] if not self._is_off else (self._track_color_disabled if self.disabled \ - else (self._track_color_active if self.active else self._track_color_normal)) - Line: - width: 2 - circle: (self.x+self.padding+dp(3),self.center_y-dp(2),8 if self.active else 6 ) \ - if self.orientation == 'horizontal' else (self.center_x-dp(2),self.y+self.padding+dp(3),8 \ - if self.active else 6) - - Color: - rgba: [0,0,0,0] if self._is_off \ - else (self.thumb_color_down if not self.disabled else self._track_color_disabled) - Rectangle: - size: ((self.width-self.padding*2)*self.value_normalized, sp(4)) \ - if slider.orientation == 'horizontal' else (sp(4), (self.height-self.padding*2)*self.value_normalized) - pos: (self.x + self.padding, self.center_y - dp(4)) if self.orientation == 'horizontal' \ - else (self.center_x - dp(4),self.y + self.padding) - Thumb: - id: thumb - size_hint: None, None - size: (dp(12), dp(12)) if root.disabled else ((dp(24), dp(24)) if root.active else (dp(16),dp(16))) - pos: (slider.value_pos[0] - dp(8), slider.center_y - thumb.height/2 - dp(2)) \ - if slider.orientation == 'horizontal' \ - else (slider.center_x - thumb.width/2 - dp(2), slider.value_pos[1]-dp(8)) - color: [0,0,0,0] if slider._is_off else (root._track_color_disabled if root.disabled \ - else root.thumb_color_down) - elevation: 0 if slider._is_off else (4 if root.active else 2) - -''') - - -class MDSlider(ThemableBehavior, Slider): - # If the slider is clicked - active = BooleanProperty(False) - - # Show the "off" ring when set to minimum value - show_off = BooleanProperty(True) - - # Internal state of ring - _is_off = BooleanProperty(False) - - # Internal adjustment to reposition sliders for ring - _offset = ListProperty((0, 0)) - - _thumb_color = ListProperty(get_color_from_hex(colors['Grey']['50'])) - - def _get_thumb_color(self): - return self._thumb_color - - def _set_thumb_color(self, color, alpha=None): - if len(color) == 2: - self._thumb_color = get_color_from_hex(colors[color[0]][color[1]]) - if alpha: - self._thumb_color[3] = alpha - elif len(color) == 4: - self._thumb_color = color - - thumb_color = AliasProperty(_get_thumb_color, _set_thumb_color, - bind=['_thumb_color']) - - _thumb_color_down = ListProperty([1, 1, 1, 1]) - - def _get_thumb_color_down(self): - return self._thumb_color_down - - def _set_thumb_color_down(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_down = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_down[3] = alpha - else: - self._thumb_color_down[3] = 1 - elif len(color) == 4: - self._thumb_color_down = color - - thumb_color_down = AliasProperty(_get_thumb_color_down, - _set_thumb_color_down, - bind=['_thumb_color_down']) - - _thumb_color_disabled = ListProperty( - get_color_from_hex(colors['Grey']['400'])) - - def _get_thumb_color_disabled(self): - return self._thumb_color_disabled - - def _set_thumb_color_disabled(self, color, alpha=None): - if len(color) == 2: - self._thumb_color_disabled = get_color_from_hex( - colors[color[0]][color[1]]) - if alpha: - self._thumb_color_disabled[3] = alpha - elif len(color) == 4: - self._thumb_color_disabled = color - - thumb_color_down = AliasProperty(_get_thumb_color_disabled, - _set_thumb_color_disabled, - bind=['_thumb_color_disabled']) - - _track_color_active = ListProperty() - _track_color_normal = ListProperty() - _track_color_disabled = ListProperty() - _thumb_pos = ListProperty([0, 0]) - - def __init__(self, **kwargs): - super(MDSlider, self).__init__(**kwargs) - self.theme_cls.bind(theme_style=self._set_colors, - primary_color=self._set_colors, - primary_palette=self._set_colors) - self._set_colors() - - def _set_colors(self, *args): - if self.theme_cls.theme_style == 'Dark': - self._track_color_normal = get_color_from_hex('FFFFFF') - self._track_color_normal[3] = .3 - self._track_color_active = self._track_color_normal - self._track_color_disabled = self._track_color_normal - self.thumb_color = get_color_from_hex(colors['Grey']['400']) - self.thumb_color_down = get_color_from_hex( - colors[self.theme_cls.primary_palette]['200']) - self.thumb_color_disabled = get_color_from_hex( - colors['Grey']['800']) - else: - self._track_color_normal = get_color_from_hex('000000') - self._track_color_normal[3] = 0.26 - self._track_color_active = get_color_from_hex('000000') - self._track_color_active[3] = 0.38 - self._track_color_disabled = get_color_from_hex('000000') - self._track_color_disabled[3] = 0.26 - self.thumb_color_down = self.theme_cls.primary_color - - def on_value_normalized(self, *args): - """ When the value == min set it to "off" state and make slider a ring """ - self._update_is_off() - - def on_show_off(self, *args): - self._update_is_off() - - def _update_is_off(self): - self._is_off = self.show_off and (self.value_normalized == 0) - - def on__is_off(self, *args): - self._update_offset() - - def on_active(self, *args): - self._update_offset() - - def _update_offset(self): - """ Offset is used to shift the sliders so the background color - shows through the off circle. - """ - d = 2 if self.active else 0 - self._offset = (dp(11+d), dp(11+d)) if self._is_off else (0, 0) - - def on_touch_down(self, touch): - if super(MDSlider, self).on_touch_down(touch): - self.active = True - - def on_touch_up(self,touch): - if super(MDSlider, self).on_touch_up(touch): - self.active = False -# thumb = self.ids['thumb'] -# if thumb.collide_point(*touch.pos): -# thumb.on_touch_down(touch) -# thumb.on_touch_up(touch) - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class SliderApp(App): - theme_cls = ThemeManager() - - def build(self): - return Builder.load_string(""" -BoxLayout: - orientation:'vertical' - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle disabled" - color: [0,0,0,1] - CheckBox: - on_press: slider.disabled = not slider.disabled - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle active" - color: [0,0,0,1] - CheckBox: - on_press: slider.active = not slider.active - BoxLayout: - size_hint_y:None - height: '48dp' - Label: - text:"Toggle show off" - color: [0,0,0,1] - CheckBox: - on_press: slider.show_off = not slider.show_off - - MDSlider: - id:slider - min:0 - max:100 - value: 40 - - MDSlider: - id:slider2 - orientation:"vertical" - min:0 - max:100 - value: 40 - -""") - - - SliderApp().run() diff --git a/src/kivymd/slidingpanel.py b/src/kivymd/slidingpanel.py deleted file mode 100644 index b818505a..00000000 --- a/src/kivymd/slidingpanel.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import OptionProperty, NumericProperty, StringProperty, \ - BooleanProperty, ListProperty -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.relativelayout import RelativeLayout - -Builder.load_string(""" -#: import Window kivy.core.window.Window - - orientation: 'vertical' - size_hint_x: None - width: dp(320) - x: -1 * self.width if self.side == 'left' else Window.width - - - canvas: - Color: - rgba: root.color - Rectangle: - size: root.size -""") - - -class PanelShadow(BoxLayout): - color = ListProperty([0, 0, 0, 0]) - - -class SlidingPanel(BoxLayout): - anim_length_close = NumericProperty(0.3) - anim_length_open = NumericProperty(0.3) - animation_t_open = StringProperty('out_sine') - animation_t_close = StringProperty('out_sine') - side = OptionProperty('left', options=['left', 'right']) - - _open = False - - def __init__(self, **kwargs): - super(SlidingPanel, self).__init__(**kwargs) - self.shadow = PanelShadow() - Clock.schedule_once(lambda x: Window.add_widget(self.shadow,89), 0) - Clock.schedule_once(lambda x: Window.add_widget(self,90), 0) - - def toggle(self): - Animation.stop_all(self, 'x') - Animation.stop_all(self.shadow, 'color') - if self._open: - if self.side == 'left': - target_x = -1 * self.width - else: - target_x = Window.width - - sh_anim = Animation(duration=self.anim_length_open, - t=self.animation_t_open, - color=[0, 0, 0, 0]) - sh_anim.start(self.shadow) - self._get_main_animation(duration=self.anim_length_close, - t=self.animation_t_close, - x=target_x, - is_closing=True).start(self) - self._open = False - else: - if self.side == 'left': - target_x = 0 - else: - target_x = Window.width - self.width - Animation(duration=self.anim_length_open, t=self.animation_t_open, - color=[0, 0, 0, 0.5]).start(self.shadow) - self._get_main_animation(duration=self.anim_length_open, - t=self.animation_t_open, - x=target_x, - is_closing=False).start(self) - self._open = True - - def _get_main_animation(self, duration, t, x, is_closing): - return Animation(duration=duration, t=t, x=x) - - def on_touch_down(self, touch): - # Prevents touch events from propagating to anything below the widget. - super(SlidingPanel, self).on_touch_down(touch) - if self.collide_point(*touch.pos) or self._open: - return True - - def on_touch_up(self, touch): - if not self.collide_point(touch.x, touch.y) and self._open: - self.toggle() - return True - super(SlidingPanel, self).on_touch_up(touch) diff --git a/src/kivymd/snackbar.py b/src/kivymd/snackbar.py deleted file mode 100644 index e0ac70e8..00000000 --- a/src/kivymd/snackbar.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -from collections import deque -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ObjectProperty, StringProperty, NumericProperty -from kivy.uix.relativelayout import RelativeLayout -from kivymd.material_resources import DEVICE_TYPE - -Builder.load_string(''' -#:import Window kivy.core.window.Window -#:import get_color_from_hex kivy.utils.get_color_from_hex -#:import MDFlatButton kivymd.button.MDFlatButton -#:import MDLabel kivymd.label.MDLabel -#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE -<_SnackbarWidget> - canvas: - Color: - rgb: get_color_from_hex('323232') - Rectangle: - size: self.size - size_hint_y: None - size_hint_x: 1 if DEVICE_TYPE == 'mobile' else None - height: dp(48) if _label.texture_size[1] < dp(30) else dp(80) - width: dp(24) + _label.width + _spacer.width + root.padding_right if root.button_text == '' else dp(24) + \ - _label.width + _spacer.width + _button.width + root.padding_right - top: 0 - x: 0 if DEVICE_TYPE == 'mobile' else Window.width/2 - self.width/2 - BoxLayout: - width: Window.width - root.padding_right - _spacer.width - dp(24) if DEVICE_TYPE == 'mobile' and \ - root.button_text == '' else Window.width - root.padding_right - _button.width - _spacer.width - dp(24) \ - if DEVICE_TYPE == 'mobile' else _label.texture_size[0] if (dp(568) - root.padding_right - _button.width - \ - _spacer.width - _label.texture_size[0] - dp(24)) >= 0 else (dp(568) - root.padding_right - _button.width - \ - _spacer.width - dp(24)) - size_hint_x: None - x: dp(24) - MDLabel: - id: _label - text: root.text - size: self.texture_size - BoxLayout: - id: _spacer - size_hint_x: None - x: _label.right - width: 0 - MDFlatButton: - id: _button - text: root.button_text - size_hint_x: None - x: _spacer.right if root.button_text != '' else root.right - center_y: root.height/2 - on_release: root.button_callback() -''') - - -class _SnackbarWidget(RelativeLayout): - text = StringProperty() - button_text = StringProperty() - button_callback = ObjectProperty() - duration = NumericProperty() - padding_right = NumericProperty(dp(24)) - - def __init__(self, text, duration, button_text='', button_callback=None, - **kwargs): - super(_SnackbarWidget, self).__init__(**kwargs) - self.text = text - self.button_text = button_text - self.button_callback = button_callback - self.duration = duration - self.ids['_label'].text_size = (None, None) - - def begin(self): - if self.button_text == '': - self.remove_widget(self.ids['_button']) - else: - self.ids['_spacer'].width = dp(16) if \ - DEVICE_TYPE == "mobile" else dp(40) - self.padding_right = dp(16) - Window.add_widget(self) - anim = Animation(y=0, duration=.3, t='out_quad') - anim.start(self) - Clock.schedule_once(lambda dt: self.die(), self.duration) - - def die(self): - anim = Animation(top=0, duration=.3, t='out_quad') - anim.bind(on_complete=lambda *args: _play_next(self)) - anim.bind(on_complete=lambda *args: Window.remove_widget(self)) - anim.start(self) - - -queue = deque() -playing = False - - -def make(text, button_text=None, button_callback=None, duration=3): - if button_text is not None and button_callback is not None: - queue.append(_SnackbarWidget(text=text, - button_text=button_text, - button_callback=button_callback, - duration=duration)) - else: - queue.append(_SnackbarWidget(text=text, - duration=duration)) - _play_next() - - -def _play_next(dying_widget=None): - global playing - if (dying_widget or not playing) and len(queue) > 0: - playing = True - queue.popleft().begin() - elif len(queue) == 0: - playing = False diff --git a/src/kivymd/spinner.py b/src/kivymd/spinner.py deleted file mode 100644 index 238062db..00000000 --- a/src/kivymd/spinner.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.widget import Widget -from kivy.properties import NumericProperty, ListProperty, BooleanProperty -from kivy.animation import Animation -from kivymd.theming import ThemableBehavior -from kivy.clock import Clock - -Builder.load_string(''' -: - canvas.before: - PushMatrix - Rotate: - angle: self._rotation_angle - origin: self.center - canvas: - Color: - rgba: self.color - a: self._alpha - Line: - circle: self.center_x, self.center_y, self.width / 2, \ - self._angle_start, self._angle_end - cap: 'square' - width: dp(2) - canvas.after: - PopMatrix - -''') - - -class MDSpinner(ThemableBehavior, Widget): - """:class:`MDSpinner` is an implementation of the circular progress - indicator in Google's Material Design. - - It can be used either as an indeterminate indicator that loops while - the user waits for something to happen, or as a determinate indicator. - - Set :attr:`determinate` to **True** to activate determinate mode, and - :attr:`determinate_time` to set the duration of the animation. - """ - - determinate = BooleanProperty(False) - """:attr:`determinate` is a :class:`~kivy.properties.BooleanProperty` and - defaults to False - """ - - determinate_time = NumericProperty(2) - """:attr:`determinate_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to 2 - """ - - active = BooleanProperty(True) - """Use :attr:`active` to start or stop the spinner. - - :attr:`active` is a :class:`~kivy.properties.BooleanProperty` and - defaults to True - """ - - color = ListProperty([]) - """:attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to 'self.theme_cls.primary_color' - """ - - _alpha = NumericProperty(0) - _rotation_angle = NumericProperty(360) - _angle_start = NumericProperty(0) - _angle_end = NumericProperty(8) - - def __init__(self, **kwargs): - super(MDSpinner, self).__init__(**kwargs) - Clock.schedule_interval(self._update_color, 5) - self.color = self.theme_cls.primary_color - self._alpha_anim_in = Animation(_alpha=1, duration=.8, t='out_quad') - self._alpha_anim_out = Animation(_alpha=0, duration=.3, t='out_quad') - self._alpha_anim_out.bind(on_complete=self._reset) - - if self.determinate: - self._start_determinate() - else: - self._start_loop() - - def _update_color(self, *args): - self.color = self.theme_cls.primary_color - - def _start_determinate(self, *args): - self._alpha_anim_in.start(self) - - _rot_anim = Animation(_rotation_angle=0, - duration=self.determinate_time * .7, - t='out_quad') - _rot_anim.start(self) - - _angle_start_anim = Animation(_angle_end=360, - duration=self.determinate_time, - t='in_out_quad') - _angle_start_anim.bind(on_complete=lambda *x: \ - self._alpha_anim_out.start(self)) - - _angle_start_anim.start(self) - - def _start_loop(self, *args): - if self._alpha == 0: - _rot_anim = Animation(_rotation_angle=0, - duration=2, - t='linear') - _rot_anim.start(self) - - self._alpha = 1 - self._alpha_anim_in.start(self) - _angle_start_anim = Animation(_angle_end=self._angle_end + 270, - duration=.6, - t='in_out_cubic') - _angle_start_anim.bind(on_complete=self._anim_back) - _angle_start_anim.start(self) - - def _anim_back(self, *args): - _angle_back_anim = Animation(_angle_start=self._angle_end - 8, - duration=.6, - t='in_out_cubic') - _angle_back_anim.bind(on_complete=self._start_loop) - - _angle_back_anim.start(self) - - def on__rotation_angle(self, *args): - if self._rotation_angle == 0: - self._rotation_angle = 360 - if not self.determinate: - _rot_anim = Animation(_rotation_angle=0, - duration=2) - _rot_anim.start(self) - - def _reset(self, *args): - Animation.cancel_all(self, '_angle_start', '_rotation_angle', - '_angle_end', '_alpha') - self._angle_start = 0 - self._angle_end = 8 - self._rotation_angle = 360 - self._alpha = 0 - self.active = False - - def on_active(self, *args): - if not self.active: - self._reset() - else: - if self.determinate: - self._start_determinate() - else: - self._start_loop() diff --git a/src/kivymd/tabs.py b/src/kivymd/tabs.py deleted file mode 100644 index c09f21c2..00000000 --- a/src/kivymd/tabs.py +++ /dev/null @@ -1,303 +0,0 @@ -# Created on Jul 8, 2016 -# -# The default kivy tab implementation seems like a stupid design to me. The -# ScreenManager is much better. -# -# @author: jrm - -from kivy.properties import StringProperty, DictProperty, ListProperty, \ - ObjectProperty, OptionProperty, BoundedNumericProperty -from kivy.uix.screenmanager import Screen -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.uix.boxlayout import BoxLayout -from kivymd.theming import ThemableBehavior -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.button import MDFlatButton - -Builder.load_string(""" -: - id: panel - orientation: 'vertical' if panel.tab_orientation in ['top','bottom'] else 'horizontal' - ScrollView: - id: scroll_view - size_hint_y: None - height: panel._tab_display_height[panel.tab_display_mode] - MDTabBar: - id: tab_bar - size_hint_y: None - height: panel._tab_display_height[panel.tab_display_mode] - background_color: panel.tab_color or panel.theme_cls.primary_color - canvas: - # Draw bottom border - Color: - rgba: (panel.tab_border_color or panel.tab_color or panel.theme_cls.primary_dark) - Rectangle: - size: (self.width,dp(2)) - ScreenManager: - id: tab_manager - current: root.current - screens: root.tabs - - -: - canvas: - Color: - rgba: self.panel.tab_color or self.panel.theme_cls.primary_color - Rectangle: - size: self.size - pos: self.pos - - # Draw indicator - Color: - rgba: (self.panel.tab_indicator_color or self.panel.theme_cls.accent_color) if self.tab \ - and self.tab.manager and self.tab.manager.current==self.tab.name else (self.panel.tab_border_color \ - or self.panel.tab_color or self.panel.theme_cls.primary_dark) - Rectangle: - size: (self.width,dp(2)) - pos: self.pos - - size_hint: (None,None) #(1, None) if self.panel.tab_width_mode=='fixed' else (None,None) - width: (_label.texture_size[0] + dp(16)) - padding: (dp(12), 0) - theme_text_color: 'Custom' - text_color: (self.panel.tab_text_color_active or app.theme_cls.bg_light if app.theme_cls.theme_style == "Light" \ - else app.theme_cls.opposite_bg_light) if self.tab and self.tab.manager \ - and self.tab.manager.current==self.tab.name else (self.panel.tab_text_color \ - or self.panel.theme_cls.primary_light) - on_press: - self.tab.dispatch('on_tab_press') - # self.tab.manager.current = self.tab.name - on_release: self.tab.dispatch('on_tab_release') - on_touch_down: self.tab.dispatch('on_tab_touch_down',*args) - on_touch_move: self.tab.dispatch('on_tab_touch_move',*args) - on_touch_up: self.tab.dispatch('on_tab_touch_up',*args) - - - MDLabel: - id: _label - text: root.tab.text if root.panel.tab_display_mode == 'text' else u"{}".format(md_icons[root.tab.icon]) - font_style: 'Button' if root.panel.tab_display_mode == 'text' else 'Icon' - size_hint_x: None# if root.panel.tab_width_mode=='fixed' else 1 - text_size: (None, root.height) - height: self.texture_size[1] - theme_text_color: root.theme_text_color - text_color: root.text_color - valign: 'middle' - halign: 'center' - opposite_colors: root.opposite_colors -""") - - -class MDTabBar(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - pass - - -class MDTabHeader(MDFlatButton): - """ Internal widget for headers based on MDFlatButton""" - - width = BoundedNumericProperty(dp(None), min=dp(72), max=dp(264), errorhandler=lambda x: dp(72)) - tab = ObjectProperty(None) - panel = ObjectProperty(None) - - -class MDTab(Screen): - """ A tab is simply a screen with meta information - that defines the content that goes in the tab header. - """ - __events__ = ('on_tab_touch_down', 'on_tab_touch_move', 'on_tab_touch_up', 'on_tab_press', 'on_tab_release') - - # Tab header text - text = StringProperty("") - - # Tab header icon - icon = StringProperty("circle") - - # Tab dropdown menu items - menu_items = ListProperty() - - # Tab dropdown menu (if you want to customize it) - menu = ObjectProperty(None) - - def __init__(self, **kwargs): - super(MDTab, self).__init__(**kwargs) - self.index = 0 - self.parent_widget = None - self.register_event_type('on_tab_touch_down') - self.register_event_type('on_tab_touch_move') - self.register_event_type('on_tab_touch_up') - self.register_event_type('on_tab_press') - self.register_event_type('on_tab_release') - - def on_leave(self, *args): - self.parent_widget.ids.tab_manager.transition.direction = self.parent_widget.prev_dir - - def on_tab_touch_down(self, *args): - pass - - def on_tab_touch_move(self, *args): - pass - - def on_tab_touch_up(self, *args): - pass - - def on_tab_press(self, *args): - par = self.parent_widget - if par.previous_tab is not self: - par.prev_dir = str(par.ids.tab_manager.transition.direction) - if par.previous_tab.index > self.index: - par.ids.tab_manager.transition.direction = "right" - elif par.previous_tab.index < self.index: - par.ids.tab_manager.transition.direction = "left" - par.ids.tab_manager.current = self.name - par.previous_tab = self - - def on_tab_release(self, *args): - pass - - def __repr__(self): - return "".format(self.name, self.text) - - -class MDTabbedPanel(ThemableBehavior, BackgroundColorBehavior, BoxLayout): - """ A tab panel that is implemented by delegating all tabs - to a ScreenManager. - """ - # If tabs should fill space - tab_width_mode = OptionProperty('stacked', options=['stacked', 'fixed']) - - # Where the tabs go - tab_orientation = OptionProperty('top', options=['top']) # ,'left','bottom','right']) - - # How tabs are displayed - tab_display_mode = OptionProperty('text', options=['text', 'icons']) # ,'both']) - _tab_display_height = DictProperty({'text': dp(46), 'icons': dp(46), 'both': dp(72)}) - - # Tab background color (leave empty for theme color) - tab_color = ListProperty([]) - - # Tab text color in normal state (leave empty for theme color) - tab_text_color = ListProperty([]) - - # Tab text color in active state (leave empty for theme color) - tab_text_color_active = ListProperty([]) - - # Tab indicator color (leave empty for theme color) - tab_indicator_color = ListProperty([]) - - # Tab bar bottom border color (leave empty for theme color) - tab_border_color = ListProperty([]) - - # List of all the tabs so you can dynamically change them - tabs = ListProperty([]) - - # Current tab name - current = StringProperty(None) - - def __init__(self, **kwargs): - super(MDTabbedPanel, self).__init__(**kwargs) - self.previous_tab = None - self.prev_dir = None - self.index = 0 - self._refresh_tabs() - - def on_tab_width_mode(self, *args): - self._refresh_tabs() - - def on_tab_display_mode(self, *args): - self._refresh_tabs() - - def _refresh_tabs(self): - """ Refresh all tabs """ - # if fixed width, use a box layout - if not self.ids: - return - tab_bar = self.ids.tab_bar - tab_bar.clear_widgets() - tab_manager = self.ids.tab_manager - for tab in tab_manager.screens: - tab_header = MDTabHeader(tab=tab, - panel=self, - height=tab_bar.height, - ) - tab_bar.add_widget(tab_header) - - def add_widget(self, widget, **kwargs): - """ Add tabs to the screen or the layout. - :param widget: The widget to add. - """ - d = {} - if isinstance(widget, MDTab): - self.index += 1 - if self.index == 1: - self.previous_tab = widget - widget.index = self.index - widget.parent_widget = self - self.ids.tab_manager.add_widget(widget) - self._refresh_tabs() - else: - super(MDTabbedPanel, self).add_widget(widget) - - def remove_widget(self, widget): - """ Remove tabs from the screen or the layout. - :param widget: The widget to remove. - """ - self.index -= 1 - if isinstance(widget, MDTab): - self.ids.tab_manager.remove_widget(widget) - self._refresh_tabs() - else: - super(MDTabbedPanel, self).remove_widget(widget) - - -if __name__ == '__main__': - from kivy.app import App - from kivymd.theming import ThemeManager - - class TabsApp(App): - theme_cls = ThemeManager() - - def build(self): - from kivy.core.window import Window - Window.size = (540, 720) - # self.theme_cls.theme_style = 'Dark' - - return Builder.load_string(""" -#:import Toolbar kivymd.toolbar.Toolbar -BoxLayout: - orientation:'vertical' - Toolbar: - id: toolbar - title: 'Page title' - background_color: app.theme_cls.primary_color - left_action_items: [['menu', lambda x: '']] - right_action_items: [['search', lambda x: ''],['more-vert',lambda x:'']] - MDTabbedPanel: - id: tab_mgr - tab_display_mode:'icons' - - MDTab: - name: 'music' - text: "Music" # Why are these not set!!! - icon: "playlist-audio" - MDLabel: - font_style: 'Body1' - theme_text_color: 'Primary' - text: "Here is my music list :)" - halign: 'center' - MDTab: - name: 'movies' - text: 'Movies' - icon: "movie" - - MDLabel: - font_style: 'Body1' - theme_text_color: 'Primary' - text: "Show movies here :)" - halign: 'center' - - -""") - - - TabsApp().run() diff --git a/src/kivymd/textfields.py b/src/kivymd/textfields.py deleted file mode 100644 index 18de10e6..00000000 --- a/src/kivymd/textfields.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.textinput import TextInput -from kivy.properties import ObjectProperty, NumericProperty, StringProperty, \ - ListProperty, BooleanProperty -from kivy.metrics import sp, dp -from kivy.animation import Animation -from kivymd.label import MDLabel -from kivymd.theming import ThemableBehavior -from kivy.clock import Clock - -Builder.load_string(''' -: - canvas.before: - Clear - Color: - rgba: self.line_color_normal - Line: - id: "the_line" - points: self.x, self.y + dp(8), self.x + self.width, self.y + dp(8) - width: 1 - dash_length: dp(3) - dash_offset: 2 if self.disabled else 0 - Color: - rgba: self._current_line_color - Rectangle: - size: self._line_width, dp(2) - pos: self.center_x - (self._line_width / 2), self.y + dp(8) - Color: - rgba: self._current_error_color - Rectangle: - texture: self._msg_lbl.texture - size: self._msg_lbl.texture_size - pos: self.x, self.y - dp(8) - Color: - rgba: (self._current_line_color if self.focus and not self.cursor_blink \ - else (0, 0, 0, 0)) - Rectangle: - pos: [int(x) for x in self.cursor_pos] - size: 1, -self.line_height - Color: - #rgba: self._hint_txt_color if not self.text and not self.focus\ - #else (self.line_color_focus if not self.text or self.focus\ - #else self.line_color_normal) - rgba: self._current_hint_text_color - Rectangle: - texture: self._hint_lbl.texture - size: self._hint_lbl.texture_size - pos: self.x, self.y + self._hint_y - Color: - rgba: self.disabled_foreground_color if self.disabled else \ - (self.hint_text_color if not self.text and not self.focus else \ - self.foreground_color) - - font_name: 'Roboto' - foreground_color: app.theme_cls.text_color - font_size: sp(16) - bold: False - padding: 0, dp(16), 0, dp(10) - multiline: False - size_hint_y: None - height: dp(48) -''') - - -class SingleLineTextField(ThemableBehavior, TextInput): - line_color_normal = ListProperty() - line_color_focus = ListProperty() - error_color = ListProperty() - error = BooleanProperty(False) - message = StringProperty("") - message_mode = StringProperty("none") - mode = message_mode - - _hint_txt_color = ListProperty() - _hint_lbl = ObjectProperty() - _hint_lbl_font_size = NumericProperty(sp(16)) - _hint_y = NumericProperty(dp(10)) - _error_label = ObjectProperty() - _line_width = NumericProperty(0) - _hint_txt = StringProperty('') - _current_line_color = line_color_focus - _current_error_color = ListProperty([0.0, 0.0, 0.0, 0.0]) - _current_hint_text_color = _hint_txt_color - - def __init__(self, **kwargs): - Clock.schedule_interval(self._update_color, 5) - self._msg_lbl = MDLabel(font_style='Caption', - theme_text_color='Error', - halign='left', - valign='middle', - text=self.message) - - self._hint_lbl = MDLabel(font_style='Subhead', - halign='left', - valign='middle') - super(SingleLineTextField, self).__init__(**kwargs) - self.line_color_normal = self.theme_cls.divider_color - self.line_color_focus = list(self.theme_cls.primary_color) - self.base_line_color_focus = list(self.theme_cls.primary_color) - self.error_color = self.theme_cls.error_color - - self._hint_txt_color = self.theme_cls.disabled_hint_text_color - self.hint_text_color = (1, 1, 1, 0) - self.cursor_color = self.theme_cls.primary_color - self.bind(message=self._set_msg, - hint_text=self._set_hint, - _hint_lbl_font_size=self._hint_lbl.setter('font_size'), - message_mode=self._set_mode) - self.hint_anim_in = Animation(_hint_y=dp(34), - _hint_lbl_font_size=sp(12), duration=.2, - t='out_quad') - - self.hint_anim_out = Animation(_hint_y=dp(10), - _hint_lbl_font_size=sp(16), duration=.2, - t='out_quad') - - def _update_color(self, *args): - self.line_color_normal = self.theme_cls.divider_color - self.base_line_color_focus = list(self.theme_cls.primary_color) - if not self.focus and not self.error: - self.line_color_focus = self.theme_cls.primary_color - Animation(duration=.2, _current_hint_text_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.mode == "persistent": - Animation(duration=.1, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.focus and not self.error: - self.cursor_color = self.theme_cls.primary_color - - def on_hint_text_color(self, instance, color): - self._hint_txt_color = self.theme_cls.disabled_hint_text_color - self.hint_text_color = (1, 1, 1, 0) - - def on_width(self, instance, width): - if self.focus and instance is not None or self.error and instance is not None: - self._line_width = width - self.anim = Animation(_line_width=width, duration=.2, t='out_quad') - self._msg_lbl.width = self.width - self._hint_lbl.width = self.width - - def on_pos(self, *args): - self.hint_anim_in = Animation(_hint_y=dp(34), - _hint_lbl_font_size=sp(12), duration=.2, - t='out_quad') - self.hint_anim_out = Animation(_hint_y=dp(10), - _hint_lbl_font_size=sp(16), duration=.2, - t='out_quad') - - def on_focus(self, *args): - if self.focus: - Animation.cancel_all(self, '_line_width', '_hint_y', - '_hint_lbl_font_size') - if len(self.text) == 0: - self.hint_anim_in.start(self) - if self.error: - Animation(duration=.2, _current_hint_text_color=self.error_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=self.error_color).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - else: - pass - elif not self.error: - self.on_width(None, self.width) - self.anim.start(self) - Animation(duration=.2, _current_hint_text_color=self.line_color_focus).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - if self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - else: - pass - else: - Animation.cancel_all(self, '_line_width', '_hint_y', - '_hint_lbl_font_size') - if len(self.text) == 0: - self.hint_anim_out.start(self) - if not self.error: - self.line_color_focus = self.base_line_color_focus - Animation(duration=.2, _current_line_color=self.line_color_focus, - _current_hint_text_color=self.theme_cls.disabled_hint_text_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - - self.on_width(None, 0) - self.anim.start(self) - elif self.error: - Animation(duration=.2, _current_line_color=self.error_color, - _current_hint_text_color=self.error_color).start(self) - if self.mode == "on_error": - Animation(duration=.2, _current_error_color=self.error_color).start(self) - elif self.mode == "persistent": - Animation(duration=.2, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) - elif self.mode == "on_focus": - Animation(duration=.2, _current_error_color=(0, 0, 0, 0)).start(self) - - def _set_hint(self, instance, text): - self._hint_lbl.text = text - - def _set_msg(self, instance, text): - self._msg_lbl.text = text - self.message = text - - def _set_mode(self, instance, text): - self.mode = text - if self.mode == "persistent": - Animation(duration=.1, _current_error_color=self.theme_cls.disabled_hint_text_color).start(self) diff --git a/src/kivymd/theme_picker.py b/src/kivymd/theme_picker.py deleted file mode 100644 index e5104ce6..00000000 --- a/src/kivymd/theme_picker.py +++ /dev/null @@ -1,422 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivy.uix.floatlayout import FloatLayout -from kivy.uix.boxlayout import BoxLayout -from kivymd.button import MDFlatButton, MDIconButton -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivy.properties import ObjectProperty, ListProperty -from kivymd.label import MDLabel -from kivy.metrics import dp -from kivy.utils import get_color_from_hex -from kivymd.color_definitions import colors - -Builder.load_string(""" -#:import SingleLineTextField kivymd.textfields.SingleLineTextField -#:import MDTabbedPanel kivymd.tabs.MDTabbedPanel -#:import MDTab kivymd.tabs.MDTab -: - size_hint: (None, None) - size: dp(260), dp(120)+dp(290) - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgb: app.theme_cls.primary_color - Rectangle: - size: dp(260), dp(120) - pos: root.pos[0], root.pos[1] + root.height-dp(120) - Color: - rgb: app.theme_cls.bg_normal - Rectangle: - size: dp(260), dp(290) - pos: root.pos[0], root.pos[1] + root.height-(dp(120)+dp(290)) - - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(10) - text: "Close" - on_release: root.dismiss() - MDLabel: - font_style: "Headline" - text: "Change theme" - size_hint: (None, None) - size: dp(160), dp(50) - pos_hint: {'center_x': 0.5, 'center_y': 0.9} - MDTabbedPanel: - size_hint: (None, None) - size: dp(260), root.height-dp(135) - pos_hint: {'center_x': 0.5, 'center_y': 0.475} - id: tab_panel - tab_display_mode:'text' - - MDTab: - name: 'color' - text: "Theme Color" - BoxLayout: - spacing: dp(4) - size_hint: (None, None) - size: dp(270), root.height # -dp(120) - pos_hint: {'center_x': 0.532, 'center_y': 0.89} - orientation: 'vertical' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': 0.5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Red') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Red' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Pink') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Pink' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Purple') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Purple' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('DeepPurple') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'DeepPurple' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Indigo') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Indigo' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Blue') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Blue' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('LightBlue') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'LightBlue' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Cyan') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Cyan' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - halign: 'center' - orientation: 'horizontal' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Teal') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Teal' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Green') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Green' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('LightGreen') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'LightGreen' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Lime') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Lime' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - pos: self.pos - orientation: 'horizontal' - halign: 'center' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Yellow') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Yellow' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Amber') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Amber' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Orange') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Orange' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('DeepOrange') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'DeepOrange' - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .5, 'center_y': 0.5} - size: dp(230), dp(40) - #pos: self.pos - orientation: 'horizontal' - padding: 0, 0, 0, dp(1) - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Brown') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Brown' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('Grey') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'Grey' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - #pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: root.rgb_hex('BlueGrey') - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.primary_palette = 'BlueGrey' - BoxLayout: - MDIconButton: - size: dp(40), dp(40) - size_hint: (None, None) - canvas: - Color: - rgba: app.theme_cls.bg_normal - Ellipse: - size: self.size - pos: self.pos - disabled: True - - MDTab: - name: 'style' - text: "Theme Style" - BoxLayout: - size_hint: (None, None) - pos_hint: {'center_x': .3, 'center_y': 0.5} - size: self.size - pos: self.pos - halign: 'center' - spacing: dp(10) - BoxLayout: - halign: 'center' - size_hint: (None, None) - size: dp(100), dp(100) - pos: self.pos - pos_hint: {'center_x': .3, 'center_y': 0.5} - MDIconButton: - size: dp(100), dp(100) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: 1, 1, 1, 1 - Ellipse: - size: self.size - pos: self.pos - Color: - rgba: 0, 0, 0, 1 - Line: - width: 1. - circle: (self.center_x, self.center_y, 50) - on_release: app.theme_cls.theme_style = 'Light' - BoxLayout: - halign: 'center' - size_hint: (None, None) - size: dp(100), dp(100) - MDIconButton: - size: dp(100), dp(100) - pos: self.pos - size_hint: (None, None) - canvas: - Color: - rgba: 0, 0, 0, 1 - Ellipse: - size: self.size - pos: self.pos - on_release: app.theme_cls.theme_style = 'Dark' -""") - - -class MDThemePicker(ThemableBehavior, FloatLayout, ModalView, ElevationBehavior): - # background_color = ListProperty([0, 0, 0, 0]) - time = ObjectProperty() - - def __init__(self, **kwargs): - super(MDThemePicker, self).__init__(**kwargs) - - def rgb_hex(self, col): - return get_color_from_hex(colors[col][self.theme_cls.accent_hue]) - - -if __name__ == "__main__": - from kivy.app import App - from kivymd.theming import ThemeManager - - class ThemePickerApp(App): - theme_cls = ThemeManager() - - def build(self): - main_widget = Builder.load_string(""" -#:import MDRaisedButton kivymd.button.MDRaisedButton -#:import MDThemePicker kivymd.theme_picker.MDThemePicker -FloatLayout: - MDRaisedButton: - size_hint: None, None - pos_hint: {'center_x': .5, 'center_y': .5} - size: 3 * dp(48), dp(48) - center_x: self.parent.center_x - text: 'Open theme picker' - on_release: MDThemePicker().open() - opposite_colors: True -""") - return main_widget - - ThemePickerApp().run() diff --git a/src/kivymd/theming.py b/src/kivymd/theming.py deleted file mode 100644 index 3172ee58..00000000 --- a/src/kivymd/theming.py +++ /dev/null @@ -1,350 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.app import App -from kivy.core.text import LabelBase -from kivy.core.window import Window -from kivy.clock import Clock -from kivy.metrics import dp -from kivy.properties import OptionProperty, AliasProperty, ObjectProperty, \ - StringProperty, ListProperty, BooleanProperty -from kivy.uix.widget import Widget -from kivy.utils import get_color_from_hex -from kivy.atlas import Atlas -from kivymd.color_definitions import colors -from kivymd.material_resources import FONTS, DEVICE_TYPE -from kivymd import images_path - -for font in FONTS: - LabelBase.register(**font) - - -class ThemeManager(Widget): - primary_palette = OptionProperty( - 'Blue', - options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown', - 'LightBlue', - 'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange', - 'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber', - 'DeepPurple', 'Lime']) - - primary_hue = OptionProperty( - '500', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - primary_light_hue = OptionProperty( - '200', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - primary_dark_hue = OptionProperty( - '700', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - def _get_primary_color(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_hue]) - - primary_color = AliasProperty(_get_primary_color, - bind=('primary_palette', 'primary_hue')) - - def _get_primary_light(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_light_hue]) - - primary_light = AliasProperty( - _get_primary_light, bind=('primary_palette', 'primary_light_hue')) - - def _get_primary_dark(self): - return get_color_from_hex( - colors[self.primary_palette][self.primary_dark_hue]) - - primary_dark = AliasProperty(_get_primary_dark, - bind=('primary_palette', 'primary_dark_hue')) - - accent_palette = OptionProperty( - 'Amber', - options=['Pink', 'Blue', 'Indigo', 'BlueGrey', 'Brown', - 'LightBlue', - 'Purple', 'Grey', 'Yellow', 'LightGreen', 'DeepOrange', - 'Green', 'Red', 'Teal', 'Orange', 'Cyan', 'Amber', - 'DeepPurple', 'Lime']) - - accent_hue = OptionProperty( - '500', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - accent_light_hue = OptionProperty( - '200', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - accent_dark_hue = OptionProperty( - '700', - options=['50', '100', '200', '300', '400', '500', '600', '700', - '800', - '900', 'A100', 'A200', 'A400', 'A700']) - - def _get_accent_color(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_hue]) - - accent_color = AliasProperty(_get_accent_color, - bind=['accent_palette', 'accent_hue']) - - def _get_accent_light(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_light_hue]) - - accent_light = AliasProperty(_get_accent_light, - bind=['accent_palette', 'accent_light_hue']) - - def _get_accent_dark(self): - return get_color_from_hex( - colors[self.accent_palette][self.accent_dark_hue]) - - accent_dark = AliasProperty(_get_accent_dark, - bind=['accent_palette', 'accent_dark_hue']) - - theme_style = OptionProperty('Light', options=['Light', 'Dark']) - - def _get_theme_style(self, opposite): - if opposite: - return 'Light' if self.theme_style == 'Dark' else 'Dark' - else: - return self.theme_style - - def _get_bg_darkest(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['StatusBar']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['StatusBar']) - - bg_darkest = AliasProperty(_get_bg_darkest, bind=['theme_style']) - - def _get_op_bg_darkest(self): - return self._get_bg_darkest(True) - - opposite_bg_darkest = AliasProperty(_get_op_bg_darkest, - bind=['theme_style']) - - def _get_bg_dark(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['AppBar']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['AppBar']) - - bg_dark = AliasProperty(_get_bg_dark, bind=['theme_style']) - - def _get_op_bg_dark(self): - return self._get_bg_dark(True) - - opposite_bg_dark = AliasProperty(_get_op_bg_dark, bind=['theme_style']) - - def _get_bg_normal(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['Background']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['Background']) - - bg_normal = AliasProperty(_get_bg_normal, bind=['theme_style']) - - def _get_op_bg_normal(self): - return self._get_bg_normal(True) - - opposite_bg_normal = AliasProperty(_get_op_bg_normal, bind=['theme_style']) - - def _get_bg_light(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - return get_color_from_hex(colors['Light']['CardsDialogs']) - elif theme_style == 'Dark': - return get_color_from_hex(colors['Dark']['CardsDialogs']) - - bg_light = AliasProperty(_get_bg_light, bind=['theme_style']) - - def _get_op_bg_light(self): - return self._get_bg_light(True) - - opposite_bg_light = AliasProperty(_get_op_bg_light, bind=['theme_style']) - - def _get_divider_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .12 - return color - - divider_color = AliasProperty(_get_divider_color, bind=['theme_style']) - - def _get_op_divider_color(self): - return self._get_divider_color(True) - - opposite_divider_color = AliasProperty(_get_op_divider_color, - bind=['theme_style']) - - def _get_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .87 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - return color - - text_color = AliasProperty(_get_text_color, bind=['theme_style']) - - def _get_op_text_color(self): - return self._get_text_color(True) - - opposite_text_color = AliasProperty(_get_op_text_color, - bind=['theme_style']) - - def _get_secondary_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .54 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .70 - return color - - secondary_text_color = AliasProperty(_get_secondary_text_color, - bind=['theme_style']) - - def _get_op_secondary_text_color(self): - return self._get_secondary_text_color(True) - - opposite_secondary_text_color = AliasProperty(_get_op_secondary_text_color, - bind=['theme_style']) - - def _get_icon_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .54 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - return color - - icon_color = AliasProperty(_get_icon_color, - bind=['theme_style']) - - def _get_op_icon_color(self): - return self._get_icon_color(True) - - opposite_icon_color = AliasProperty(_get_op_icon_color, - bind=['theme_style']) - - def _get_disabled_hint_text_color(self, opposite=False): - theme_style = self._get_theme_style(opposite) - if theme_style == 'Light': - color = get_color_from_hex('000000') - color[3] = .26 - elif theme_style == 'Dark': - color = get_color_from_hex('FFFFFF') - color[3] = .30 - return color - - disabled_hint_text_color = AliasProperty(_get_disabled_hint_text_color, - bind=['theme_style']) - - def _get_op_disabled_hint_text_color(self): - return self._get_disabled_hint_text_color(True) - - opposite_disabled_hint_text_color = AliasProperty( - _get_op_disabled_hint_text_color, bind=['theme_style']) - - # Hardcoded because muh standard - def _get_error_color(self): - return get_color_from_hex(colors['Red']['A700']) - - error_color = AliasProperty(_get_error_color) - - def _get_ripple_color(self): - return self._ripple_color - - def _set_ripple_color(self, value): - self._ripple_color = value - - _ripple_color = ListProperty(get_color_from_hex(colors['Grey']['400'])) - ripple_color = AliasProperty(_get_ripple_color, - _set_ripple_color, - bind=['_ripple_color']) - - def _determine_device_orientation(self, _, window_size): - if window_size[0] > window_size[1]: - self.device_orientation = 'landscape' - elif window_size[1] >= window_size[0]: - self.device_orientation = 'portrait' - - device_orientation = StringProperty('') - - def _get_standard_increment(self): - if DEVICE_TYPE == 'mobile': - if self.device_orientation == 'landscape': - return dp(48) - else: - return dp(56) - else: - return dp(64) - - standard_increment = AliasProperty(_get_standard_increment, - bind=['device_orientation']) - - def _get_horizontal_margins(self): - if DEVICE_TYPE == 'mobile': - return dp(16) - else: - return dp(24) - - horizontal_margins = AliasProperty(_get_horizontal_margins) - - def on_theme_style(self, instance, value): - if hasattr(App.get_running_app(), 'theme_cls') and \ - App.get_running_app().theme_cls == self: - self.set_clearcolor_by_theme_style(value) - - def set_clearcolor_by_theme_style(self, theme_style): - if theme_style == 'Light': - Window.clearcolor = get_color_from_hex( - colors['Light']['Background']) - elif theme_style == 'Dark': - Window.clearcolor = get_color_from_hex( - colors['Dark']['Background']) - - def __init__(self, **kwargs): - super(ThemeManager, self).__init__(**kwargs) - self.rec_shadow = Atlas('{}rec_shadow.atlas'.format(images_path)) - self.rec_st_shadow = Atlas('{}rec_st_shadow.atlas'.format(images_path)) - self.quad_shadow = Atlas('{}quad_shadow.atlas'.format(images_path)) - self.round_shadow = Atlas('{}round_shadow.atlas'.format(images_path)) - Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style)) - self._determine_device_orientation(None, Window.size) - Window.bind(size=self._determine_device_orientation) - - -class ThemableBehavior(object): - theme_cls = ObjectProperty(None) - opposite_colors = BooleanProperty(False) - - def __init__(self, **kwargs): - if self.theme_cls is not None: - pass - elif hasattr(App.get_running_app(), 'theme_cls'): - self.theme_cls = App.get_running_app().theme_cls - else: - self.theme_cls = ThemeManager() - super(ThemableBehavior, self).__init__(**kwargs) diff --git a/src/kivymd/time_picker.py b/src/kivymd/time_picker.py deleted file mode 100644 index 6de6fc20..00000000 --- a/src/kivymd/time_picker.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- - -from kivy.lang import Builder -from kivy.uix.modalview import ModalView -from kivy.uix.floatlayout import FloatLayout -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior -from kivy.properties import ObjectProperty, ListProperty - -Builder.load_string(""" -#:import MDFlatButton kivymd.button.MDFlatButton -#:import CircularTimePicker kivymd.vendor.circularTimePicker.CircularTimePicker -#:import dp kivy.metrics.dp -: - size_hint: (None, None) - size: [dp(270), dp(335)+dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(520), dp(325)] - pos_hint: {'center_x': .5, 'center_y': .5} - canvas: - Color: - rgba: self.theme_cls.bg_light - Rectangle: - size: [dp(270), dp(335)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(250), root.height] - pos: [root.pos[0], root.pos[1] + root.height - dp(335) - dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [root.pos[0]+dp(270), root.pos[1]] - Color: - rgba: self.theme_cls.primary_color - Rectangle: - size: [dp(270), dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(270), root.height] - pos: [root.pos[0], root.pos[1] + root.height - dp(95)] - #if root.theme_cls.device_orientation == 'portrait' else [root.pos[0], root.pos[1]] - Color: - rgba: self.theme_cls.bg_dark - Ellipse: - size: [dp(220), dp(220)] - #if root.theme_cls.device_orientation == 'portrait' else [dp(195), dp(195)] - pos: root.pos[0]+dp(270)/2-dp(220)/2, root.pos[1] + root.height - (dp(335)/2+dp(95)) - dp(220)/2 + dp(35) - #Color: - #rgba: (1, 0, 0, 1) - #Line: - #width: 4 - #points: dp(270)/2, root.height, dp(270)/2, 0 - CircularTimePicker: - id: time_picker - pos: (dp(270)/2)-(self.width/2), root.height-self.height - size_hint: [.8, .8] - #if root.theme_cls.device_orientation == 'portrait' else [0.35, 0.9] - pos_hint: {'center_x': 0.5, 'center_y': 0.585} - #if root.theme_cls.device_orientation == 'portrait' else {'center_x': 0.75, 'center_y': 0.7} - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72)*2, root.pos[1] + dp(10) - text: "Cancel" - on_release: root.close_cancel() - MDFlatButton: - pos: root.pos[0]+root.size[0]-dp(72), root.pos[1] + dp(10) - text: "OK" - on_release: root.close_ok() -""") - - -class MDTimePicker(ThemableBehavior, FloatLayout, ModalView, ElevationBehavior): - # background_color = ListProperty((0, 0, 0, 0)) - time = ObjectProperty() - - def __init__(self, **kwargs): - super(MDTimePicker, self).__init__(**kwargs) - self.current_time = self.ids.time_picker.time - - def set_time(self, time): - try: - self.ids.time_picker.set_time(time) - except AttributeError: - raise TypeError("MDTimePicker._set_time must receive a datetime object, not a \"" + - type(time).__name__ + "\"") - - def close_cancel(self): - self.dismiss() - - def close_ok(self): - self.current_time = self.ids.time_picker.time - self.time = self.current_time - self.dismiss() diff --git a/src/kivymd/toolbar.py b/src/kivymd/toolbar.py deleted file mode 100644 index fc7b146c..00000000 --- a/src/kivymd/toolbar.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ListProperty, StringProperty, OptionProperty -from kivy.uix.boxlayout import BoxLayout -from kivymd.backgroundcolorbehavior import BackgroundColorBehavior -from kivymd.button import MDIconButton -from kivymd.theming import ThemableBehavior -from kivymd.elevationbehavior import ElevationBehavior - -Builder.load_string(''' -#:import m_res kivymd.material_resources - - size_hint_y: None - height: root.theme_cls.standard_increment - background_color: root.background_color - padding: [root.theme_cls.horizontal_margins - dp(12), 0] - opposite_colors: True - elevation: 6 - BoxLayout: - id: left_actions - orientation: 'horizontal' - size_hint_x: None - padding: [0, (self.height - dp(48))/2] - BoxLayout: - padding: dp(12), 0 - MDLabel: - font_style: 'Title' - opposite_colors: root.opposite_colors - theme_text_color: root.title_theme_color - text_color: root.title_color - text: root.title - shorten: True - shorten_from: 'right' - BoxLayout: - id: right_actions - orientation: 'horizontal' - size_hint_x: None - padding: [0, (self.height - dp(48))/2] -''') - - -class Toolbar(ThemableBehavior, ElevationBehavior, BackgroundColorBehavior, - BoxLayout): - left_action_items = ListProperty() - """The icons on the left of the Toolbar. - - To add one, append a list like the following: - - ['icon_name', callback] - - where 'icon_name' is a string that corresponds to an icon definition and - callback is the function called on a touch release event. - """ - - right_action_items = ListProperty() - """The icons on the left of the Toolbar. - - Works the same way as :attr:`left_action_items` - """ - - title = StringProperty() - """The text displayed on the Toolbar.""" - - title_theme_color = OptionProperty(None, allownone=True, - options=['Primary', 'Secondary', 'Hint', - 'Error', 'Custom']) - - title_color = ListProperty(None, allownone=True) - - background_color = ListProperty([0, 0, 0, 1]) - - def __init__(self, **kwargs): - super(Toolbar, self).__init__(**kwargs) - Clock.schedule_once( - lambda x: self.on_left_action_items(0, self.left_action_items)) - Clock.schedule_once( - lambda x: self.on_right_action_items(0, - self.right_action_items)) - - def on_left_action_items(self, instance, value): - self.update_action_bar(self.ids['left_actions'], value) - - def on_right_action_items(self, instance, value): - self.update_action_bar(self.ids['right_actions'], value) - - def update_action_bar(self, action_bar, action_bar_items): - action_bar.clear_widgets() - new_width = 0 - for item in action_bar_items: - new_width += dp(48) - action_bar.add_widget(MDIconButton(icon=item[0], - on_release=item[1], - opposite_colors=True, - text_color=self.title_color, - theme_text_color=self.title_theme_color)) - action_bar.width = new_width diff --git a/src/kivymd/vendor/__init__.py b/src/kivymd/vendor/__init__.py deleted file mode 100644 index 9bad5790..00000000 --- a/src/kivymd/vendor/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/src/kivymd/vendor/circleLayout/LICENSE b/src/kivymd/vendor/circleLayout/LICENSE deleted file mode 100644 index 9d6e5b59..00000000 --- a/src/kivymd/vendor/circleLayout/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Davide Depau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/src/kivymd/vendor/circleLayout/README.md b/src/kivymd/vendor/circleLayout/README.md deleted file mode 100644 index 6cf54bbe..00000000 --- a/src/kivymd/vendor/circleLayout/README.md +++ /dev/null @@ -1,21 +0,0 @@ -CircularLayout -============== - -CircularLayout is a special layout that places widgets around a circle. - -See the widget's documentation and the example for more information. - -![Screenshot](screenshot.png) - -size_hint ---------- - -size_hint_x is used as an angle-quota hint (widget with higher -size_hint_x will be farther from each other, and viceversa), while -size_hint_y is used as a widget size hint (widgets with a higher size -hint will be bigger).size_hint_x cannot be None. - -Widgets are all squares, unless you set size_hint_y to None (in that -case you'll be able to specify your own size), and their size is the -difference between the outer and the inner circle's radii. To make the -widgets bigger you can just decrease inner_radius_hint. \ No newline at end of file diff --git a/src/kivymd/vendor/circleLayout/__init__.py b/src/kivymd/vendor/circleLayout/__init__.py deleted file mode 100644 index 9d62c99c..00000000 --- a/src/kivymd/vendor/circleLayout/__init__.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -CircularLayout -============== - -CircularLayout is a special layout that places widgets around a circle. - -size_hint ---------- - -size_hint_x is used as an angle-quota hint (widget with higher -size_hint_x will be farther from each other, and vice versa), while -size_hint_y is used as a widget size hint (widgets with a higher size -hint will be bigger).size_hint_x cannot be None. - -Widgets are all squares, unless you set size_hint_y to None (in that -case you'll be able to specify your own size), and their size is the -difference between the outer and the inner circle's radii. To make the -widgets bigger you can just decrease inner_radius_hint. -""" - -from kivy.uix.layout import Layout -from kivy.properties import NumericProperty, ReferenceListProperty, OptionProperty, \ - BoundedNumericProperty, VariableListProperty, AliasProperty -from math import sin, cos, pi, radians - -__all__ = ('CircularLayout') - -try: - xrange(1, 2) -except NameError: - def xrange(first, second, third=None): - if third: - return range(first, second, third) - else: - return range(first, second) - - -class CircularLayout(Layout): - ''' - Circular layout class. See module documentation for more information. - ''' - - padding = VariableListProperty([0, 0, 0, 0]) - '''Padding between the layout box and it's children: [padding_left, - padding_top, padding_right, padding_bottom]. - - padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. - - .. version changed:: 1.7.0 - Replaced NumericProperty with VariableListProperty. - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and - defaults to [0, 0, 0, 0]. - ''' - - start_angle = NumericProperty(0) - '''Angle (in degrees) at which the first widget will be placed. - Start counting angles from the X axis, going counterclockwise. - - :attr:`start_angle` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0 (start from the right). - ''' - - circle_quota = BoundedNumericProperty(360, min=0, max=360) - '''Size (in degrees) of the part of the circumference that will actually - be used to place widgets. - - :attr:`circle_quota` is a :class:`~kivy.properties.BoundedNumericProperty` - and defaults to 360 (all the circumference). - ''' - - direction = OptionProperty("ccw", options=("cw", "ccw")) - '''Direction of widgets in the circle. - - :attr:`direction` is an :class:`~kivy.properties.OptionProperty` and - defaults to 'ccw'. Can be 'ccw' (counterclockwise) or 'cw' (clockwise). - ''' - - outer_radius_hint = NumericProperty(1) - '''Sets the size of the outer circle. A number greater than 1 will make the - widgets larger than the actual widget, a number smaller than 1 will leave - a gap. - - :attr:`outer_radius_hint` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - ''' - - inner_radius_hint = NumericProperty(.6) - '''Sets the size of the inner circle. A number greater than - :attr:`outer_radius_hint` will cause glitches. The closest it is to - :attr:`outer_radius_hint`, the smallest will be the widget in the layout. - - :attr:`outer_radius_hint` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - ''' - - radius_hint = ReferenceListProperty(inner_radius_hint, outer_radius_hint) - '''Combined :attr:`outer_radius_hint` and :attr:`inner_radius_hint` in a list - for convenience. See their documentation for more details. - - :attr:`radius_hint` is a :class:`~kivy.properties.ReferenceListProperty`. - ''' - - def _get_delta_radii(self): - radius = min(self.width-self.padding[0]-self.padding[2], self.height-self.padding[1]-self.padding[3]) / 2. - outer_r = radius * self.outer_radius_hint - inner_r = radius * self.inner_radius_hint - return outer_r - inner_r - delta_radii = AliasProperty(_get_delta_radii, None, bind=("radius_hint", "padding", "size")) - - def __init__(self, **kwargs): - super(CircularLayout, self).__init__(**kwargs) - - self.bind( - start_angle=self._trigger_layout, - parent=self._trigger_layout, - # padding=self._trigger_layout, - children=self._trigger_layout, - size=self._trigger_layout, - radius_hint=self._trigger_layout, - pos=self._trigger_layout) - - def do_layout(self, *largs): - # optimize layout by preventing looking at the same attribute in a loop - len_children = len(self.children) - if len_children == 0: - return - selfcx = self.center_x - selfcy = self.center_y - direction = self.direction - cquota = radians(self.circle_quota) - start_angle_r = radians(self.start_angle) - padding_left = self.padding[0] - padding_top = self.padding[1] - padding_right = self.padding[2] - padding_bottom = self.padding[3] - padding_x = padding_left + padding_right - padding_y = padding_top + padding_bottom - - radius = min(self.width-padding_x, self.height-padding_y) / 2. - outer_r = radius * self.outer_radius_hint - inner_r = radius * self.inner_radius_hint - middle_r = radius * sum(self.radius_hint) / 2. - delta_r = outer_r - inner_r - - stretch_weight_angle = 0. - for w in self.children: - sha = w.size_hint_x - if sha is None: - raise ValueError("size_hint_x cannot be None in a CircularLayout") - else: - stretch_weight_angle += sha - - sign = +1. - angle_offset = start_angle_r - if direction == 'cw': - angle_offset = 2 * pi - start_angle_r - sign = -1. - - for c in reversed(self.children): - sha = c.size_hint_x - shs = c.size_hint_y - - angle_quota = cquota / stretch_weight_angle * sha - angle = angle_offset + (sign * angle_quota / 2) - angle_offset += sign * angle_quota - - # kived: looking it up, yes. x = cos(angle) * radius + centerx; y = sin(angle) * radius + centery - ccx = cos(angle) * middle_r + selfcx + padding_left - padding_right - ccy = sin(angle) * middle_r + selfcy + padding_bottom - padding_top - - c.center_x = ccx - c.center_y = ccy - if shs: - s = delta_r * shs - c.width = s - c.height = s - -if __name__ == "__main__": - from kivy.app import App - from kivy.uix.button import Button - - class CircLayoutApp(App): - def build(self): - cly = CircularLayout(direction="cw", start_angle=-75, inner_radius_hint=.7, padding="20dp") - - for i in xrange(1, 13): - cly.add_widget(Button(text=str(i), font_size="30dp")) - - return cly - - CircLayoutApp().run() diff --git a/src/kivymd/vendor/circularTimePicker/LICENSE b/src/kivymd/vendor/circularTimePicker/LICENSE deleted file mode 100644 index 9d6e5b59..00000000 --- a/src/kivymd/vendor/circularTimePicker/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Davide Depau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/src/kivymd/vendor/circularTimePicker/README.md b/src/kivymd/vendor/circularTimePicker/README.md deleted file mode 100644 index 20ac2de9..00000000 --- a/src/kivymd/vendor/circularTimePicker/README.md +++ /dev/null @@ -1,43 +0,0 @@ -Circular Date & Time Picker for Kivy -==================================== - -(currently only time, date coming soon) - -Based on [CircularLayout](https://github.com/kivy-garden/garden.circularlayout). -The main aim is to provide a date and time selector similar to the -one found in Android KitKat+. - -![Screenshot](screenshot.png) - -Simple usage ------------- - -Import the widget with - -```python -from kivy.garden.circulardatetimepicker import CircularTimePicker -``` - -then use it! That's it! - -```python -c = CircularTimePicker() -c.bind(time=self.set_time) -root.add_widget(c) -``` - -in Kv language: - -``` -: - BoxLayout: - orientation: "vertical" - - CircularTimePicker - - Button: - text: "Dismiss" - size_hint_y: None - height: "40dp" - on_release: root.dismiss() -``` \ No newline at end of file diff --git a/src/kivymd/vendor/circularTimePicker/__init__.py b/src/kivymd/vendor/circularTimePicker/__init__.py deleted file mode 100644 index fbc73954..00000000 --- a/src/kivymd/vendor/circularTimePicker/__init__.py +++ /dev/null @@ -1,770 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -Circular Date & Time Picker for Kivy -==================================== - -(currently only time, date coming soon) - -Based on [CircularLayout](https://github.com/kivy-garden/garden.circularlayout). -The main aim is to provide a date and time selector similar to the -one found in Android KitKat+. - -Simple usage ------------- - -Import the widget with - -```python -from kivy.garden.circulardatetimepicker import CircularTimePicker -``` - -then use it! That's it! - -```python -c = CircularTimePicker() -c.bind(time=self.set_time) -root.add_widget(c) -``` - -in Kv language: - -``` -: - BoxLayout: - orientation: "vertical" - - CircularTimePicker - - Button: - text: "Dismiss" - size_hint_y: None - height: "40dp" - on_release: root.dismiss() -``` -""" - -from kivy.animation import Animation -from kivy.clock import Clock -from kivymd.vendor.circleLayout import CircularLayout -from kivy.graphics import Line, Color, Ellipse -from kivy.lang import Builder -from kivy.properties import NumericProperty, BoundedNumericProperty, \ - ObjectProperty, StringProperty, DictProperty, \ - ListProperty, OptionProperty, BooleanProperty, \ - ReferenceListProperty, AliasProperty -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.label import Label -from kivy.metrics import dp -from kivymd.theming import ThemableBehavior -from math import atan, pi, radians, sin, cos -import sys -import datetime -if sys.version_info[0] > 2: - def xrange(first=None, second=None, third=None): - if third: - return range(first, second, third) - else: - return range(first, second) - - -def map_number(x, in_min, in_max, out_min, out_max): - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min - - -def rgb_to_hex(*color): - tor = "#" - for col in color: - tor += "{:>02}".format(hex(int(col * 255))[2:]) - return tor - - -Builder.load_string(""" - -: - text_size: self.size - valign: "middle" - halign: "center" - font_size: self.height * self.size_factor - -: - canvas.before: - PushMatrix - Scale: - origin: self.center_x + self.padding[0] - self.padding[2], self.center_y + self.padding[3] - self.padding[1] - x: self.scale - y: self.scale - - canvas.after: - PopMatrix - -: - orientation: "vertical" - spacing: "20dp" - - FloatLayout: - anchor_x: "center" - anchor_y: "center" - size_hint_y: 1./3 - size_hint_x: 1 - size: root.size - pos: root.pos - - GridLayout: - cols: 2 - spacing: "10dp" - size_hint_x: None - width: self.minimum_width - pos_hint: {'center_x': .5, 'center_y': .5} - - Label: - id: timelabel - text: root.time_text - markup: True - halign: "right" - valign: "middle" - # text_size: self.size - size_hint_x: None #.6 - width: self.texture_size[0] - font_size: self.height * .75 - - Label: - id: ampmlabel - text: root.ampm_text - markup: True - halign: "left" - valign: "middle" - # text_size: self.size - size_hint_x: None #.4 - width: self.texture_size[0] - font_size: self.height * .3 - - FloatLayout: - id: picker_container - #size_hint_y: 2./3 - _bound: {} -""") - - -class Number(Label): - """The class used to show the numbers in the selector. - """ - - size_factor = NumericProperty(.5) - """Font size scale. - - :attr:`size_factor` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0.5. - """ - - -class CircularNumberPicker(CircularLayout): - """A circular number picker based on CircularLayout. A selector will - help you pick a number. You can also set :attr:`multiples_of` to make - it show only some numbers and use the space in between for the other - numbers. - """ - - min = NumericProperty(0) - """The first value of the range. - - :attr:`min` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - max = NumericProperty(0) - """The last value of the range. Note that it behaves like xrange, so - the actual last displayed value will be :attr:`max` - 1. - - :attr:`max` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - range = ReferenceListProperty(min, max) - """Packs :attr:`min` and :attr:`max` into a list for convenience. See - their documentation for further information. - - :attr:`range` is a :class:`~kivy.properties.ReferenceListProperty`. - """ - - multiples_of = NumericProperty(1) - """Only show numbers that are multiples of this number. The other numbers - will be selectable, but won't have their own label. - - :attr:`multiples_of` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - """ - - # selector_color = ListProperty([.337, .439, .490]) - selector_color = ListProperty([1, 1, 1]) - """Color of the number selector. RGB. - - :attr:`selector_color` is a :class:`~kivy.properties.ListProperty` and - defaults to [.337, .439, .490] (material green). - """ - - color = ListProperty([0, 0, 0]) - """Color of the number labels and of the center dot. RGB. - - :attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to [1, 1, 1] (white). - """ - - selector_alpha = BoundedNumericProperty(.3, min=0, max=1) - """Alpha value for the transparent parts of the selector. - - :attr:`selector_alpha` is a :class:`~kivy.properties.BoundedNumericProperty` and - defaults to 0.3 (min=0, max=1). - """ - - selected = NumericProperty(None) - """Currently selected number. - - :attr:`selected` is a :class:`~kivy.properties.NumericProperty` and - defaults to :attr:`min`. - """ - - number_size_factor = NumericProperty(.5) - """Font size scale factor fot the :class:`Number`s. - - :attr:`number_size_factor` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0.5. - """ - - number_format_string = StringProperty("{}") - """String that will be formatted with the selected number as the first argument. - Can be anything supported by :meth:`str.format` (es. "{:02d}"). - - :attr:`number_format_string` is a :class:`~kivy.properties.StringProperty` and - defaults to "{}". - """ - - scale = NumericProperty(1) - """Canvas scale factor. Used in :class:`CircularTimePicker` transitions. - - :attr:`scale` is a :class:`~kivy.properties.NumericProperty` and - defaults to 1. - """ - - _selection_circle = ObjectProperty(None) - _selection_line = ObjectProperty(None) - _selection_dot = ObjectProperty(None) - _selection_dot_color = ObjectProperty(None) - _selection_color = ObjectProperty(None) - _center_dot = ObjectProperty(None) - _center_color = ObjectProperty(None) - - def _get_items(self): - return self.max - self.min - - items = AliasProperty(_get_items, None) - - def _get_shown_items(self): - sh = 0 - for i in xrange(*self.range): - if i % self.multiples_of == 0: - sh += 1 - return sh - - shown_items = AliasProperty(_get_shown_items, None) - - def __init__(self, **kw): - self._trigger_genitems = Clock.create_trigger(self._genitems, -1) - self.bind(min=self._trigger_genitems, - max=self._trigger_genitems, - multiples_of=self._trigger_genitems) - super(CircularNumberPicker, self).__init__(**kw) - self.selected = self.min - self.bind(selected=self.on_selected, - pos=self.on_selected, - size=self.on_selected) - - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sx, sy = self.pos_for_number(self.selected) - epos = [i - (self.delta_radii * self.number_size_factor) for i in (sx, sy)] - esize = [self.delta_radii * self.number_size_factor * 2] * 2 - dsize = [i * .3 for i in esize] - dpos = [i + esize[0] / 2. - dsize[0] / 2. for i in epos] - csize = [i * .05 for i in esize] - cpos = [i - csize[0] / 2. for i in (cx, cy)] - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - color = list(self.selector_color) - - with self.canvas: - self._selection_color = Color(*(color + [self.selector_alpha])) - self._selection_circle = Ellipse(pos=epos, size=esize) - self._selection_line = Line(points=[cx, cy, sx, sy], width=dp(1.25)) - self._selection_dot_color = Color(*(color + [dot_alpha])) - self._selection_dot = Ellipse(pos=dpos, size=dsize) - self._center_color = Color(*self.color) - self._center_dot = Ellipse(pos=cpos, size=csize) - - self.bind(selector_color=lambda ign, u: setattr(self._selection_color, "rgba", u + [self.selector_alpha])) - self.bind(selector_color=lambda ign, u: setattr(self._selection_dot_color, "rgb", u)) - self.bind(selector_color=lambda ign, u: self.dot_is_none()) - self.bind(color=lambda ign, u: setattr(self._center_color, "rgb", u)) - Clock.schedule_once(self._genitems) - Clock.schedule_once(self.on_selected) # Just to make sure pos/size are set - - def dot_is_none(self, *args): - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - if self._selection_dot_color: - self._selection_dot_color.a = dot_alpha - - def _genitems(self, *a): - self.clear_widgets() - for i in xrange(*self.range): - if i % self.multiples_of != 0: - continue - n = Number(text=self.number_format_string.format(i), size_factor=self.number_size_factor, color=self.color) - self.bind(color=n.setter("color")) - self.add_widget(n) - - def on_touch_down(self, touch): - if not self.collide_point(*touch.pos): - return - touch.grab(self) - self.selected = self.number_at_pos(*touch.pos) - if self.selected == 60: - self.selected = 0 - - def on_touch_move(self, touch): - if touch.grab_current is not self: - return super(CircularNumberPicker, self).on_touch_move(touch) - self.selected = self.number_at_pos(*touch.pos) - if self.selected == 60: - self.selected = 0 - - def on_touch_up(self, touch): - if touch.grab_current is not self: - return super(CircularNumberPicker, self).on_touch_up(touch) - touch.ungrab(self) - - def on_selected(self, *a): - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sx, sy = self.pos_for_number(self.selected) - epos = [i - (self.delta_radii * self.number_size_factor) for i in (sx, sy)] - esize = [self.delta_radii * self.number_size_factor * 2] * 2 - dsize = [i * .3 for i in esize] - dpos = [i + esize[0] / 2. - dsize[0] / 2. for i in epos] - csize = [i * .05 for i in esize] - cpos = [i - csize[0] / 2. for i in (cx, cy)] - dot_alpha = 0 if self.selected % self.multiples_of == 0 else 1 - - if self._selection_circle: - self._selection_circle.pos = epos - self._selection_circle.size = esize - if self._selection_line: - self._selection_line.points = [cx, cy, sx, sy] - if self._selection_dot: - self._selection_dot.pos = dpos - self._selection_dot.size = dsize - if self._selection_dot_color: - self._selection_dot_color.a = dot_alpha - if self._center_dot: - self._center_dot.pos = cpos - self._center_dot.size = csize - - def pos_for_number(self, n): - """Returns the center x, y coordinates for a given number. - """ - - if self.items == 0: - return 0, 0 - radius = min(self.width - self.padding[0] - self.padding[2], - self.height - self.padding[1] - self.padding[3]) / 2. - middle_r = radius * sum(self.radius_hint) / 2. - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - sign = +1. - angle_offset = radians(self.start_angle) - if self.direction == 'cw': - angle_offset = 2 * pi - angle_offset - sign = -1. - quota = 2 * pi / self.items - mult_quota = 2 * pi / self.shown_items - angle = angle_offset + n * sign * quota - - if self.items == self.shown_items: - angle += quota / 2 - else: - angle -= mult_quota / 2 - - # kived: looking it up, yes. x = cos(angle) * radius + centerx; y = sin(angle) * radius + centery - x = cos(angle) * middle_r + cx - y = sin(angle) * middle_r + cy - - return x, y - - def number_at_pos(self, x, y): - """Returns the number at a given x, y position. The number is found - using the widget's center as a starting point for angle calculations. - - Not thoroughly tested, may yield wrong results. - """ - if self.items == 0: - return self.min - cx = self.center_x + self.padding[0] - self.padding[2] - cy = self.center_y + self.padding[3] - self.padding[1] - lx = x - cx - ly = y - cy - quota = 2 * pi / self.items - mult_quota = 2 * pi / self.shown_items - if lx == 0 and ly > 0: - angle = pi / 2 - elif lx == 0 and ly < 0: - angle = 3 * pi / 2 - else: - angle = atan(ly / lx) - if lx < 0 < ly: - angle += pi - if lx > 0 > ly: - angle += 2 * pi - if lx < 0 and ly < 0: - angle += pi - angle += radians(self.start_angle) - if self.direction == "cw": - angle = 2 * pi - angle - if mult_quota != quota: - angle -= mult_quota / 2 - if angle < 0: - angle += 2 * pi - elif angle > 2 * pi: - angle -= 2 * pi - - return int(angle / quota) + self.min - - -class CircularMinutePicker(CircularNumberPicker): - """:class:`CircularNumberPicker` implementation for minutes. - """ - - def __init__(self, **kw): - super(CircularMinutePicker, self).__init__(**kw) - self.min = 0 - self.max = 60 - self.multiples_of = 5 - self.number_format_string = "{:02d}" - self.direction = "cw" - self.bind(shown_items=self._update_start_angle) - Clock.schedule_once(self._update_start_angle) - Clock.schedule_once(self.on_selected) - - def _update_start_angle(self, *a): - self.start_angle = -(360. / self.shown_items / 2) - 90 - - -class CircularHourPicker(CircularNumberPicker): - """:class:`CircularNumberPicker` implementation for hours. - """ - - # military = BooleanProperty(False) - - def __init__(self, **kw): - super(CircularHourPicker, self).__init__(**kw) - self.min = 1 - self.max = 13 - # 25 if self.military else 13 - # self.inner_radius_hint = .8 if self.military else .6 - self.multiples_of = 1 - self.number_format_string = "{}" - self.direction = "cw" - self.bind(shown_items=self._update_start_angle) - # self.bind(military=lambda v: setattr(self, "max", 25 if v else 13)) - # self.bind(military=lambda v: setattr(self, "inner_radius_hint", .8 if self.military else .6)) - # Clock.schedule_once(self._genitems) - Clock.schedule_once(self._update_start_angle) - Clock.schedule_once(self.on_selected) - - def _update_start_angle(self, *a): - self.start_angle = (360. / self.shown_items / 2) - 90 - - -class CircularTimePicker(BoxLayout, ThemableBehavior): - """Widget that makes use of :class:`CircularHourPicker` and - :class:`CircularMinutePicker` to create a user-friendly, animated - time picker like the one seen on Android. - - See module documentation for more details. - """ - - primary_dark = ListProperty([1, 1, 1]) - - hours = NumericProperty(0) - """The hours, in military format (0-23). - - :attr:`hours` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0 (12am). - """ - - minutes = NumericProperty(0) - """The minutes. - - :attr:`minutes` is a :class:`~kivy.properties.NumericProperty` and - defaults to 0. - """ - - time_list = ReferenceListProperty(hours, minutes) - """Packs :attr:`hours` and :attr:`minutes` in a list for convenience. - - :attr:`time_list` is a :class:`~kivy.properties.ReferenceListProperty`. - """ - - # military = BooleanProperty(False) - time_format = StringProperty( - "[color={hours_color}][ref=hours]{hours}[/ref][/color][color={primary_dark}][ref=colon]:[/ref][/color]\ -[color={minutes_color}][ref=minutes]{minutes:02d}[/ref][/color]") - """String that will be formatted with the time and shown in the time label. - Can be anything supported by :meth:`str.format`. Make sure you don't - remove the refs. See the default for the arguments passed to format. - :attr:`time_format` is a :class:`~kivy.properties.StringProperty` and - defaults to "[color={hours_color}][ref=hours]{hours}[/ref][/color]:[color={minutes_color}][ref=minutes]\ - {minutes:02d}[/ref][/color]". - """ - - ampm_format = StringProperty( - "[color={am_color}][ref=am]AM[/ref][/color]\n[color={pm_color}][ref=pm]PM[/ref][/color]") - """String that will be formatted and shown in the AM/PM label. - Can be anything supported by :meth:`str.format`. Make sure you don't - remove the refs. See the default for the arguments passed to format. - - :attr:`ampm_format` is a :class:`~kivy.properties.StringProperty` and - defaults to "[color={am_color}][ref=am]AM[/ref][/color]\n[color={pm_color}][ref=pm]PM[/ref][/color]". - """ - - picker = OptionProperty("hours", options=("minutes", "hours")) - """Currently shown time picker. Can be one of "minutes", "hours". - - :attr:`picker` is a :class:`~kivy.properties.OptionProperty` and - defaults to "hours". - """ - - # selector_color = ListProperty([.337, .439, .490]) - selector_color = ListProperty([0, 0, 0]) - """Color of the number selector and of the highlighted text. RGB. - - :attr:`selector_color` is a :class:`~kivy.properties.ListProperty` and - defaults to [.337, .439, .490] (material green). - """ - - color = ListProperty([1, 1, 1]) - """Color of the number labels and of the center dot. RGB. - - :attr:`color` is a :class:`~kivy.properties.ListProperty` and - defaults to [1, 1, 1] (white). - """ - - selector_alpha = BoundedNumericProperty(.3, min=0, max=1) - """Alpha value for the transparent parts of the selector. - - :attr:`selector_alpha` is a :class:`~kivy.properties.BoundedNumericProperty` and - defaults to 0.3 (min=0, max=1). - """ - - _am = BooleanProperty(True) - _h_picker = ObjectProperty(None) - _m_picker = ObjectProperty(None) - _bound = DictProperty({}) - - def _get_time(self): - try: - return datetime.time(*self.time_list) - except ValueError: - self.time_list = [self.hours, 0] - return datetime.time(*self.time_list) - - def set_time(self, dt): - if dt.hour >= 12: - dt.strftime("%I:%M") - self._am = False - self.time_list = [dt.hour, dt.minute] - - time = AliasProperty(_get_time, set_time, bind=("time_list",)) - """Selected time as a datetime.time object. - - :attr:`time` is an :class:`~kivy.properties.AliasProperty`. - """ - - def _get_picker(self): - if self.picker == "hours": - return self._h_picker - return self._m_picker - - _picker = AliasProperty(_get_picker, None) - - def _get_time_text(self): - hc = rgb_to_hex(0, 0, 0) if self.picker == "hours" else rgb_to_hex(*self.primary_dark) - mc = rgb_to_hex(0, 0, 0) if self.picker == "minutes" else rgb_to_hex(*self.primary_dark) - h = self.hours == 0 and 12 or self.hours <= 12 and self.hours or self.hours - 12 - m = self.minutes - primary_dark = rgb_to_hex(*self.primary_dark) - return self.time_format.format(hours_color=hc, - minutes_color=mc, - hours=h, - minutes=m, - primary_dark=primary_dark) - time_text = AliasProperty(_get_time_text, None, bind=("hours", "minutes", "time_format", "picker")) - - def _get_ampm_text(self, *args): - amc = rgb_to_hex(0, 0, 0) if self._am else rgb_to_hex(*self.primary_dark) - pmc = rgb_to_hex(0, 0, 0) if not self._am else rgb_to_hex(*self.primary_dark) - return self.ampm_format.format(am_color=amc, - pm_color=pmc) - - ampm_text = AliasProperty(_get_ampm_text, None, bind=("hours", "ampm_format", "_am")) - - def __init__(self, **kw): - super(CircularTimePicker, self).__init__(**kw) - self.selector_color = self.theme_cls.primary_color[0], self.theme_cls.primary_color[1], \ - self.theme_cls.primary_color[2] - self.color = self.theme_cls.text_color - self.primary_dark = self.theme_cls.primary_dark[0] / 2, self.theme_cls.primary_dark[1] / 2, \ - self.theme_cls.primary_dark[2] / 2 - self.on_ampm() - if self.hours >= 12: - self._am = False - self.bind(time_list=self.on_time_list, - picker=self._switch_picker, - _am=self.on_ampm, - primary_dark=self._get_ampm_text) - self._h_picker = CircularHourPicker() - self.h_picker_touch = False - self._m_picker = CircularMinutePicker() - self.animating = False - Clock.schedule_once(self.on_selected) - Clock.schedule_once(self.on_time_list) - Clock.schedule_once(self._init_later) - Clock.schedule_once(lambda *a: self._switch_picker(noanim=True)) - - def _init_later(self, *args): - self.ids.timelabel.bind(on_ref_press=self.on_ref_press) - self.ids.ampmlabel.bind(on_ref_press=self.on_ref_press) - - def on_ref_press(self, ign, ref): - if not self.animating: - if ref == "hours": - self.picker = "hours" - elif ref == "minutes": - self.picker = "minutes" - if ref == "am": - self._am = True - elif ref == "pm": - self._am = False - - def on_selected(self, *a): - if not self._picker: - return - if self.picker == "hours": - hours = self._picker.selected if self._am else self._picker.selected + 12 - if hours == 24 and not self._am: - hours = 12 - elif hours == 12 and self._am: - hours = 0 - self.hours = hours - elif self.picker == "minutes": - self.minutes = self._picker.selected - - def on_time_list(self, *a): - if not self._picker: - return - self._h_picker.selected = self.hours == 0 and 12 or self._am and self.hours or self.hours - 12 - self._m_picker.selected = self.minutes - self.on_selected() - - def on_ampm(self, *a): - if self._am: - self.hours = self.hours if self.hours < 12 else self.hours - 12 - else: - self.hours = self.hours if self.hours >= 12 else self.hours + 12 - - def is_animating(self, *args): - self.animating = True - - def is_not_animating(self, *args): - self.animating = False - - def on_touch_down(self, touch): - if not self._h_picker.collide_point(*touch.pos): - self.h_picker_touch = False - else: - self.h_picker_touch = True - super(CircularTimePicker, self).on_touch_down(touch) - - def on_touch_up(self, touch): - try: - if not self.h_picker_touch: - return - if not self.animating: - if touch.grab_current is not self: - if self.picker == "hours": - self.picker = "minutes" - except AttributeError: - pass - super(CircularTimePicker, self).on_touch_up(touch) - - def _switch_picker(self, *a, **kw): - noanim = "noanim" in kw - if noanim: - noanim = kw["noanim"] - - try: - container = self.ids.picker_container - except (AttributeError, NameError): - Clock.schedule_once(lambda *a: self._switch_picker(noanim=noanim)) - - if self.picker == "hours": - picker = self._h_picker - prevpicker = self._m_picker - elif self.picker == "minutes": - picker = self._m_picker - prevpicker = self._h_picker - - if len(self._bound) > 0: - prevpicker.unbind(selected=self.on_selected) - self.unbind(**self._bound) - picker.bind(selected=self.on_selected) - self._bound = {"selector_color": picker.setter("selector_color"), - "color": picker.setter("color"), - "selector_alpha": picker.setter("selector_alpha")} - self.bind(**self._bound) - - if len(container._bound) > 0: - container.unbind(**container._bound) - container._bound = {"size": picker.setter("size"), - "pos": picker.setter("pos")} - container.bind(**container._bound) - - picker.pos = container.pos - picker.size = container.size - picker.selector_color = self.selector_color - picker.color = self.color - picker.selector_alpha = self.selector_alpha - if noanim: - if prevpicker in container.children: - container.remove_widget(prevpicker) - if picker.parent: - picker.parent.remove_widget(picker) - container.add_widget(picker) - else: - self.is_animating() - if prevpicker in container.children: - anim = Animation(scale=1.5, d=.5, t="in_back") & Animation(opacity=0, d=.5, t="in_cubic") - anim.start(prevpicker) - Clock.schedule_once(lambda *y: container.remove_widget(prevpicker), .5) # .31) - picker.scale = 1.5 - picker.opacity = 0 - if picker.parent: - picker.parent.remove_widget(picker) - container.add_widget(picker) - anim = Animation(scale=1, d=.5, t="out_back") & Animation(opacity=1, d=.5, t="out_cubic") - anim.bind(on_complete=self.is_not_animating) - Clock.schedule_once(lambda *y: anim.start(picker), .3) - - -if __name__ == "__main__": - from kivy.base import runTouchApp - - c = CircularTimePicker() - runTouchApp(c) diff --git a/src/main.py b/src/main.py index 969dbe56..22ea7c3e 100644 --- a/src/main.py +++ b/src/main.py @@ -1,8 +1,8 @@ """This module is for thread start.""" -from bitmessagemain import main import state if __name__ == '__main__': state.kivy = True - print("Kivy Loading......") + print("Kivy Loading for PyBitmessage......") + from bitmessagemain import main main() diff --git a/src/navigationdrawer/__init__.py b/src/navigationdrawer/__init__.py deleted file mode 100644 index a8fa5ce7..00000000 --- a/src/navigationdrawer/__init__.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -from kivy.animation import Animation -from kivy.lang import Builder -from kivy.properties import StringProperty, ObjectProperty -from kivymd.elevationbehavior import ElevationBehavior -from kivymd.icon_definitions import md_icons -from kivymd.label import MDLabel -from kivymd.list import OneLineIconListItem, ILeftBody, BaseListItem -from kivymd.slidingpanel import SlidingPanel -from kivymd.theming import ThemableBehavior - -Builder.load_string(''' - - canvas: - Color: - rgba: root.parent.parent.theme_cls.divider_color - Line: - points: self.x, self.y, self.x+self.width,self.y - - - widget_list: widget_list - elevation: 0 - canvas: - Color: - rgba: root.theme_cls.bg_light - Rectangle: - size: root.size - pos: root.pos - BoxLayout: - size_hint: (1, .4) - NavDrawerToolbar: - padding: 10, 10 - canvas.after: - Color: - rgba: (1, 1, 1, 1) - RoundedRectangle: - size: (self.size[1]-dp(14), self.size[1]-dp(14)) - pos: (self.pos[0]+(self.size[0]-self.size[1])/2, self.pos[1]+dp(7)) - source: root.image_source - radius: [self.size[1]-(self.size[1]/2)] - - ScrollView: - do_scroll_x: False - MDList: - id: ml - id: widget_list - - - NDIconLabel: - id: _icon - font_style: 'Icon' - theme_text_color: 'Secondary' -''') - - -class NavigationDrawer(SlidingPanel, ThemableBehavior, ElevationBehavior): - image_source = StringProperty() - widget_list = ObjectProperty() - - def add_widget(self, widget, index=0): - if issubclass(widget.__class__, BaseListItem): - self.widget_list.add_widget(widget, index) - widget.bind(on_release=lambda x: self.toggle()) - else: - super(NavigationDrawer, self).add_widget(widget, index) - - def _get_main_animation(self, duration, t, x, is_closing): - a = super(NavigationDrawer, self)._get_main_animation(duration, t, x, - is_closing) - a &= Animation(elevation=0 if is_closing else 5, t=t, duration=duration) - return a - - -class NDIconLabel(ILeftBody, MDLabel): - pass - - -class NavigationDrawerIconButton(OneLineIconListItem): - icon = StringProperty() - - def on_icon(self, instance, value): - self.ids['_icon'].text = u"{}".format(md_icons[value]) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 2a22367f..2ea8fcd7 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -19,7 +19,9 @@ class BMNetworkThread(StoppableThread): def run(self): try: while not self._stopped and state.shutdown == 0: + print("I am running in run method which calls a loop for BMConnectionPool line19..................................") BMConnectionPool().loop() + print("I am running in run method which calls a loop for BMConnectionPool line 21..................................") except Exception as e: excQueue.put((self.name, e)) raise diff --git a/src/paths.py b/src/paths.py index 325fcd8b..86190363 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,10 +1,11 @@ from os import environ, path import sys import re +import os from datetime import datetime - +from kivy.utils import platform # When using py2exe or py2app, the variable frozen is added to the sys -# namespace. This can be used to setup a different code path for +# namespace. This can be used to setup a different code path for # binary distributions vs source distributions. frozen = getattr(sys,'frozen', None) @@ -22,6 +23,10 @@ def lookupExeFolder(): return exeFolder def lookupAppdataFolder(): + + print("HIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", platform) + import traceback + print(traceback.print_tb) APPNAME = "PyBitmessage" if "BITMESSAGE_HOME" in environ: dataFolder = environ["BITMESSAGE_HOME"] @@ -37,6 +42,10 @@ def lookupAppdataFolder(): else: print stringToLog sys.exit() + elif platform == 'android': + # dataFolder = path.join(os.path.dirname(os.path.abspath("__file__")), "PyBitmessage") + '/' + dataFolder = path.join('/sdcard/', 'DCIM/', APPNAME) + '/' + print("YOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", dataFolder) elif 'win32' in sys.platform or 'win64' in sys.platform: dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep @@ -60,13 +69,13 @@ def lookupAppdataFolder(): pass dataFolder = dataFolder + '/' return dataFolder - + def codePath(): if frozen == "macosx_app": codePath = environ.get("RESOURCEPATH") elif frozen: # windows codePath = sys._MEIPASS - else: + else: codePath = path.dirname(__file__) return codePath @@ -87,7 +96,7 @@ def tail(f, lines=20): blocks.append(f.read(BLOCK_SIZE)) else: # file too small, start from begining - f.seek(0,0) + f.seek(0, 0) # only read what was not read blocks.append(f.read(block_end_byte)) lines_found = blocks[-1].count('\n') @@ -111,4 +120,4 @@ def lastCommit(): ) except (IOError, AttributeError, TypeError): pass - return result + return result \ No newline at end of file diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py index 7f21c6b8..c5a21ac3 100644 --- a/src/plugins/menu_qrcode.py +++ b/src/plugins/menu_qrcode.py @@ -37,7 +37,7 @@ class Image(qrcode.image.base.BaseImage): QtCore.Qt.black) -class QRCodeDialog(QtGui.QDialog): +class QRCodeDialog(QtGui.QDialog): """The dialog""" def __init__(self, parent): super(QRCodeDialog, self).__init__(parent) diff --git a/src/proofofwork.py b/src/proofofwork.py index bb16951c..5a36edf3 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -19,6 +19,8 @@ import state import tr from bmconfigparser import BMConfigParser from debug import logger +from kivy.utils import platform + bitmsglib = 'bitmsghash.so' bmpow = None @@ -228,6 +230,7 @@ def buildCPoW(): call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash"), '-f', 'Makefile.bsd']) else: # GNU make + print("I am in buildCPoW hurray.......................................", os.path.join(paths.codePath(), "bitmsghash")) call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")]) if os.path.exists(os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so")): init() @@ -292,8 +295,7 @@ def init(): global bitmsglib, bmpow openclpow.initCL() - - if sys.platform == "win32": + if "win32" == sys.platform: if ctypes.sizeof(ctypes.c_voidp) == 4: bitmsglib = 'bitmsghash32.dll' else: @@ -319,6 +321,14 @@ def init(): except: logger.error("C PoW test fail.", exc_info=True) bso = None + elif platform == "android": + print(sys.platform) + try: + bso = ctypes.CDLL('libbitmsghash.so') + except Exception as e: + bso = None + print(e) + else: try: bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index ab2990e6..44eddfca 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -10,7 +10,7 @@ import sys import ctypes OpenSSL = None - +from kivy.utils import platform class CipherName: def __init__(self, name, pointer, blocksize): @@ -72,7 +72,9 @@ class _OpenSSL: """ Build the wrapper """ + print("I am on openssl ctypes loading...............................................") self._lib = ctypes.CDLL(library) + print(library, "library12library12library12library12library12library12library12") self._version, self._hexversion, self._cflags = get_version(self._lib) self._libreSSL = self._version.startswith("LibreSSL") @@ -670,6 +672,10 @@ def loadOpenSSL(): libdir.extend(['libcrypto.dylib', '/usr/local/opt/openssl/lib/libcrypto.dylib']) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append('libeay32.dll') + elif platform == "android": + libdir.append('libcrypto1.0.2p.so') + libdir.append('libssl1.0.2p.so') + else: libdir.append('libcrypto.so') libdir.append('libssl.so') @@ -681,6 +687,7 @@ def loadOpenSSL(): libdir.append(find_library('libeay32')) for library in libdir: try: + print(library, "librarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrarylibrary") OpenSSL = _OpenSSL(library) return except: diff --git a/src/semaphores.py b/src/semaphores.py new file mode 100644 index 00000000..04120fe7 --- /dev/null +++ b/src/semaphores.py @@ -0,0 +1,3 @@ +from threading import Semaphore + +kivyuisignaler = Semaphore(0) \ No newline at end of file diff --git a/src/shared.py b/src/shared.py index 6d03bcca..b197b631 100644 --- a/src/shared.py +++ b/src/shared.py @@ -9,7 +9,7 @@ import hashlib import subprocess from binascii import hexlify from pyelliptic import arithmetic - +from kivy.utils import platform # Project imports. import state import highlevelcrypto @@ -116,21 +116,30 @@ def decodeWalletImportFormat(WIFstring): def reloadMyAddressHashes(): logger.debug('reloading keys from keys.dat file') + print("SHARED 146 begins.....................................................................") + myECCryptorObjects.clear() myAddressesByHash.clear() myAddressesByTag.clear() # myPrivateKeys.clear() + print("SHARED 152 begins.....................................................................") keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') hasEnabledKeys = False + print("SHARED 156 begins.....................................................................") + print(BMConfigParser().addresses()) for addressInKeysFile in BMConfigParser().addresses(): + print("SHARED 158 begins.....................................................................") isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') + print("SHARED 160 begins.....................................................................") if isEnabled: + print("SHARED 161 begins.....................................................................") hasEnabledKeys = True # status _, addressVersionNumber, streamNumber, hash = \ decodeAddress(addressInKeysFile) if addressVersionNumber in (2, 3, 4): + print("SHARED 166 begins.....................................................................") # Returns a simple 32 bytes of information encoded # in 64 Hex characters, or null if there was an error. privEncryptionKey = hexlify(decodeWalletImportFormat( @@ -149,13 +158,17 @@ def reloadMyAddressHashes(): myAddressesByTag[tag] = addressInKeysFile else: + print("SHARED 185 begins.....................................................................") logger.error( 'Error in reloadMyAddressHashes: Can\'t handle' ' address versions other than 2, 3, or 4.\n' ) + print("SHARED 187 begins.....................................................................") - if not keyfileSecure: - fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + if not platform == "android": + if not keyfileSecure: + fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + print("SHARED 196 begins.....................................................................") def reloadBroadcastSendersForWhichImWatching(): diff --git a/src/singleinstance.py b/src/singleinstance.py index c2def912..a495bea0 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -11,6 +11,7 @@ except ImportError: pass + class singleinstance: """ Implements a single instance application by creating a lock file @@ -28,7 +29,7 @@ class singleinstance: self.lockfile = os.path.normpath( os.path.join(state.appdata, 'singleton%s.lock' % flavor_id)) - if state.enableGUI and not self.daemon and not state.curses: + if state.enableGUI and not state.kivy and not self.daemon and not state.curses: # Tells the already running (if any) application to get focus. import bitmessageqt bitmessageqt.init() diff --git a/src/state.py b/src/state.py index 2cbc3a7c..b86c3bf6 100644 --- a/src/state.py +++ b/src/state.py @@ -69,3 +69,7 @@ testmode = False kivy = False association = '' + +kivyapp = None + +navinstance = None \ No newline at end of file diff --git a/src/tr.py b/src/tr.py index 8b41167f..6f26e75d 100644 --- a/src/tr.py +++ b/src/tr.py @@ -25,9 +25,13 @@ def translateText(context, text, n = None): try: from PyQt4 import QtCore, QtGui except Exception as err: - print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' - print 'Error message:', err - os._exit(0) + try: + if state.kivy: + pass + except Exception as err: + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' + print 'Error message:', err + os._exit(0) if n is None: return QtGui.QApplication.translate(context, text) else: From 9df2021c9fd369843ba132de1114b2db2cb2ee3b Mon Sep 17 00:00:00 2001 From: surbhi Date: Mon, 13 May 2019 17:01:33 +0530 Subject: [PATCH 098/306] Fix code quality checks and refactor with Inbox loading --- src/bitmessagekivy/kivy_helper_search.py | 2 +- src/bitmessagekivy/main.kv | 28 ++- src/bitmessagekivy/mpybit.py | 306 ++++++++--------------- 3 files changed, 116 insertions(+), 220 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 6758f554..cbf00fb4 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -12,7 +12,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' else: - sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read + sqlStatementBase = '''SELECT folder, msgid, toaddress, message, fromaddress, subject, received, read FROM inbox ''' sqlStatementParts = [] sqlArguments = [] diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index dc74450d..8f167298 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -266,12 +266,14 @@ NavigationLayout: spacing: 15 BoxLayout: orientation: 'vertical' - TextInput: + MDTextField: id: ti hint_text: 'type or select sender address' size_hint_y: None height: 100 multiline: False + required: True + helper_text_mode: "on_error" BoxLayout: size_hint_y: None @@ -288,7 +290,7 @@ NavigationLayout: txt_input: txt_input rv: rv size : (890, 60) - size_hint: 1,2 + size_hint: 1,1 MyTextInput: id: txt_input size_hint_y: None @@ -296,29 +298,32 @@ NavigationLayout: hint_text: 'type or search recipients address starting with BM-' RV: id: rv - TextInput: + MDTextField: id: subject hint_text: 'subject' - size_hint_y: None + required: True height: 100 + size_hint_y: None multiline: False - TextInput: + helper_text_mode: "on_error" + + MDTextField: id: body + multiline: True hint_text: 'body' size_hint_y: None - height: 100 - multiline:True - size_hint: 1,2 + required: True + helper_text_mode: "on_error" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 + size_hint: .8, .3 text: 'send' on_press: root.send() BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 + size_hint: .8, .3 text: 'reset' on_press: app.root.ids.scr_mngr.current = 'random' @@ -441,7 +446,8 @@ NavigationLayout: multiline: True hint_text: "Label" helper_text: "Label (not shown to anyone except you)" - helper_text_mode: "persistent" + required: True + helper_text_mode: "on_error" MDRaisedButton: text: 'next' size_hint_y: 0.13 diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a6a29ead..05bc3186 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -49,42 +49,55 @@ from kivy.core.window import Window userAddress = '' + class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() - # print("priiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnnnttttttttttthethingsss.................", ) class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) - # if state.association == '': - # state.association = 'BM-2cTuPpAPbu44sbkfVJN2F99sXGJoeNpDBh' - # print(self.get_address_via_split(state.association)) + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts.""" - print("generateaddressgenerateaddressgenerateaddressgenerateaddressgenerateaddress", BMConfigParser().addresses()) - if BMConfigParser().addresses(): - data = [{'text': "surbhi cis222222", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "peter surda", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "uber", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "ola", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "glitch", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "github", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "kivy", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "andrew", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] + """Clock Schdule for method sent accounts.""" + self.inboxaccounts() + print(dt) + + def inboxaccounts(self): + """Load inbox accounts.""" + account = state.association + self.loadMessagelist(account, 'All', '') + + def loadMessagelist(self, account, where="", what=""): + """Load Sent list for Sent messages.""" + xAddress = 'toaddress' + data = [] + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "inbox", where, what, False) + if queryreturn: + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + data.append({'text': mail[2].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[2]) > 10 else mail[2] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text }) for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/kivymd_logo.png')) + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) else: - self.manager.current = 'login' + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) class MyAddress(Screen): @@ -95,25 +108,23 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - pass - # if BMConfigParser().AddressSuccessful(): - # data = [{'text': "me", 'secondary_text': "BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyTfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyVfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWySfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyHfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyJfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyKfBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyMnBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyOkBdY2FbgyuCb7abFZ49JYxSzUhNFe"}, - # {'text': "me", 'secondary_text': "BM-2cWyWuBdY2FbgyuCb7abFZ49JYxSzUhNFe"}] - # for item in data: - # meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - # meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - # self.ids.ml.add_widget(meny) - # else: - # self.manager.current = 'login' - + if BMConfigParser().addresses(): + data = [] + for address in BMConfigParser().addresses(): + data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) + for item in data: + meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + self.ids.ml.add_widget(meny) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no address is created by user!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) class AddressBook(Screen): @@ -124,7 +135,6 @@ class AddressBook(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - # sqlExecute("DELETE FROM addressbook WHERE label='' ") data = sqlQuery("SELECT label, address from addressbook") if data: for item in data: @@ -140,16 +150,16 @@ class AddressBook(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) - print("chek iniiiiiiiiiiiiiittttttttttttttttttttttttttttttttt", self) - # self.ids.ml.clear_widgets() def refreshs(self, *args): state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) + class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): ''' Adds selection and focus behaviour to the view. ''' + pass class SelectableLabel(RecycleDataViewBehavior, Label): @@ -191,51 +201,32 @@ class DropDownWidget(BoxLayout): def send(self): """Send message from one address to another.""" fromAddress = str(self.ids.ti.text) - # For now we are using static address i.e we are not using recipent field value. - # toAddress = str(self.ids.txt_input.text) - # print("hiiiiiiiiiiiiiiiiii i am hereeeeeeeeeeeeeeeeeeeeee..............") - # print("hiiiiiiiiiseeeee to addresssssssssss..........................", self.ids) - # print("ssssssssssseeeeeeeeeeeeeeeeeeetheeeeeeeeeeetexttinput....data...", self.ids.txt_input.text) - # toAddress = "BM-2cVJ8Bb9CM5XTEjZK1CZ9pFhm7jNA1rsa6" - # print("every thng is good for the day..................", str(self.ids.txt_input.text)) toAddress = str(self.ids.txt_input.text) - print("alllllllllllllllllllllllllllsss wel ends wellllllllllllllll", ) subject = str(self.ids.subject.text) message = str(self.ids.body.text) - print("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR") encoding = 3 print("message: ", self.ids.body.text) sendMessageToPeople = True - print("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS") if sendMessageToPeople: - print("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT") - print("did_addresssssssssssssssss_existsssssssssssssssssssss.........buyyyyy", toAddress) - if toAddress != '': - print("UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU") + if toAddress != '' and subject and message: from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) - print("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV") if status == 'success': from addresses import * toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' - print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") if addressVersionNumber > 4 or addressVersionNumber <= 1: print("addressVersionNumber > 4 or addressVersionNumber <= 1") if streamNumber > 1 or streamNumber == 0: print("streamNumber > 1 or streamNumber == 0") if statusIconColor == 'red': print("shared.statusIconColor == 'red'") - print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') - print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - print("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY") t = () - print("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', @@ -253,26 +244,38 @@ class DropDownWidget(BoxLayout): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) - print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) - print("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") - print("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD") print("sqlExecute successfully #######################") self.ids.body.text = '' self.ids.ti.text = '' self.ids.subject.text = '' self.ids.txt_input.text = '' - # self.manager.current - # self.ids.scr_mngr.current = 'add_sucess' self.parent.parent.current = 'sent' - # print("whattttttttttttttttisdebuggerbtnssssssssss........................", self.ids) self.ids.btn.text = 'select' self.ids.ti.text = '' - print("sssssssssssuvvvvvvvvvvvvvvvvvtttttttttttttttttt...............") return None + else: + msg = 'Enter a valid recipients address' + self.address_error_message(msg) + elif not toAddress: + msg = 'Enter a recipients address' + self.address_error_message(msg) + + def address_error_message(self, msg): + self.box = FloatLayout() + self.lab = (Label(text=msg, font_size=25, + size_hint=(None, None), pos_hint={'x': .25, 'y': .6})) + self.box.add_widget(self.lab) + self.but = (Button(text="dismiss", size_hint=(None, None), + width=200, height=50, pos_hint={'x': .3, 'y': 0})) + self.box.add_widget(self.but) + self.main_pop = Popup(title="Error", content=self.box, + size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) + self.but.bind(on_press=self.main_pop.dismiss) + self.main_pop.open() class MyTextInput(TextInput): @@ -297,8 +300,8 @@ class MyTextInput(TextInput): self.parent.parent.parent.parent.ids.rv.data = display_data # ensure the size is okay if len(matches) <= 10: - self.parent.height = (250 + (len(matches)*20)) - else: + self.parent.height = (250 + (len(matches) * 20)) + else: self.parent.height = 400 def keyboard_on_key_down(self, window, keycode, text, modifiers): @@ -311,6 +314,7 @@ class MyTextInput(TextInput): class Payment(Screen): pass + class Login(Screen): pass @@ -330,7 +334,7 @@ class NetworkStat(Screen): """Clock Schdule for method inbox accounts.""" import network.stats import shared - from network import objectracker + from network import objectracker self.text_variable_1 = '{0} :: {1}'.format('Total Connections', str(len(network.stats.connectedHostsList()))) self.text_variable_2 = 'Processed {0} per-to-per messages'.format(str(shared.numberOfMessagesProcessed)) self.text_variable_3 = 'Processed {0} brodcast messages'.format(str(shared.numberOfBroadcastsProcessed)) @@ -355,39 +359,16 @@ class Random(Screen): eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - queues.addressGeneratorQueue.put(( - 'createRandomAddress', - 4, streamNumberForAddress, - label, 1, "", eighteenByteRipe, - nonceTrialsPerByte, - payloadLengthExtraBytes) - ) - self.manager.current = 'add_sucess' - print("whhhheeeeeeee55566666666666666666666..................", self) - print("what is the screeen forrrrrrrrrrrrrrrrr...............", self.ids) - self.ids.label.text = '' - # print("whatttttt99999999999999999999999999999999999988888888......", self.parent.parent) - # print("go.....more...parenxccccccccccccccccccccccc555559955555555555", self.parent.parent.parent) - # print("ssssshooooocxvxcvxcvoooouuuuuuuuuuuuuuuuuueeeettttttttteeeeeeeeeee............... ", ContentNavigationDrawer().ids.btn) - # print("spiiiiinnnxcvxcxc99999999999999999999999999999999999999tttt..........", ContentNavigationDrawer().ids.btn.text) - # print("text_dirrrrrrrrrrrrrrrrrrrrrr9999999999999999fgdg.............................", dir(ContentNavigationDrawer().ids.btn)) - # print("ttttttttttttttiiiiiiiiilllllllllllllllttttleeeeeeeee9999999999999999999", ContentNavigationDrawer().ids.btn.text) - # prnit("55555557777777777777777888888888888888888jjjjjjjjjj", ContentNavigationDrawer().ids.btn.text) - # print("what account is associated..............................", state.association) - # print("pppppppppp999999999666666666663333333333333333333333..............", BMConfigParser().addresses()) - # print("whatssssssssssssssssssssssstheva,lllllllllllleeeeeeeee...........") - # print("wh.....................8888888899999999999999999999999999", queues.addressGeneratorQueue.get()) - - # print("ljjkkkkkkkkkkkkkkkkkkk666666666666666666666666666666666", self.parent.parent.parent.parent.parent) - # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] - # if BMConfigParser().addresses(): - # print("iiiinnnnnnnnnnnnnnnnnnnnnnnnnnsssssssssssiiiiiiiiiideeeeeeeee") - # ContentNavigationDrawer().ids.btn.text = BMConfigParser().addresses()[0] - # return BMConfigParser().addresses()[0] - # print("iiiiiiiiiiiiiihhhhhhhhhhhhhhhhh5555555555555555555....", ContentNavigationDrawer()) - # print("khhhhhhhhhhhhhyaaaaaaaaaaaaaaaa5555555555555555...............", ContentNavigationDrawer().ids) - # print("it is sccccccccccccefssssfulllllll............................", ContentNavigationDrawer().ids.btn.text) - # ids.btn.text + if self.ids.label.text: + queues.addressGeneratorQueue.put(( + 'createRandomAddress', + 4, streamNumberForAddress, + label, 1, "", eighteenByteRipe, + nonceTrialsPerByte, + payloadLengthExtraBytes) + ) + self.manager.current = 'add_sucess' + self.ids.label.text = '' class AddressSuccessful(Screen): @@ -397,90 +378,53 @@ class AddressSuccessful(Screen): class NavigationLayout(): pass + class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" data = ListProperty() def __init__(self, *args, **kwargs): super(Sent, self).__init__(*args, **kwargs) - # print("I amuuuuuupfatgd vale should get..................... .", ContentNavigationDrawer().ids.btn.text) - # print("yyyyyyuuuuuuuuuuuuuuuuuoooooooooouuuyyyyyyyyyyyy...............", ContentNavigationDrawer().ids.btn.values) - # print("ccchekkkkkkkkkccccccccccclre..................................................", ContentNavigationDrawer().ids.btn) - # print("llllllllllleeeeetttttttttttttttttttttheeeeeeeeemmmmmmcheccccccccccckkk........", dir(ContentNavigationDrawer().ids.btn)) - # print("llllllllllllllllllllllllllleeeeeeeeeeeeeeeeeeeeeeeexfgcgcgvcgvcvgbeeechhhhhhhhhhheck", state.association) if state.association == '': - # state.association = Navigatocoming inside thew methoddddddddddddddddddds1buildrss().ids.btn.text - print("uuuuuuuuuuuuuuuuuuuuuuuuu999999999999999999999999999999") - print("lllllllllllllllllllllllllllllll55555555556666666666", BMConfigParser().addresses()) if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - print("kkkkkkkkkkkkkkkkkkkkkkkkkkkk6666666666888888888888888888...................", state.association) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): """Clock Schdule for method sent accounts.""" - print("oooooooooooooooooooooooooooo999999999999999999999000000000") self.sentaccounts() print(dt) def sentaccounts(self): """Load sent accounts.""" - print("mmmmmmmmmmmmmmmmmmmmmmmm44444444444444444455555555555__........") account = state.association - print("zzzzzzzzzzzzzzzzzzzzzzz99999999999999999999999999999999999", account) self.loadSent(account, 'All', '') def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" - # print("uuuuuuuuuuuuuuuuyyyyyyyyyrrrrrrrrrrrinside_loadSent..........") xAddress = 'fromaddress' data = [] - # print("check--------thre.................somethiong.......cvmnvb mvn xmnvcxv.") queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - print("qqqqqqqq77777777777777777777777777777777555hhhhhhhhhhhhhhhfffffff....", queryreturn) if queryreturn: - # for mail in sqlQuery("SELECT toaddress, subject, message FROM addressbook a, sent s WHERE a.address = s.fromaddress and s.fromaddress = 'BM-2cUz6dniZHjFTqv6j2es2wBSe3NydZdk4R';"): for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - print("whatttttttttttttttttttttttttttisssssssssssssssssssssssserrrrrrrrrrrrror") - print("nowwwwwwwwww9999999999999999999999999999999..................", third_text) - # print("sssssssssssssssseeeeeeeeeeeeeeeeeeeeeeeeeeeepprob.....", mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2]) - # data.append({'text': mail[0].strip(), 'secondary_text': mail[2][:20] + '.....' if len(mail[2]) > 20 else mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) - # data.append({'text': '', 'secondary_text': mail[2] + '\n' + " " + (third_text[:35] + '...!') if len(third_text) > 35 else third_text }) data.append({'text': mail[0].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 }) - print("kyaaaaaaaaaaaaaaaaaaaaaaaaaayhaaaaaaaaaaaaerorrrrrrrrrr") - # self.data = [{ - # 'data_index': i, - # 'index': 1, - # 'height': 48, - # 'text': row[2], - # } - # for i, row in enumerate(queryreturn) - # ] - print("show 6666666666666666666eeeeeee555555555555555daaaaaaaaaaa.......", data) for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) - print("uyyyyyyyyyyyyyyyyyyyyyyyyyuuuuuuuuuggg558888888888gggggggoooooooooooooooooooooooooooooooooooooooo....") - # print("ufffffffffffffffffffffffff6666666666666ffffyyyyyyyyyyyyyyyyyyyyyyyyypp.......", self.data) else: - # self.data = [{ - # 'data_index': 1, - # 'index': 1, - # 'height': 48, - # 'text': "yet no message for this account!!!!!!!!!!!!!"} - # ] content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) + class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" def __init__(self, *args, **kwargs): @@ -512,20 +456,13 @@ class Page(Screen): class Create(Screen): def __init__(self, **kwargs): super(Create, self).__init__(**kwargs) - # from kivy.core.window import Window - print("cheeeeeeeeeeeehn888888888888888888888888gggkkkkkkkthe windowwwwwwwwwwwwwwww", Window.size) - # print("take the onlyyyyyyyyyyyyyyyyyyyyyyyyyyyy x axssssssssssssssssssssssswindow", Window.size[0]) - # print("realllllllllllyyyyyyyyyyyyy yyyyyyyyyyyoooooouuuuuuu wwwwwwaaaaaaaaaaaannnnnnnnnntttt", Window._get_width) - # print("mmmmmmmmmmmmmminnnnnnnnnnnnnnnn and mmmmmmmmaaaaaaaaxxxxxxxesssssssss", Window.minimum_height, Window.minimum_width) - # print("dir in windowwwwwwwwwkkkkkkkkkkkww of the mobile screen", dir(Window)) - # print("cheeeeeeeeeeeeeeeeeckkkkkkkkkkkkkkkk width and heightttttttttttttttttttt", Window.width, window.height) widget_1 = DropDownWidget() from helper_sql import * widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] - # widget_1.ids.txt_input.word_list = ['how to use python', 'how to use kivy', 'how to use django', 'BM-2cTik2JBHAS92U633LPY', 'BM-2cUYmQofWjTQeUitL7'] widget_1.ids.txt_input.starting_no = 2 self.add_widget(widget_1) + class AddressSuccessful(Screen): pass @@ -540,10 +477,9 @@ class NavigateApp(App): obj_1 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - # user_address = StringProperty('jai') + sentmail = NumericProperty(0) scr_size = Window.size[0] - - title = "KivyMD" + title = "PyBitmessage" count = 0 menu_items = [ {'viewclass': 'MDMenuItem', @@ -563,9 +499,6 @@ class NavigateApp(App): ] def build(self): - print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllllllrrrrrrrrrrahut......') - print('chreckoooooooooooooooo........................', self.variable_1) - print("dsssssssssssoddddddddd77777777777777777777eeeeeeeeetheroot", dir(self)) import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) @@ -595,17 +528,7 @@ class NavigateApp(App): "That's pretty awesome right!", size_hint_y=None, valign='top') - print("9063 I am pressed...............................................................") content.bind(texture_size=content.setter('size')) - print("9064 I am pressed...............................................................") - # self.dialog = MDDialog(content=content, - # size_hint=(.8, None), - # height=dp(200), - # auto_dismiss=False) - print("9065 I am pressed...............................................................") - # self.dialog.add_action_button("Dismiss", - # action=lambda *x: self.dialog.dismiss()) - print("966 I am pressed...............................................................") self.dialog.open() @staticmethod @@ -622,31 +545,16 @@ class NavigateApp(App): return [address[:16] + '..' for address in BMConfigParser().addresses()] else: return "valuesdemo" - # return [BMConfigParser().get(address, 'label')[:12] + '..' for address in BMConfigParser().sections()[1:]] - # return BMConfigParser().addresses() def getCurrentAccountData(self, text): """Get Current Address Account Data.""" - print("self tttttttttttttttttttttteeeeeeeeeexfgvbcvgfcgfdgfdgfgxxxxxxxxtttttttttzzzzzzzz ", text) state.association = text - # print("eeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrorrrrrrrrrrrrrrrrrr", self.root) - # print("iiiiiiiiiiiiiidddddddddddddddddeeeeeeeessssssssssssssssss55......", self.root.ids) self.root.ids.sc1.clear_widgets() self.root.ids.sc4.clear_widgets() self.root.ids.sc5.clear_widgets() - # print("resffffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuurrrrrrrrrrrrr......") self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) - # print("again aaaaddddddddddddddddddinggggggggggggggggguuuuuuuuuuuuuuuu1 ........") - - # self.root.ids.toolbar.title = BMConfigParser().get( - # state.association, 'label') + '({})'.format(state.association) - # print("what theyyyyyyyyyyyyyyyyyyyy areeeeeeeeeeeee printing11........", self.root.ids.toolbar.title) - # Inbox() - # Sent() - # Trash() - # print("finish gamneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!") def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" @@ -669,9 +577,6 @@ class NavigateApp(App): p.open() def getDefaultAccData(self): - print("coming inside thew methodddddddddddddddddddsdcassdfs1") - print("combbbbbbbbbbbbggggffffffdfgdgfffffffgggggggggggggggggggllllllloooo", BMConfigParser().addresses()) - # return BMConfigParser.addresses[0] if BMConfigParser().addresses(): return BMConfigParser().addresses()[0] return 'Select Address' @@ -684,19 +589,13 @@ class GrashofPopup(Popup): self.size_hint_x = 0.9 def savecontact(self): - print("show the addedes addess in databaseeeeeeeeeeeeeeeeee............................") - print("1110 I am pressed...............................................................") label = self.ids.label.text - print("2210 I am pressed...............................................................") address = self.ids.address.text - print("3310 I am pressed...............................................................") if label and address: state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - # self.parent.children[1].ids.sc11.clear_widgets() - # self.parent.children[1].ids.sc11.add_widget(AddressBook()) def show_error_message(self): content = MDLabel(font_style='Body1', @@ -743,18 +642,9 @@ class NavigationDrawerTwoLineListItem( Binds Controller.current_account property. """ pass - # self.controller = App.get_running_app().controller - # self.controller.bind( - # current_account=lambda _, value: self.on_current_account(value)) def on_current_account(self, account): pass - # e.g. deleting the last account, would set - # Controller.current_account to None - # if account is None: - # return - # address = "0x" + account.address.encode("hex") - # self.address_property = address def _update_specific_text_color(self, instance, value): pass From 2c666dddc729fe477426cc5d1b02725376bfbf2e Mon Sep 17 00:00:00 2001 From: surbhi Date: Tue, 28 May 2019 16:42:51 +0530 Subject: [PATCH 099/306] Added Enhancement for Sent Screen and also manage KivyMD with virtual env --- src/bitmessagekivy/main.kv | 45 ++++++++++++++++++-- src/bitmessagekivy/mpybit.py | 77 +++++++++++++++++++++++++++++------ src/images/avatar.png | Bin 0 -> 27865 bytes src/images/drawer_logo1.png | Bin 0 -> 2041 bytes src/state.py | 10 ++++- 5 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 src/images/avatar.png create mode 100644 src/images/drawer_logo1.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 8f167298..62d3cbe3 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -51,6 +51,7 @@ text: app.getDefaultAccData() values: app.variable_1 on_text:app.getCurrentAccountData(self.text) + on_press: app.limit_spinner() NavigationDrawerIconButton: icon: 'email-open' text: "Inbox" @@ -60,7 +61,7 @@ icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' - badge_text: "2" + badge_text: "0" NavigationDrawerIconButton: icon: 'message-draw' text: "Draft" @@ -127,7 +128,9 @@ NavigationLayout: BoxLayout: orientation: 'vertical' Toolbar: - id: toolbar.. + id: toolbar + opacity: 1 if app.addressexist() else 0 + disabled: False if app.addressexist() else True md_bg_color: app.theme_cls.primary_color background_palette: 'Primary' background_hue: '500' @@ -172,6 +175,8 @@ NavigationLayout: id:sc12 NetworkStat: id:sc13 + SentDetail: + id:sc14 : name: 'inbox' @@ -388,6 +393,7 @@ NavigationLayout: id: grp_chkbox_1 group: 'test' active: True + allow_no_selection: False MDLabel: font_style: 'Caption' theme_text_color: 'Primary' @@ -400,6 +406,7 @@ NavigationLayout: MDCheckbox: id: grp_chkbox_1 group: 'test' + allow_no_selection: False MDLabel: font_style: 'Caption' theme_text_color: 'Primary' @@ -445,7 +452,6 @@ NavigationLayout: id: label multiline: True hint_text: "Label" - helper_text: "Label (not shown to anyone except you)" required: True helper_text_mode: "on_error" MDRaisedButton: @@ -640,4 +646,35 @@ NavigationLayout: AnchorLayout: MDRaisedButton: size_hint: .8, .6 - text: root.text_variable_5 \ No newline at end of file + text: root.text_variable_5 + +: + name: 'sentdetail' + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: dp(400) + padding: dp(32) + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: root.subject + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "To: " + root.to_addr + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "From: " + root.from_addr + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.message + halign: 'left' + bold: True \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 05bc3186..7273aeee 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -45,9 +45,7 @@ from semaphores import kivyuisignaler from kivy.uix.button import Button import kivy_helper_search from kivy.core.window import Window - - -userAddress = '' +from functools import partial class Navigatorss(MDNavigationDrawer): @@ -108,9 +106,9 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses(): + if BMConfigParser().addresses() or state.kivyapp.variable_1: data = [] - for address in BMConfigParser().addresses(): + for address in state.kivyapp.variable_1: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) @@ -125,6 +123,10 @@ class MyAddress(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) + try: + self.manager.current = 'login' + except Exception as e: + pass class AddressBook(Screen): @@ -259,10 +261,11 @@ class DropDownWidget(BoxLayout): return None else: msg = 'Enter a valid recipients address' - self.address_error_message(msg) elif not toAddress: - msg = 'Enter a recipients address' - self.address_error_message(msg) + msg = 'Please fill the form' + else: + msg = 'Please fill the form' + self.address_error_message(msg) def address_error_message(self, msg): self.box = FloatLayout() @@ -369,6 +372,10 @@ class Random(Screen): ) self.manager.current = 'add_sucess' self.ids.label.text = '' + self.parent.parent.parent.parent.ids.toolbar.opacity = 1 + self.parent.parent.parent.parent.ids.toolbar.disabled = False + self.parent.parent.parent.parent.ids.sc10.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) class AddressSuccessful(Screen): @@ -409,10 +416,11 @@ class Sent(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[0].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 }) + data.append({'text': mail[0].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, 'lastactiontime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -424,6 +432,16 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) + def sent_detail(self, lastsenttime, *args): + state.sentMailTime = lastsenttime + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(SentDetail()) + src_mng_obj.current = 'sentdetail' + class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" @@ -475,9 +493,10 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() + # obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - sentmail = NumericProperty(0) + total_sentmail = str(state.totalSentMail) scr_size = Window.size[0] title = "PyBitmessage" count = 0 @@ -504,6 +523,7 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() + # self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() @@ -535,7 +555,6 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": - # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -581,6 +600,19 @@ class NavigateApp(App): return BMConfigParser().addresses()[0] return 'Select Address' + def addressexist(self): + if BMConfigParser().addresses(): + return True + return False + + def prnttttttttttttt(self): + pass + + def limit_spinner(self): + max = 2.8 + spinner_obj =ContentNavigationDrawer().ids.btn + spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -650,4 +682,25 @@ class NavigationDrawerTwoLineListItem( pass def _set_active(self, active, list): - pass \ No newline at end of file + pass + + +class SentDetail(Screen): + """SentDetail Screen uses to show the detail of mails.""" + to_addr = StringProperty() + from_addr = StringProperty() + subject = StringProperty() + message = StringProperty() + + def __init__(self, *args, **kwargs): + super(SentDetail, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method SentDetail mails.""" + data = sqlQuery("select toaddress, fromaddress, subject, message from sent where lastactiontime = {};".format(state.sentMailTime)) + if data: + self.to_addr = data[0][0] + self.from_addr = data[0][1] + self.subject = data[0][2].upper() + self.message = data[0][3] \ No newline at end of file diff --git a/src/images/avatar.png b/src/images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..b006bfa2a69bcfce8d50e0ef220452aaf490ee8f GIT binary patch literal 27865 zcmV*2KzF~1P)et*1sv+7Z#RYMVeF*MXJh*6?+2e4-bI(29$)boNiYTIpA_PPQNEA^- z5k(XsAu2$kh$4z8q6i6YyC)Du6c(T@j)QESg+G?!c)-?KL=lBaaM(S8D5B7TG|h-` z%)$SejE_g+ z(hNvb7|#dC7#ve@q=o;X5q*F$562Gzy6!BP0CWy-nhd!V>ln3TkdQRjQb|% zUZCs7CVhd|Tp}a6p3MUOqVT_~?9xkFLXGs)0%U zy%z)14mr*Np8fivKY-(CVPl6?7@vS|60p`E(pB1zO)8nM2hjY(H+chC^SIdx;FSH| zBH+UNJ(GbM%|0mwmagQl@-*S2_f0`ey`M~eLZR5{be}rvT43^k_%ncye|BgYa9rD>i-9Hzhyd{Y4pe8Frgf>? z384weq5%;!nh*&XGMzQM2sq`o!_NSpx#_!mfTfr4H&?IcqZc(5UsF6PYMfE${)vvL z06DQi&TG;rPP(iqFfKRs4&bRPDu)3t7+d~0aNy{&dB96nYJCq@!}lss`JWjoAdOGAKx(#Jvanpz}mcE^5|H3Dsp%CJEiOTrVt>=lW>0YA-4yaf2m@)c(S7k;+= zMPO9|f0uCLllO>^;o@@D&hr(aaq4fw&*oLpdM8;wx<;8S7uENX!S8tv?55gZ6%LX*W8 zM8OSjsTAj{Wjo;ZXA=^Eqv!6q8n|Z7va5mRkMeg54TYTa5}oNNj)$lKsT=UqFa|yc zjGxe@1bEKSBM$;!yQ7=|yIfU%Incfd2L&zAw1bw#2~G2w4pbgbRcSkfQ+$$2c?1Xf zT;{3_IIn~}AY*ZF0Jm*xG#7aP!gb}qg$uX753D$yzuLPPj~>-fBu7+$$PL_yIeYUl z=IhZ{0Q=usychUNheNLe`)k_rS`pzi@P2n5ZLAsAF>8Z;kC<|WP-nb0H=9N{KP z#(o22tf>pQY+3x{z=xL4d>{Bn8GlvP)qM1Bz_;m$CyOGIhzbz7K$^zwd~|5Ue2i^7 zx)^xNzw)*L-)(vLKA?RQ3>VVc>}6e`>3qo+wk%0FbyF3LHEsgDWAG>cQQ3$;TZuZ5 z=Sh6IL|c{mji>;L3@B;}&$s)l8zum|Z7lBxeDUU^*}&l|s%HZ2n`pR@R^zb9^b#^G zO8hemzBWK+|9R5D{V-6`OfCfe@OSqB;3IE-yBWAGmA|U`8a|4+K8en3{X$fLSc?ok zP<7ha|K8FMIB-gCQ{eCS6sfRnex^aXojpR@c}W(AOOP&{ItZu)OUh8-Ilp~55x5d- zc~xG;NAKPE@-#ceJ9dI*miS zvnOZ0-8*TT*M&ePpWqk>WYPpT7)AVdK*kyk1Wsw-YXY1;``eYk9jp1PJV*E_IzdXL zTh&cO1&BFF=Yw-zmttVTnn8B}NA=A<12}nV=~uv(XWBYTGe8R=EjV^B%m`_tyd*W9 zv34q@)zHF4;!a>rhvpvvCti?o4)C)U2O9#*ckowH%`Ta|PIU_|yC+b`A@Vf(4gn?( z>dt`AJhN{h@Y%6dTY$-J?44%#5DOvCRAg+YO8bFMXn{p4?FY?^Mk=~!GkiY-8T2Nc zt@bCBOcOE-RjI(_vH1&tS6p#Q6)^FtijBa9&*T>YJ*VKyKeTnSbr?>&Cs4;gCMtaB z?$G5$V8e>`alp@CI^+S4t@8py02?<+x8P7iDN1CMB=L^~tuR&D4bm8C129hI35UZD z;JCsbUf}0fx0nfR(1}0m!j6r?AR|+YGN}>OK=dJv4-V|u=Dy&jg}{M#H?IbMvj5<6 zVA?OMxX&OXrqxmWsJEYQfh=ouV4G1AjX!oj=N8`8+sQk~{Dy5lMq(S#(SqiZ0 z6WwEg!CrHOEEBK7Js!5D?hMY9QW8T zWW5JG^GExpXf8y8oopTdXkN1ANzlAx2_it$SKo$N$X*ESUv}gG@XO_wp9LI%B~)T# z`AGM@OuwvLh&s`a4Xo}%J-}nXxo!n;(9Z>ffxrJ=Isj@>itu!MUYVEHL5S)7Ju@ zD$0KcIO?X-)xZ`DZJniwkhY}9SRj+88ZJS)c}ZG5SXz)zs4dX{>BK$2oYzyzfuB?^ zdJUL9_wcR2vcCLP-ei1vdZeZ;E208~0|P!?ueF;FO!}ekK;X+Higl=Je|fPBa0M&Ii{Ie2jna!gj!Cagurj<1naV;+exer8xV6MIqLeIOXW?d*M05-`cr=Y8Pktq#8pyyQ-M zr)M6dtGR>_H?}0sdTGn3lh1_`|0Jp9B`ajBeU|z<@P}c`F9Y82_0c?FDF)wosklzP zi;t_X8b}%+9Ix;({^kMy0p7g2;4R>|*|yEhWcbDX+q|K`3+Y|X2T7&u~KnC)`fzGVB zE3Ua5IJjrU8sHnxR#gC#yW2NKbKs|O*liM`Dz7e;^6cyp()HgUP3R&ZlV%~54s@QV z2qXnv$l{|SO$cj@xyJ&}Ea{d6TzbvU1;CvDNgk>N@V3-!!|<><-Bm~A6o z0uK5m|1n@jT7AhJmu?|MNINe{OL|Bbwk#`T4W|y$2PaVlV@b_`=iK$<7r^EJ;?GuH zO-G5?ge^insf8t~@&IPU*zVIF3 z#mkQt0Smw7&w8lRMF>Z>7j;zwL0^Zn7atRroze|Bet%sT9HO6uY#ImMK(DHlXI>Od zC7Ix$=rgeah~l^qC1a?Vr!3bOZJ5HmzOsJ@_W$YhBH%de7nE=@A88${dsTnyngF3H zxzqTVka+Fyz-LF5bO1i_f40pmObA=OYzrY352ShNtRZAIgy4{*W|m*AB??=XWFeFe zbiPQy%2I1g+kngDGX14hh_z-)+RgVJC z{_W60;IC)dI;&7X&OwuQIHp0?c_CyqRmo;*lpV63uSf@7G>u;a1TKD`|Fx^1nK-$EPI-|2RHm*Fe(v;LPJ=!mg_}0iXW!&>g^WbtZa2I0vc3 zf-D{EBn^|4c3ucs8%jwB*?&h#f*YDO0Zy6wqsk|-b#_@tK6;zt%QEbk+wmZ)27-dY zk-^89=PtPhc;?>xDZo+Z*fukxpaeTAh9`^QAX~3wVUh$<(nAvX1vf+m$8jOf7xgQV z1b&*3Bskg>IO;#={s`=c#a?5cgMhtR=AxS=h*b!3c3`v~gVqUaBOHvC;)bgT!5>Xr%ex^oQYO-k)|70BEBxofwaYUo3bb_ucGU>?@6^F1Ynkrm~^Q9>=TCoAxX@cW-;OM#huL;F` zbhXEqN%Ku4tA*u==VR>73ugicEv?7}zVW8)<<`Z{i%eE_*QP>kTczy~_u)R3!E2wj1`cS@u_18&_`Pd@nY;Ou zo{9J>+pkPn1V|bmTpQc00yaLWn z1uCW4smc!Fe5M9hb_-g%z8V5;oQDQt16Qsx$miyuAMh?3UDiFYu@C`!j)uKg4He z;macKeX>h{r18OtZqvlwolXKi^h)I)z+qq7G%r7h{0-`JAxR@5F|QRW<(-!#tysmp z=Bt#?CnOs}G`(03Z7_%|fh}W7xE$(%$8#FKSoki%natr{Tygu(5;D0Wu{t{Sz8GqIr@vT~aT4IED_EbexGRTr?EIXuayd~@XXmd%Ho6*7GapLcLTo6@?SE-c_0q7g1g;=%Ya=UuUG=KUvP*WmuwfRtVIpUSudI3h?Y^; z2{HvywdJVbI4)#spjJ5$cyG^s`M@r>@V~m;TKxHb5DU%@mG*}tBK&stcF#*2Ci#g1-=S)vGOeW3gxS>{FO>o%3*KE&v()~A#Md(7Vb3-DWu3 zo#>99e2o3u1&P43Q%m~-=iOoL=lVlh(~G1|UfJd)YY>5~khOO`LAvWp)?VxeO|yyj z0na~g;r{^_VZWrxHFz}B%Yj;D!om!5Cl&!qc%eKOI4W|*5OHTCZ80@UNR$P%vnLaW zY?z@kiXaezgQ^G1vJgsIMqNao$<~WKMAK}=c;Kiv`J;pv_~^{Ur%hjRtTJI?5sjEv z`PlfB&K}@X-+A@{8(nSD=hjHvQAV%b(3*tStF#?rA42stSuV5JxXQ#_c$-8hHKY zibcQ<|F-7yn1ACYNiJ0Pjd5}DH!I`OxTW!6fs|xk!Z}V2f6R7XwpErfWg8Kfmb|_p zWDNJvrvVCEFO>zC%&96Hq|>mqK^L?TN^;%%X&iQg&KJ!qOjHg6p1f*M0q{CJVq7^N zX3tvg%Bv=SjsTr_*%~*|jxh1vMi)0Zjj@iG^?&KyG)1ZW zzR~a|sraHu_7~IK*uJ(vW?d8(B-k7il*b3>U_wx-2dg` z2BI2OlJqN)4x};C^)8D~h~`DVqbv=jXkG(=Oq%sU%!^D_CeO>!9ym3{y&0Ht5&x@; zN<^ib^*JUB5C`@ycmJo~KY-W#U*)Gjb3X+jb~tq6?Y>YEemlZ;terzy5aYg0{;A8Fp?fdsvR84pM&cv1xoEK>t5ngbdS+1{K*^D*+Uzf_B|4_!8JB{jgtNN6>1C%ub zS~dtD0-3605wKbls3cKd1lfvt`kgO}uKSA4K*stH0$yFs{~GgOJ~~W`D>F-gpmWA? zE+6A}c!mQnGd)pJ)LfEf=Y`NaulP@rKX0g9KyAkL8r<*i%1`=iLP8?%fZWzhjf6}= zVu7~Vgy5LWCc|ah?9q;^x;Ib+Nm}QIJ#&@64|Wc5y=LFM>I}%FC(CtjwFxvt__dOj z1Y%whK3~Tw1YxQQ9U~R8#7k2qq|Rro-EF;l z_g~0Z?5M=QC%?kDJ~GI_(X=*IyPcM8*+r@V8ROXOR7<^y?rG|*NF!-}M#s0h4^RZk z<}RP~nymUrrn$20nza28nyhU32$~FNSs-ek(av5H$kOYdOj&)m0|$-ae~tN?kB+df ztZ)TL8Xo3fe2j~YKNEQFV__b*W`UNaNk1*nqzRd~vsVR4a+@Y^G(SVpNLHM_W5{C= zy_9r*13dytYg3iwe8E0zwp!M0Bx|Ss<(L<%Gt2dws*$|g<h_F)9 zWMvT?G%s1AybylpOA<{;)`aD_pMmE#$4A(~&`BCdTByejSAbya6xUWhCZ6fd1)hDQ z;Uj6o*(9;``t2mF(u8^{R0K)Ft_J%XbyYNy@uz;+zgpQVJQDwQV#0CeC0Pw2aRXiF z8{y;8=ej&QT8*Ufmu(hz_=?qgK_WB`S;9&YLX#y;ND}yIXp%szTapP5f_D?}?2q`P z#Q)1y-m6gnF6d9w|2VtPg-^?DUKS_L`^rNZRl}NuqIV+e!3P$r8_N)Vt|( zibnE9-=>2fRHL|VZTPc#WAht`=4JQ!qTlaT&Ac4oAXol<;b`wLV2UG+r0w`#AD(%p zqM77%S<~x_`e)jbws$?g|k9%}NeB1pbJdSCX<{eTk{zzq;o|HM0Vl&IUU80y%{(bA)k&)p=*TR>PLW)JTvf=z<_= z;-AnsNE4Ffd>KT87lC)oQ)G-xHTkA|cCp3KP_bs{dAC&m#U;*L!?){9^QYp$d?}e2g8Np9Ji7jo(Yi zc1dyUvMkVATdyoP_I~~k&XxLa1pns;6eMx&l0J%vMxy;4^`5Ue%Ki-E-xVFgvBkXU z2#ust(MY_EHEQ4Hm6Oh5@(GexRZ63A2!TdBd%NdFwd+W5NEU`GAd9cjWE2bqc7LBg ziXF>GQ7cRL3Sv}%;4SLBfsYBh8cqaWT$7MOWz;DXR1#IsFGE$93j#F_m=m6_00FNW zkVbMi<@VHP80+}(fc|OsGS+Zo^A}prQeP34AQ9(FG82cY#ZH1PjO#V$L+~YgZ9Q|h zB2b!lc?=XC$AibNwPpFdw7uA6*+FZA8)TW+QeZ8OL$WYj+45b?M#D>i!*ShCz&KCm z5PVvaGNypG+_CO#w1_E(mQLyCm}xf`c@T1NhG<(Agdn8+UWO zav8K4(R=urFNSW~@(Uu6M9`Ap04>(1{G;=wnzpjl%=Sv~jWk=;X;e3G5k|<_E=;qM zL_7N2L_v?WY>vh_UI3XT8((-stFXdd4&7knel zS(hu->c3`dB-(Q2vY2KOVqSK)9@fA&8ff<{{2|r}$$m$xLB0^zcwq8n{I4<3@X;|< z?{SO@5FBGKJM$~xT~Ejsl^|}QpH)gD&{TUf)HWK#|5*kK|J69#y zZ`-E#kp4-EAlaGxlbVpY1f7^x3E0g(zL2G}5k>@nYOhyo8}Wak!ZeLU8$=+9i9>{y zYTFt}0@*AQW;brCFQ}RY?0P4E6#FqB9T=Sz{7Tm=K+q;eVP5fPRQ(HhZVUZWwFbh+ zK|2Xq1P8+RvoaeyO$p>|-_yvMdNyP2Up)OnsQw$5k#vo&T3ZoM7J()Ss)qrG4dajEaXlA3)Pn}#8#H0L zPK_T0Othdylre~CD%olXQHMlQkvI8xIcNL8KfR~#Hn<$(KS(;cp|UWyzxdP}2P{?_ zTXjzO-oDAH=ZYuTnb@h>A6kv1k+b#KlTKp(f<(5e#sms`rSMxx7DB(MB}vYg2nGqZ zK48^r=k@MC-OniFm+l*5Vrs^?+@!x#hc>Z&7}i zLpyg~xkV8u-egab=LaUwLP$O0snxF}5c7(3bYolodCoiBU%PK&uty%@P?kBz6vr}H z%o46nX_uO+Jm1^hCnmP$Z80~-c8XK3^Q3M~o@ov>X$P_K;3{@xI@-hglP9KjXnrqL zg;E5<4K?p`40b-~R8~3Xa#yyiR*Bf+;fK2(JcqHJFD}0$1GMMsyia<%N8tOL3|dcl z>+x~dt^FSOemDMX*>-%@>_G3=+cA(zmn0Xr0>-2^@&dz{xj~3{aY+P+07ZG(otRYv z)OUod{@7;=o$bl98n0+}1qis)#tl+-V7qp%xaIfD81t~IQ>wyg$OA`*1!busz+eWy zvtQW;rgjDK@je%}2o8cUZFxIS=y|R(r$>Fy`I;&MW%l-OHYKTZlfyJ5o8X`f_HgIb zL)HD5>&BSrvE$Tq)Bn|Ov>JO_Vq$~Qj5XNb{Oy(tYyR%M#?{^Zm7)pEY<1sBAE^tz z)Aa`&&+#^_Qto~3yJEl>+R<^Yb3x7f97~l=FdU~Hu4TWn#f*D&7pu;F5Jop2bEaoA z5F97*2i0d)K31W8@7&9GblRjWysni_r{hcIe%a*P zk39^wO3k6a=Akooe!68jIQ6}+cn3soTEcWDTj`Ab%HChO51lRCi`)+=kH2I$Iu=8~ zr^De;HX=#YjqhywG2}A4z7+lL6u57S`zE2Y^8EV7A2mB&`NJT`gRpKW8frV|^~wgO zTk51{>s3MUrL%X<`y59dBb}A1pkL$qverBnur=xkU33!hZ!akSwliK~cDwQl5FGzw z3;r_yk@|BRj)jUVO71ASn6a$eH(s&wBgV>qEEsu2*{3^yc3uzPgQcou)l+~>p8OjE z1rbmbp(Yrl;f26HH?ens?$7vN9a!#Nh(yBz1na0$ihE2><$7R?gjfbNAAX5!vI!2- zgk+gljo_f}2pJ(A1#Ym($_;%%(;Y2R6ams`&zx=3)uW|{ch1PJy0AOZ4@V?WT{2A`i0bmlrCO&N6!WStjdxPxY**mZ^( z2TeM^adERpl^bDhOib)aswsKN-tsS!^%7z$`&RJ3^}5pw&2V!{SJBHgXPE#^uh3z~m<8>2N*>g(s5sG+x>4 z8?X^LpTe4B>ic3>C482A4Py!KHo7?V-?iR%z%f|e`CpqlqFEZe&oNou`O}>~&ou+u z!#O^1q&PlM{_qr=stSO%>@22e3Tj7xzVm-x-TD6)cmDrnWPtkLU%qFUJAb=Cf+OeB zEx)W*zERmZ1wD^IiJ$3Nh4|7zxMMuWlCei1PQs#=VSs(oWKFZS1)chM>{El?Z{H<5_obABUf*N(149o}{t{v|!`tcnYZe&QAgrL9!lbzO!Adt0AT} zRKEnIN3lcs=)}Abk^}zLC4=RGpc9=sR*`Ki1Zd;fWl4b2W~j;|I1s*wr2BcF^m;wl zFjnBp`E9>)ojA?~!j2fI{PNp?Ouz4ElW&u%Sr#fgqDY+2O+sMZX2s!!X$zd~%1*uc z$Szm*?8!6RoyW;+7kLt3;#i`bjvWWD%bLen=H`tfR+cK~eXOUyXQ34{4gwS$(suld z5J=$UeRpVf zwz4xSJ?rqhx#h=r-MuQAI|s;u|Bjo`M>CpDwes#t6mg#^xCZ3_wH3RnN>SK*)&GARr`EHt(-Z|3oPQ3co2b4rs~uY zMlFqFw4cUtoGVBKI}j*eDA2}=&M#gEjt7B?An6TM9&Z8~pTF>Jm|V-NZ!xeFhPwy> za&e&72N58SpZVxoP|yL`@u2RRU|$e+k4kA4Xt5)dtyT~B8n9Xwv#bqvgvT7zq5LZs#;&?-T0STam|r-IQZDr7{~$(l7_6U`o7J+Ha;s7tSC%)L`3u( zKWH_QMnhVUJqZ%fHYs{OX!_*S3lxQef+Tms&KI^Q3(3K|wm-WeM@?|tV~IvWJ7wk9 zGE$qYzQL%*ArdC(KFC#R9GVIO4ku7qfJ=Z(ci6V@MOw5GFMa^nsTqIdLIFZ@z#qW` z2s+VS&v+jMy3YZ+j_&YyeR+*}df;5sgZFkD+<5OfAqMqQQ#n!?%0$05tS zYD$fy;p2#C9Hkxd#~vQWSoYJK2dz2>1&2rTI+z&>T47_QXp@HQHud*ys8aY!TwelN z&CUqJT@~@+^KA@&`edp1rTNm-KgjYcB3xg&x5fOIv34)?89PYXsW$$y&AyZV$@I6{ z%~0L(;cFyxy;D@x3^v0zBc!iXFL2CoTs;~GUGKPHi+(0%<#qH>DUR=)22`%2mOv(a zv5_uL$%}`&9^#Lbb)SREFQsW;A54It_nq~?=p;X5k6$r0NfPYDyyPo^g2Awsb_J;c z`Z)4OXMMHz6-5)DyJpQ|MIco6D{WGID)S2>5E@7AgvkRC=9e-x^;gE4-qR_r$Mjl> zNhmNJDj0L$2;}cm^U0Q~#Y~KYOjMM=Ay-~@K)C*NyCJHo?fBkz47i4|7J0l1uw$yS zK`xqYppr0nd`B;!vM@gcWQ<`E(1?N0i@Yl7!Cr2#oO=!Y zTE$8N;pEbW*Vzt=rt(E5od^X-Vcfw#CFZjW#4Jc_E6m)?a z4w<&xHvldC{4im(Cwh%ZgPh}bgH(2^nMEq5ET*b)%4N&LB-11Ec^c<<_9>g2uWIOT zsuJf5ZM@0(m34T#{PI*!J&m#a9_txRmUv> zUQc1TZ~1uH1gUNh^FSI&^LM&D+1sal-@AQoFO-w-v9re(UTbUf@phQPwB_4=+NLz+ z@wvWxA-J-|h%SwKHB$wZ-rfxL3PEdC1p+P96jc>yhaaj5keuNGd?rGG-KH|==Q!s9 z86=hh&9AjZ>%%gj@>unG2Y;Jk4MY}*C@)Fix08rezKc%hxVT_xUgRu?%cjtv#?e+; zu-XE{m^TRyiVc#YutPmomoH# zumv*HG!oxjpz=STs??3TBS1((wgEEvG!7CRk#brFa*nqsEiG@ZJij0((mJx~i)p z{&gY-qt0=0y;F%I(lqp5x66VQ!_j#h5d}(NxFk5*s?-m3wmV%wCE3s>aBJ zRD#{u!r7kLXwNmuy71__dCN|(e}W{`%yD)|Weq5E+o+E;(1tb8ap=CI=+r<9{1}zS zH)06q?Z8^$zd8kpSuLBT6(Ay!jWiBPAOwd_4M^E(zY2K}j-ISpSk6w;I087wwH?O9 z4uecrpdU@~H&v;Ed`=Wd1k86x>0RiK?DB$IXVLh3f{VvH-MP&~;bu-i$T< zt;3#E&hpnt0s;j|!QXPOJ@6P~nUgnq|G25{o3=u&RV7SSWJ)3nfzhhpWWv%yt2y9t z{i3>pfr3r+F63HM8otjt45-}CSwQ9|NJx_nD$ooztR*=N${B zL40qqd)Qkcd~h(0g9L~6g3&t1QR5KdxWPq#KX zg0=<~nHVX3Aeavno$QXmz~HYF2(odd{1HEmgu;_ehBN|1s8q7_1wjaj9b&$VZ;99I zfs)*Bu|vKz18)ozj=R`%UiHG`2o4f-p@!p{1fh`_weg-PAPteisWos6bDrlsPti!K zy8gZQos2c?(IT%67x;z*N$!N5@pZ}BZrC}F5IbzT{%N75jPgLxY8Zhu4lOjt7m2l` zNdz-Vp%Xu-g(bu&D@PtsS>Tre8I(i3IB-eC&|#kd(Uwss32wK>5#+`;3g5L}ulE7< z!XBZksG!CN~Whb%N|D-4DmCie06g&Z&Lw8mKH#O@8Z8(zQy>{9op5AN=F$inBfB%y9y( zAGFa6lmJKqf);qKhM|2NAo|MZ1+wrPM46o7E;izL9-OZM6^&#$keQy4s8@hwnD>z! zvXxQyD?4vel$Uq3cY_DIL8tqM`kEc*g@H^}*Lkk>c>IG1#C*wAg%?c1iz!o6KMKP+ z9)+b4zhkiI9t}v4wEnt#_rBjSmOB5W>pSz_gZlbF1a`K6R@EhxZ(i=eXyU>clGO5T-ThQCVp!wE%gu4XtyI z`(eLtzi+k$$E~LjVWcJngE$vBUCyU#Ok0XZvb$@hevL$3_LK#tAU4NyptG{>6>hj- z<$Mdv$Ok~k&T*_!mJ zTV=eZs`B{g-pryst(5EU@*SNv4LU}xEt3(d#v#@bO27-|+n@!SG>t$Bcfo!aS|7}= ztw-}RYQm!PK{fwE-0%vGMB{AVQwdz;<*)KSi7%&bp5b?#x z-+g0%%=~pi(_l(3XaitY2@?_iOFj}6w9eDIFLJm1J~2owEFUgOo?r36!IS1`XJ9n- zKT?QrF*2Xev)Hpijpn-A`z>R|PaioWx399}o2qCW%GvciSzTQPKU08&G2!FD^Qx_m zYq(aG-g#4rzVV@?H=RI`q~DCtNY3FJ37gNZXICF{XGKwU3@Mr%#yU;7V{z#yG7R* zIomlZ*YMGUD~m7S3KPtPHJT6JCV0U6tHuEjAJ)E5*d$3p+70bag2Hhl4CO-yc#kqx zke@wqzjA|T->_-MAHOMQazOPDRcEq*7pidPQ#kI;DPvM!vpyVGXdEX$;pO-Bh5u4xt1vZ^P-|5=ngdz*;rvupR~t@Ce@6&Q2`$jtdPT5}O|EaB0`BA%y?Fv3>hSW#hGf z|N0}#oe;HEb=5JWwl*nZRJoFhZato^G;r`V*Q4^+%9oUX0-dJIU*VjC9X?K<4KJ)W&azU8^b>wAFAe+TT=E7JpQ@ znco;z96w^vHg1wc;|K=#>oKvhxr*lcY>zijf1a@>IVXMD`E>OuW8uG^%tm|qGq&%i zbwif^t(G9!#IK~{50CUdsN8>9#hch4+ZZb^FM2Q^dcy~6-H@s!ZOH3XPE# zXsSgO2y<03#|OY#f7fa%A=a`I^U`j_BMiq+Ku;2XRPh}jY2Eh)-24U8K&In??&f24 zm*NY6TZe=(S8G5EvRU=F-@ql!b#izR(r^OSQJzVy&&=n>PKS zXv77+?6dZbRUZGc{*C1cV7jVYTQT7{$I(Vl)h>BsW#c9a*VkGkbUNex1e-SeHpC5u zEctL{PXTFNuf{u-*8R{;SSb6U93Y_TYOZSLYzuv==D@EPyF40)E>K2!bv95D9BWf% zr)FCij;qx;45hJ!j_O;=%ggRkF3^toV-G`%{yJjH`b*jSdQ^B`Xe2Q`a!*$l?Bu!4 zhPGU1-~gnN{Fs@!=cuwkjNH(D#o3DB_`K@z%EyAgUAO5-i$Kww!Ky%$#u2K?N!w|Y z5M~CsShpnUFzERdNb7pl)qJFNKd@-mnMf!ENXz2qfZ2D3KGpEx*MFmq!}$;Q{W0$| z*6Pfj2hPZ|FdUa!#YPyup1$k6%8gPuF6Yku<*M)CC+MsvEBx{|>M5M(xfZ(4R|H9` zQx=`NQqgp8aG&K~ssH`zeW;u#&&$;>RriAx0?29-UA3UUlLkV*4O*B3MQzgS0yJm} zwDb3?P8|rrd@PhHuKgUN8k4r4ku1P@mCXXux?a_fkHN!^bUM*Vd8@iF`%>V##1N-z z99rkHEY5n9kUGEpzd9)kYutpS{Dvl!G$8l}_y(vWDc&}pt)lk1hcbU3r}U;bZxmRgVJ=&)YDxwVvt=RNHee#*+Fs?%MPoz&gS&G+Qk3Gv_6WF|X@ z1N9$=e0!etK;`$I1yqiIJCM}~2(4yErm0}}cK}nD*jNV26b~do=ySCTy7n>6%V@%% zw&%Gd5E<+k9N@VYNY9qP$wyk}g*Q2%$kQo6s5OcgbEL~Bl4cy+?hbS6o(o(Lk)^nx#aA4uzXIfg&bI`0eG!N_1aci3A1${x+VAGogC z*!y*WB(`J?rObvm+4BU{yvqMN>#9AMGU4Pl3eh4~5{tdaoTVM1rs{0fV`UGQ{K{DF z@7rS6D;kN<>+R;%QPRS+`H|qLr`MHPa7+a%g5*4)vQV@K>VLmhBViY+^k29G)d~xw zkzf^EUoKF`M6?UIwhD4E%|~YqEV1F0%y;J3i(P{wHvnlJFME`a;*JcuCg~L*cp%!d zm9NV40ROm5=lcUf>{M+o1rc#zG)wWGBd%O!hva?5^Rli+KcsO`UcDq|OPCUZm0ZB@ zU3l@qoCBXKJD~YT`{#XU;k?kd5vkf|bq(Iuo@&oaj8*I`X;fINJh^BIi@&E!MHm`M zGO*SLBUs}m(nz!wCCKEcx0$mj8LFkzX0j9)@v-t|d{qN{dC(Qvpb3kd@|EB7v1DcWFTgc_(|rWl zYG&CCAM*``FxSlX8>j#Ah;l~%dG!3l3m8*t_AaTZO(k6#8V~#I?`ahQzFz>BERq4K*GjX(HC zW;zSMB`4g5bCpZ?NJU0jcjZ!Ep7+kd`HUsq+VqVUEtK={XKbgq<8^XGh#Pw=9B96-!_vnT0sgnbUir}F2VC6gIu1bRHHDvN$Ads7t^;2=kOke5 z`x*k3@gPw7!y1(}3-jA5YZiX(@yPkE{hdie(f)m>N`DhpoXUXfktnvP?HgqC`Xx+f zbROt@X+b8f+t6Eznn}Ukz%Qm2{0dx(f}{YwB-JhP-9HDLhtZzs_!B~W1)y}mp7(&i zz3KN#ZR3-A7KUpTJWZ;ztA;2V$p;%7{Bg2!hGX(K=DlP0tZHEy-*@>A07E~FuxSta zt5L49s_gFKQ=#F|h5;+iQcYVwAJ4Q^S1S=j8q~-sbNGe}S3U!k0ScBJf$F;8A`Tg$$=fd?j{<4kF5SyVTG#dKRz?K~PSrbrj}@46TC}Vp7nnIlNW8f~CVg!x+o7#$ zjOWX{(ert=hp~Ng*S@n%xxh?9#yL%KU6S7 z-I1DG+e`C1_-P~$0gv%M3Xjz`cEan#n*==0Mj?;}qV>t?4eB6`gVrtCf-dNMX*DLT z37JZ-(8gVpe^ZhNTy#EvR7~aDZ|9@X{dC(FLKPr*33{-0O7X8dPX~VTNzk1`6e_d{ zcERA8UsVlN`s89vQ$}!7ge8E)q>g9zr-~JSd&*GOpd{v)zGuOr*hr50y6({=Yj4UZFp}GO;;RO zQjH^E__?OBey=f}4X$QZ8E*m1DrX+F|AZal0hL;*reR`o=jNN+yo<(1tFTqaX| zf*jDAUIN*6gMc)WU1uyGo^dZ@M=!`+zWXJ{qoT}g`X44l9zlo;mS`|U3jmz0IjTl- z(Gg`q+5hUAa~FRe6(sb#=jUggwD%Rp_6}I}$in+T<0zRA&T>)9$)+7OEpW~uK;yNx zd{cl>CLX9fo&`M48?+`XtpL$%O#FNzc0t>_K0sK!Umq0`ltJcS-ULYNavnA(F2;4c z`g44l;kv+~3J_cpNaZObA3MN z?ERlG`veIINHPV`!etPC4SxclvZ}O6@mAH@-eBb&HBRCa2KYM{EIl|hQ~Cbc|K74? zjq>|@f2%&bsxhMB4^s7868+m2kT zI@>E2-&FrK67{-LcBuKuSwr^zqzI0)Hg;cmDb$>*_EbS%54(a^=sKVcKoB^JfFWok zWZKd?+XHPlw1UHKO+yQ+0v%*y=~va);C*uVG~k*~`J(EO1v9&rr`w3G?`M2ihAbP>mmppw&n$ceYcfKGLixe&65?>Q|z|C~BPTs%fjf zY9#7;QZ^)oJ9FR4`jxSq(k;E$R4R8~PW7EtcJ>F=84RL@RwFT7{a5R3_le>@$9$dL znc`ZA^oAg&Y@yMISk<@kWnflH(K6t!UHq@5AMugaZ5Fg>VjzSoKr;B?#XUzwXFe88 zuUG?IeQ%h@uQTvX2Qu4LV-fy4eeL7RmZ_QTtyGKWl2FSv1^`8O7~SzM;nlpXsv%VG zG!ppLlpSjR;_SxzUQslTC%DGpdB3`4RUQkw5bAVk9{Y(!GnE~^W0t_`bUwHT>#tz=K<*7ASL7{DBgYX2asa0hcXaix=bsu&@;y@t$&cMJLNyMS8`4_04 z3BoZF$Z9mXFdOI{j04g-T!^(SM8l|%O;-ey1PB|=2M?A3E_uCR4RFIx6&_%g39XVO zfhK%TnncL}iF%%iRr4VHcmIWJpIACZ)kuznrIDz+PD8Kf^@D>|>9q)TO(RjSE9Lhq zxg>w_VMXv~HQKmgq1QC) z7zC_IU^Gi}s(cEVH8{T?aKlghuO-j$k=E((!)+Yl9^lxAi^VE5C;zkI^}ykcPpJe> znc~a>n)|5{0fpJM1=>BC8i*T+iW>&8K|8N^J?(Zg)@EF<1O0X~mfE}Rl#@FuPYl-A zIHz#N!8i6RJH7n})~;LDzSfQ@(7Y&!KoT2t%zqQ!NnX!b`#GoIGvo%w;?^Wx&>-x6 zSQw~%T@^5ve?j(Z`;wKNuizl(xXD$0%hv!`mTF6u3#Ez5DSYR7#zhvypNU%C`KuN7gac z;EERMZBA3J*nO_fZnp*V!$w!7Hy3O@(vY#N>(}43{Hz+mp@m}^kOeMN9xlkqOJ&WC zCc0X+v7+Dca-j0~e=3>d7htVEB(JH2zB>90GPvWXGV+dIKxNDW8kir|oWgnOjgk@q z+M$xMJu1TnW$JIa82C6^fcButst|1qo?r3h8R35-huInk0log7^Y~c&ARiA6&2a(W z{LP}z4H z_%pOXEX7{uqP(r?cdW@#Sbo6b z0!}R2)c|{{cX+wY8sPt3()KRk*d-RvLqPnHXj7FY3>P7rCZtAfxs>(m`9Aj#fU@9I zOA-rDXDsiXoe5j6uk}I_$hkn}!fFm=*4fDE^FqyF*NKGqhCin&3sbwDr!5}zDPuAD z@fRmTe!@t{WH#CV^<--F{pLN#o5NVqcZcR=EBn9f>P@+SB%{XR34dOG9X^A-Ub5?o zAe_l2B}CHkyk`TIQ7xKf-~bf0^)67kj{gTV@csy0mxLS@(*_?<@zIa`uY3N@DyejW;I;X5#b9?FSKE}&LOTl z-Kokin48cdX{NGcd#Su{NolR97&^b&nnP4fFF?3&xbw0+$_w_fgOmm3*O=d8|HD|y zpjPL#znHPa9~;2LDif0dF1#Ppwgv{}>NAj=BgL3LUyxqMU!=H}P z?{8GlL<(YOZ;^&g$M-$}R86l6S>W?U_aQaHLyb>pHrE4L&=$_33bn&#>AG6WvMp;M@;In3;0--RTGddI!M+V zTc?IbB`2K2fGl`Ze|(;7*M{dM+YUO&JVX?gNido~DBbm?t(j%9<}bcK_6!fEkp$F) za0BG-4OD*D-asAivlx4t0-uY?n+u$SSK6)wJ{DsRzxQr@d4^TkIijHa-Eow+sL4X0)XoEaPJpZq$AIt)5SW1&E(d1T~QkKepKo{CjcR z8-U|N&KHqxr-~5sqKt7_@=8qFsZw0Nb1P8C8-i#gvi^>KAVEUTZHp1G>TIMIXoHB< zyo_GQqGlFp5IRB8x2~;Qg*K}wPHd1zr(6jmTmBdRC)SiXvn zdCts}fpfc;mH>C{G4Oa8~)ckT))fzgR{eRHF8^sNDB~zsNUO;kNFSqaqp6xzQ7Of@SFnFaU{A> zHO=GghF?P|yP*vtFxxhc3mDm$Jud@Ua6vLqCG$QBWYU#D(G6TE#ZENX_YM(4;Np1` z`2{wgFTZl-RtXLg7KTkVL4OW34=2vElQL_R_a8zB3iyMF-w`=^R)fk)TV8^i?^ z6&%NhR^zY<6h28err1GJ)Qa|ZjIc?_D)`cY;cFziO*E6)G4oQaf|yr?OpO5r2c1{C z-boV*F)ZG(9B5o45k(tc28N$FSk)PLbUhaw|Hee@?AQ26>!c{lZkvt6ZViNx#s}8| zJ~qCSkDaEpE&={+N!xRQ{}^V=?2ZAy-p`WwUc`kvNu_jxmYk4UjU*sY&=^kWvI(MQ z8HK6R{0{;3Ya{_RG`;V$D6G`3;D%rtv{mz>8dG|Ey%WTB{uR);Mv|QjeDk-=4B#i& zPiZH5YmQ=hc275adAj~1n+v-&5JCnYyr`0qgw2`AOP~Dsd46x;>dS4JU2TxfnRZ^X z2@ZoL7p#W1YN=Ku3Ai)YRACjRT_i=onq~OdR{&H-)i%Nces8g}548c8*~J!VUX&mg zsq39I3OcWW=4DcK>OgSz1{xOt4$PHY5ITsv1F5-X9L6a4&i=s41y8ani z16ec>0xFA6ERvDYnB zKqj1<0e75e!k{>OtMe~{A>?Q_3_5VAU^PJ?A(}vifHkSYf)Hd8>PJGK=STr6k2e9C z-+2}D3iEs!o*!kl=L1oR2=?-Nk$?*ulqYH0?`KTR?>@CM+$;xn9l3;!F6Ly{_mVz!fVB zegyvdl!7Z1>y+R7Ar7 z;IH$z;8=n6nX@(Po+lgMEki=UUtm>3sc=E9SzXj!UmG*-c0&>=x)ldqL>sSg@#uh*w??a=rFbSCq;herxrEy;a zoi7?`fu>R$C_o(Pz?#=N{taZJ6o&u_6tjFDKdZDHWSVk346OCUB9%3-)0ze?^6i8Q z(b$RvNUBQR0^QRM$k^6PffLs7zy3)bT+{hjv6_!Q>|xHTCLDxNPFe_9lYrab6NC4KnF3`NI+5!ub_ih6| z^-$#|;MyYmkWPFo&Ecc>S$x|>OTSwfkky2x1={>P*YdF#YiaFmQ#2d6;GN9-fNz}R zxds^gfWm}8fDz?zKQU=YzSvw)$;;d@Z4NB&6Suf-WMQ@$Xl3kUm$_*iD=-S+0A8Z$FUL_-3>{bn)-b zd#7jz~apE zUx7#5jqU>u9O&EvtT}+6Z$p+H4(+^X$0^ATBo<)18*gb$W{$nU+Pkjb+!lU5pOkU!PRI^BHHRM`r@(Ve{SH7>9KP^EpKSj!lvLis7KHXdoKUo~+^uJ{~#3 z$GzQ;GT{8P3*HCLZ!F$Is-+~(XM)g#s1cLh&;}96(oX^*qF{7tB*GbcH!yHsfpCs% zoV-DyJzwDpT5SaZ)PSgHpD-Qjgjk>>ya5o`HGPkUDr=snzel)_hEa%cUA-D42@+gq ziWURspGxZzf6?C2e57@&q8vX>qK-xSAZr+}UZnHEbsirZV4`80QGD$2dzWh9bKf)? z1nk^7;xh~Y=^FkZ><*JO3g>2^f1{s(KogMjOJMk6+GhWbL8Jdj14EyX;|t(1j$?BJ zH4$_`jmhx)$Ql-}MYvIz#Y2HRcKkU7_}G>FubVMIJM&XM7Ey4}e0*C7pJXrUs0Jc{ z;l5s!>?Npi3D=)d3>aGiPkAvx9UXWf@7kt3lQ`Y&{nJZOgiXbnUQTS*oivp_a$(O)E(MnXIK0M&oR0&TKMDBK2U zBJmG34*K4w&M*L@&?fS0J_Vm`)VB2JT&@#)dYUjom%v||_G*rRc`0aNCM`@z!sHYA;w z)eya`=K)zwsf<9N1&+$2n|!{){T=l7)Te5&YE^P8w~1r|C4s23cfDP{Hu1UIgieE~ z>Iy8lV9y-jw8n+iz(u%m-He6x4=3`m5<9H=NH?xGTefw`>< z+Nii-3p7T}TCI@?O;(%V5d6=~aPceK2LdOjS9}00xIpg*h=swZ)6HVY+Kb&T zhy=q6fXu(P6ovOvSShurrBy^aEAzcwjNkRP`0)@c_d><`%K}=yGn`kVq0v+o2 zCYW}8SzJw+5N_i)@}=#(5=eq$5pFO^aO7^}V>xCR+280XQaI5B2mw=qT8-Sed?x|;i#1V{EMz!}|hx&ddS z&bkA`a!KPT!`cQOG-b(Og2XJGr~-tL&Ic!IAaU`0Y|@91-A+k92pm+@vK)BbhDO%{ zPwf-&nQ9TK1*g718@8-jFbq4}3A6x`3De+$C`>`LA&Ic5(QyD+tBNrRP;!o&9p+8H zgUK5mVWPTCWytd_Tnt>l?%Qy2v&P{N`(k5qj**!iK)#oxDh6mVC&KbHcZA*VQ+sP-oF zG52>qR$$?K2;jw|ouH^|#T2bV1|NKA%7UhqfJ*EHR)+C7m3c>Ufa|YF>Im$3LChz> zmQOgp09rReVH2k^*Rqs%mlWcBQQ2)xzloq|s**V}fvlz<2kp!o0&BgViZ#vw9%o*( zaAN-tQJhaN^cGPx2$A?VR3&p%0-1jw5|iNg1juTF3ygNK#G;r&^LRm}?(^e&1E>fN zH*js|ZL@&SVM&o~+xWQWBR(F+%<&3*x0gE9r0bt?{X|p)IW{oRk^&853;5WmijVD1 z=VO;Kjgo;we?NIG@Xj394L}oTVv)*UUtxAQHHDixp91RGIpad;*P2#R%`xEjiEztc zqnelycm|6xl5b;AGVr~YN6!QP?;rfx?O3>fKQ?m8kKtq0V0<^lvDMqCDx;|HVZ5P& z%En{-Mr9*D=A&k^w~UWldgm7df1aB4Z{UpS6~6)t!(Qq|rg2no=z?E@omt1l1=i~U zvf%kNxS)v)b{ff-Ai3ZW8QPc!BU%Or%jgdiMl;ogfYuovT~!Gz?2+9JIAb~&96$fU zpWTA%Al=vbXtJXFJ}Ni@A*zAsLmD3(xKnYr;$t#qwzt6E>?bEB4*{O_+R25$$ExB~ z=>H&bW0O<%1kc|HhKMI{>fD)&c~Prctwv%K0!2RsjEbV_ztjsHH8IQQX|QyRp9X{1 z1JB=JZ1)D>bEg$e0xrT@RlBi;Y%ZFpi}7(4CIqUwA|NBYZ&QB}6(Gid;du@U1769; z#D#opdXSHuvB_(PJ3HqC@9ESa57_6jKqfBVSfKJhQ&mP01fp~X3ED`9QCVN^jz$rzIYZ!f;IpSgzlQ3Xt%Cdo?HdN}BSqF*@T~C-JdE zu%Lxdwmcl%=?dpLg>eM}6&D->WR@+!1d&Ov zIZtATPt}DD=68s&XKdkW_V@4&05aX->7|LleT(;>4*aBf(KO)dzwu}HV7N&ZY8Xec ze^4dnbBK&_iHZ=_4MYWqIY{FJ87X4W`Id~f)aK3k*nSs|@h86myuVfIOki&_-R|`Y z!dZHcO6g2`Vj(u_bVggh-b6m#^9kZywmQhbC`33eHprr|TD>N$d=GHL=R4K_Ur*(K z-M0$Ij(p6;g8ju9j$c(ppN@ygFh27r0MRgBbFc?T4Eyz>Z=?#Hb7goTmtewC>FE4l zfLrpa(tw5S;wJ!4-sb)V7~ecn6PFdjMD?pmfn&TyRXsvgqrd;ksStm_(zU5$l;!Ss1yG!aEFiC};wD*c_snkX;o zYa$lx0Q1t@a4KYI`;%ycKQz7-$Mrzvdt?HcU(GMlFv>pz?r)QK8*u(jxnqI9C?J&&Se-`B+62B--G|MxEgiLR5g*3(9!MXb|Upe2m4;Wyx6Ovo*%8x4|2v zb$*Hu*zfNxCjqbdEcpjuGYPx|`XHN$iePy;d@@xX0GilRW|WRiC5R0RO=VnC4abE^z;nLp^~%-?n)r@bNRb;P@T|!@3{%NZ0wE_xVWo0o@mL zpNJ@`sNk>(Q4K_D(9h$MWo2E1`w-1ESQ zO!}{ov<4KxHx$V1n-}GUU^r~hMrHJRZS`D}A?85>ODkBlB}Yh;!q-))U@WH)IJ0Zs zXdu;`I*1E@7HSx|_zerN<{X)(s-NJamjs4+UoZ+&5EUSG1DK2JKx?*h2p?lE=VMYo zKBi>yu_?yEw?TJw%NDJl2VOim<$BU#+oBhv~4YXj!;0-@djutq__4M-d4`1xVdQ0N+VWYd$8RbDo^>WLs!;Dj%CqPI?m9HM4Cw z@aCO752e}L?(>1+Ptb6miwHqF-;1`|vPL5jJAFEj+I}D*hW~0IOnB7)gftHNyj+#c z^9GQyiY(xvdos@femtT02yh!N{8U>i`*S{GkRdyQ1@+4?!L|y09Z_FKT}4!Y)NPOv z0psBvMSOG)=VNRqJ|=bLV+uMSn_zTH)1iE9xjQKr*fp`~EZ~r3iT!}5JP`LRuvuC# zO~tH^aArfyi%ND#f}pjYw1Ol+>s0|tNHo~%T$~@$fKcP`ZUict#l65o8KoBh|9tK6 zEa2kN#g78Fp=ObTiL-g1@bNI#lq$erkkV25b?R zdlLmg5Jg12oAb^)Q4s|h5*a97XhrE%b~R?5(5`8lrl(0xa_rmx?+xaZu4|LJ)Aj#6 z7Y{kKYtFXjJ@41^kL`HyW~aQ?3k=%4j*kCs6iBqR_=9jIqxeLaNK~H}PTn#l z>X`7)<9=EA7p0_&^xkI1jm~nkYxy^$OP?C8y=pYLiMu|6YDvnP6ka8;0c3ZeV8ki$ znkT^&F2d=vMl%GG?8ioj$2)cO8KWb34vjvWKO=nj?!iOC+fIAe3-=e&tLXiWY>1d1 zz}0m?+o-e^g?eofNYvK6;R~lrl|kXJV^cp1zvdha-LELm@>-{$a8Q{4%;@4FqyAx| zbzE(mWBhb7+pxgv(iZO6Vh6wmklhJgw4(j$;G>$NIiGsZXqsmH9-b%%=#C8Hanw?+C9M_Z;EAX?GPpxRa<$Z(K5=^=#C;g$9xn!bH2I z)yxZ50>pXY%>Md|!hhaaI4YdDf7%!RL^G_y@BRGSM$7chE`DirfkEL#GS=nijMh0L zyh)&GYO`B+%5~>FMme9wcESb_i~pi%qcwRns+vvpA$ZGByn8mx_iGD-dEB$vS9`j-H47`sj9~%G#!gol&6H>6`Xs8 zK``}&@Eb~%RW`OO^u%V#DCYThTi{6M3R6#uI3O&s$k%wpXn@&Zi(W^91C~O404a8P zTNXPUHh@@M3i?5zJ(UwE^ZQ8xgo_o6hiP43&1gSnb~&1<28_lBqd_-nm z*jEtVSqhH{y>ADO2@edrM}@;bCO#56ulGMKJh-MR13{<2G{8{eQkO0l zD+(8DmNZTLKAwpCD3Pg+eTKc3EC+IB-bAtG-opo=2C57ngx>8&Q>U`$h1Z_T6omQH zX4+^al+3NNxXJsyd)XadEYh8tysQ+>r6NK zuNc+L!e?({nXj+$_gN!zsB06OrgwnrbBkto$iiMbKjP(Ygi#UTdJyB38hDPm^(M-J@u|&(Bx?UjjnAehX4Qo07*qo IM6N<$g4k)%&;S4c literal 0 HcmV?d00001 diff --git a/src/images/drawer_logo1.png b/src/images/drawer_logo1.png new file mode 100644 index 0000000000000000000000000000000000000000..4152cc40edce2815f0acd9ec48d233dff917ece3 GIT binary patch literal 2041 zcmV)-76pvCA*me!29MAo7ZEa+u#oN zQvd)5OG!jQRCt{2o#~dNAP|KGj0?myny76S^ZpMxnyob;Cex_E;rsML}7X zk&%&+k&%&+k&%&+k&%&+kp^;-Ly|aazr{>SJUcuC)Cz#o-PL+=Zv6@b5Vvf1A%tOo znra_A+qK_Kgra>zFrbAnA*8fVc@nMtihom`5yaqoaY6#it6j&cezr+SIC#IGEg=}W zUY@M|zF*6OJp0k+3_xmoi9)^8{=|T9m~HO_jazJD1u(ZM{2K6qi6F$;wetM68MxYp z{|neNC&^lKCX$-d{UhL$6B2^l<6geOwh{yQz--NV4&B0+$ej82gUlpm+dC0xPPG)h zGZN1C;)Ly_(p+|aw5}`UvivlGn4K$>rN`V~t9Qo1tbk8W4Be75#-;|yQjXA44mFWME_E;=eFuLiGr(6ZbKM3Jt1981aH3$feq= zM`(GRX&=(jT?GlZ<3_|6y19acoX9d}i0c&SaNy3rnIXtr3 zs!2E!&tPuus!7O5ib z+tbRihRPDY#WP5*AK@ST9oT+p2URCzZV~>fI~}JyA$O_N z9fen&5J1kEbf;SqD^JLcI$<3M$K&@_a*JxHPYBT1vB(S3gbZ;+{T! z{|`b@7itJ2WV@%&Ekzv&0by-ZJa-heAVeAcbpLr&K?_0v3+m~w92-3d0elZ${HEBf zN9cTel$%FLg@J!FY*r)`X~Xxo>ZQ8rLWr(|-n55vrFjR;?Rzx%;Fq!HnB)e{XbYtV`Ceh|+phOUH8g!i1%_mfas z5dsv^2ch&L#FZ7jpSjeF5WoX_2qdr-{^WwNQqWDb|4$f2$szXrxh}$b z3%xE#=!RiaX4$Pu5{B@b!YyA3Ph=U-M|dxDHNQwb{qpk=E+uLoOFKfwcB@{5Bd6Ro zA`A}G@2)hVu(?87!s)bQ#R-upheldLC~7j4l@K-J0Ocg)ogmhN5bgv5%1DT(PpGI( zh%&JyXQU%UXTilkWh2Cy=<24D5yGqRsz_21qJVkznKpz7UPaD>vJoN}Ttp@3%S71K z{3e71Fth8q>L;&2c*lYmoXe|Q75mL$)(Uz{5u%O@64+vesa@2$zf`%|c?oX?9bxws zhUvvV<#FOHUgUZP!p>ZT+`3nJIeGispQj|=!i4D2yHHj(p?j=<{DUM#kA)B-k~OYf zo%TO*vTjvehC~p;)QRM&-ux~BggBHJ&l)8}kA8)~WL-AYNcUk5G$6cBS>52?q;0?Q z+HU1cRkRkpU==Qh+^1p^1Od2Kr=lI)lc?XV_@(ENsLklvai5H;s2-|C#`^aY*aaUeZ}( z+IZUoIj>k0bT#tTdV0BSl81i(phvV#WJ;uDx*r-rrC!cxUpLoVc&?I6y1Cv+GjDsK z?gj|$yzPN Date: Fri, 31 May 2019 19:47:03 +0530 Subject: [PATCH 100/306] Remove unused print statement --- src/alice.png | Bin 0 -> 669 bytes src/bitmessagekivy/uikivysignaler.py | 4 ++-- src/bob.png | Bin 0 -> 640 bytes src/class_singleWorker.py | 1 - src/dave.png | Bin 0 -> 650 bytes src/debug.py | 1 - src/depends.py | 3 --- src/eve.png | Bin 0 -> 651 bytes src/helper_startup.py | 1 - src/image.svg | Bin 0 -> 704 bytes src/images/black_cross.png | Bin 0 -> 5201 bytes src/images/left_arrow.png | Bin 0 -> 2444 bytes src/images/red.png | Bin 0 -> 57642 bytes src/images/search_mail.png | Bin 0 -> 10555 bytes src/images/text_images/!.png | Bin 0 -> 5035 bytes src/images/text_images/0.png | Bin 0 -> 7321 bytes src/images/text_images/1.png | Bin 0 -> 5027 bytes src/images/text_images/2.png | Bin 0 -> 6916 bytes src/images/text_images/3.png | Bin 0 -> 7265 bytes src/images/text_images/4.png | Bin 0 -> 5891 bytes src/images/text_images/5.png | Bin 0 -> 6831 bytes src/images/text_images/6.png | Bin 0 -> 7644 bytes src/images/text_images/7.png | Bin 0 -> 5941 bytes src/images/text_images/8.png | Bin 0 -> 7777 bytes src/images/text_images/9.png | Bin 0 -> 7733 bytes src/images/transparent.png | Bin 0 -> 24650 bytes src/images/white.png | Bin 0 -> 82182 bytes src/network/networkthread.py | 2 -- src/paths.py | 2 -- src/proofofwork.py | 3 --- src/pyelliptic/openssl.py | 3 --- src/shared.py | 11 --------- src/suravata.py | 32 +++++++++++++++++++++++++++ 33 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 src/alice.png create mode 100644 src/bob.png create mode 100644 src/dave.png create mode 100644 src/eve.png create mode 100644 src/image.svg create mode 100644 src/images/black_cross.png create mode 100644 src/images/left_arrow.png create mode 100644 src/images/red.png create mode 100644 src/images/search_mail.png create mode 100644 src/images/text_images/!.png create mode 100644 src/images/text_images/0.png create mode 100644 src/images/text_images/1.png create mode 100644 src/images/text_images/2.png create mode 100644 src/images/text_images/3.png create mode 100644 src/images/text_images/4.png create mode 100644 src/images/text_images/5.png create mode 100644 src/images/text_images/6.png create mode 100644 src/images/text_images/7.png create mode 100644 src/images/text_images/8.png create mode 100644 src/images/text_images/9.png create mode 100644 src/images/transparent.png create mode 100644 src/images/white.png create mode 100644 src/suravata.py diff --git a/src/alice.png b/src/alice.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6c6a928b708897009c3b211e6825d252fc3389 GIT binary patch literal 669 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic4M^IBzMRCsz?9+Q8b-XjVE4hJ7M zv9>6(m~tGv^iO$F`XbNoFM1l<^lEQT>)2s;ApVyWBZq{5fkFZZI~-_ea0FsT#%3U9 zW@2OE0b!7WISZv6^=i*wc^;j+Lq!@W0MX@e0HO=71EPyV0-_6MESe&iu`opzzO}cx zzuN}S&)=F@$A11i8{A@;3cRi(s3>Svx&4OsnX7Enet+M7YeORr*K*w80EGZt7TuXR z9q~z1uu#%jj&{Mb_je=EaQ!{E3SP5U-~OJ?+#H{Qh%8`4p+**J+(2R!t_T)4$chf= pdbz|LV=x1!0kp`%jL{DZ+Q9Jf(;5h43330 z7d1>T#;$t6Y4)&3uw47X13_<>HOxPjT;^~%(9poh*bKzXOl&MXAj}~F!U6^g2_Oto z;D}9;fC1Txn3>vSW85aZaeHg}_48RXnMu5qSqgMIvh%UK42L3z1IT`aD}n_A#E%XK zHcS^1e0@=R;q@!}Hn$62S?4dAUt4cx@S_z=fI$o-Csb`788xMtXRTj3KY!c92|2*P zC*LfP%TZ$}(Ogw&nqdPduwha#3m`F!;`==>*bbIT>~CJUvm2PQ7(8A5T-G@yGywp< C&zlec literal 0 HcmV?d00001 diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 6686e2c4..a7e19762 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -50,7 +50,6 @@ class singleWorker(StoppableThread): def __init__(self): super(singleWorker, self).__init__(name="singleWorker") proofofwork.init() - print("I am in single worker 52.....................................................") def stopThread(self): """Signal through the queue that the thread should be stopped""" diff --git a/src/dave.png b/src/dave.png new file mode 100644 index 0000000000000000000000000000000000000000..e8d7bd0b004741caf27eb657dbe0a66e72a8f2eb GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic4M^IBzMRCsz!d1|;uunK>+RKpyoVJ;Tn-BS zbXk1Gr97I|-Gg;sB-gfdtqtK-e+RKpyoVJ8Tn`HT zbXk1GrF=hE-vq9r4iQbhGa(83Rl8MBRx#AS%w$nWa5&J=;0VNwjLb}IAk4x8!Wv8@ueDm&3YGweepB6;gR*&<~0SwgM6ufIvX%Q2D!=9_OFJM>8|)fPMlSQiBZy*}#&Q&)e#8{y}{9@5P}a zEv9%nn_?Fz#@vZ_?J*#(mA1& zU-YVp_xv7_FaGVPnp#ak^qMIq&Qx&!9+}rjQ0aQxvk~jS*}mi?FW&zinKwI~tu{n; zB^^&^BX1|QzJGL3zRWk`YmkvXi`Y#v+VWWOG&l5b)xNva@BE#(SwBm)>i*pNPGu9= z>+dmn>6;m(mvxp=-_&{V0obsi9_Js$-_Ebf`gtnW%}r7^w)^*he6GKxye31mb!(v? zm!{U;;Onbn^3}gJ@<5|p>U_iN?_v3M%nU%8O6FKoi_bTX&adYuZAeY2#9zCm_QY$> z_p0CdJN$ZnvX}CyjeI}mqZ^BrN#$PkJO6jQ#?+uOz2tG_Wjo1+|DwnFf8*bskBzT0 z^jb`p^L23@U+qr6^M8(CoS$rF>)*QEGa2m!wBIYYH~r4viJSFvo@I=euTtvPg7-&< m80AvCK*+Jx+yUnU0nkrlDpx$5Kw1 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 literal 0 HcmV?d00001 diff --git a/src/images/search_mail.png b/src/images/search_mail.png new file mode 100644 index 0000000000000000000000000000000000000000..7b38e9b40e3f57aeb8d27ac00f77cb1a3cc151c6 GIT binary patch literal 10555 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/!.png b/src/images/text_images/!.png new file mode 100644 index 0000000000000000000000000000000000000000..bac2f2461db6556140398a6cd73595b7e30d603a GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/0.png b/src/images/text_images/0.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8b63e3a79f5359fe81085211f5bd2cb84aa784 GIT binary patch literal 7321 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 SCbXY#0Ha%`H>-6WBmWD_4en|H literal 0 HcmV?d00001 diff --git a/src/images/text_images/2.png b/src/images/text_images/2.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf202e95b89b345d8363939a8ba195b05cfb542 GIT binary patch literal 6916 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 KMNUMnLSTX>U6tto literal 0 HcmV?d00001 diff --git a/src/images/text_images/3.png b/src/images/text_images/3.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d612dd8b00cd754006110d0365087fdb3b32a5 GIT binary patch literal 7265 zcmV-n9G>HeP)E13H#1cjT1HUub0L4>FkN>kcIEmTd~2t^f@+LRngSU5SjDM2Z0mJZqjWqQpKT@~6<2iwPpU-@<*oS|1trrJ;W+Lv1e7+2 z3uJr6v#xF32kKatm*}T#H@KEB#5W`yGUDz+z-WU|pp0V^bgEn#UR6e%geEWC#KxoN zP2~&o9z9z=ks$6WsSV;XII6t5I+_@K%Uvvp6*EBL;0WUSG>M_SLd&b1?QT(2-7uB6 z<#lC<-;hxGnoI{QBpkfg;rG-dGAfq6FeDQOu?bDsBMOAmlXjz5hCQibnba;@;ivE^9s)vszYP{Jz4E~+-L%kpBn#ptX-KLE1sn+^;X zK&))0y8xQvJ952&j_xKyAYFxZ15Di-VY|yv@e%o)YDINSCvv|;6-Vxa_&b{BJBCi# zC_{0O%6hC!a9w3B)5e`bb(;tEyPM!UjMjU;27r4EqpVusabk3Tigg369jAeOgP{zS z5pOFbV*OOqnBv8DHGCqT>%nT=cC>PYyxof>r%eW`sUFSFl>oHcHX?Ym&X6BchAg08 zk!9nO?+Wrcv0f^_u0FA>z$Y>v1*4T{jazsklJ26WsPYX4`FeEze>o2oKNwFZIzFP6 zXoUfXe(F>!#pP(@^M5b5u9ye^kTWhLB#u_RH_db63xz)BndDY zCCau$KB997YG94eq?d`B%LY5;DO0OeOk1AwU9m@0YN-g>d#7`Dw46^E18cH>9F;ti zE;g1P>u2sbugqjF-#^b**@dkIyf%lg_D%VQlq3Oq!Fhey4y@9T zb!|o7o*#|q7m)B%Uc6YmLb)B$P7(VjpEDW%uFe7R2}!D7;`yd|8&I!?&k9km_{3-Z zrWcTSd9$KRQMnF<5EbHWR^E_#4tduVV?N@4e%wPoNs=^9;-h|QJb1d0fY_)$a)XRb zN z0jj-sYnW~|c|*md0+`MV$J*f*CyL34Rq?hvNN7S4;RRlWME1sdG19p{N2C++Tveb1 z)923A1Rvo9Z&y=x@QlYn)NU@bUYv{@K{-Lr#TIRKY!_Y!Q~RN$RW_Xr+0cx0G!RIUxMxh9nGN1o&pj2px*r~N3!9m@fyy?lNvp;lso8TkDgmDKURDwitURzd#Nj-Amsg*%xqlC<> z@<-k~pHZ{K@u0>g^L-F%QmPtq9b~z2)5Lb=ZTl4(Z!0hn)xb2TT;m{x6@|KV_qL&{ zzbkN9&*O>jq*Fe6evZdIis;c|9rAya(L3A@INdE_~rB*1_%wNaV=F#!3v2V-dz+_rPNiSHxbRW$8g>o}i#L?dUU zn;J0f5T?#WApsWb1{^ULIAR{Ka2BxduE6|Vfmu5NLt>HHJ_f9NA6WYyux1PJ@&@3A zb->ECz_V`yW0Fch?W~cv=K=LxQhs5I7b>IYw`BrXfurXGzq=GTcS$M`E|@w6m^U;1 z1Ax;PO>&#J0l)kW@W89UUC#p>KJeD%2m)-sZ_pAT=wXR`Zv1@ioCsfW4ig`e5KdvK zP<-wf;LyFQZ*Th;aPKR?zy1n%@=f}h$bSCFlRTsNBmvmM>yu1j4xth+z9N%>U6yYe zhwTk~^^AH1gTno<0Dt?_R2?%dT9MCDOwPyinBpMb9H}ZtfG@sD{Mm89otHEx8~||I zBH*4&fj>MlO$Y2=4Ux~}6zA1IRgrjJ=PNcrtV8}k8kOgp#BcyycP4Q4iL|j@H>MAP zubc{e?X1*};i{<0#~*q9+-A%ol0F(umXvijlfcMo5v3-T<(tIcpAP)NAx-xpkBbfl zZa6O$T9q50qwl(FRi?%i; z3n~?B;*3rLT|3tmAvtm$aMg*;wC#cm4+gG0&Q68yE3dOffEWjH#`GcZ^|Ml!t`F=O z0k3TYHoTu+uU)4Bvu6N%?d+%it4{25lr=-d$oG1o-UHz~b5E>R7%8 zxa$Sr!PkJ7Hl*nnb{?jDov|~I7S=dAb)afG2vLb7C8S_;Isdw77iT}0RQ_k z@X1?&zq}XNvfaIoPah8KFYH1lFJzDT%;pf|AeNXj1GwZ+_i{Hc2R?Bt@Wh+N+Rcmu zfLm7p7yT#j))u#VhJ(~#=Ljth(KN5h6XPJ3xcCrYhQo_m#}eSGp8#LF57;(Vyj{wR zxN?|FUDYDA zaxL(854qJfeVE=%X;Xh+czKSFrzc7&RV<=V>CUxPNItv=uyl@n{u`eJ?s%?Tn>K#@ z??0Woh+S~*68rl5z?xPcj?+n*t(SoM^U2qNllHUE`|Zbo_X>EKWQaSr%7e!kaOd->y<>}=rvgj&u&=*Q zyp0W_tcX%?Y|Duqk&nyrb>Q&5?ec9M18(>l%tEAW$UlsP*HShUR;gQwArmg0DJ|M1kzx<6`*?BYVHGn?yqM@$5)kKscF^}t{ zJ-($ zvT=mA^OOxDBEA>P0GH_bMvt%Hk-aJMZx#71+uZ7Ycbi-NUFQMyT;g#Ma;le|fOV@w zO~Z$Kw+LK>7y#bfTunbZh$KD_V!&pH)p?4?7dMD{u+D>*BfV6x!*2tnVS+-u({5MS;lFA>;qc1_4kFBg~rN@?s+j=K9o2_ z)4VEAjDrLY)9=0JRKWIK>Ac(*!T(iE)q?LZ?DraTM^;h4yv*V0mh!+t%L) zUY?`!yc#Bn{vIsT4q@tC6p~^v`SCA41o-Qd?d#h<27KoU`}+ID1M0aH-;32U3W0M0xx6^;XEyVbS+{rp2*a{Z?E`@qLINXx(g9JCj3 z)?(m-gMmf67pv#mpQ*n@)wGcu5}#X?Y`j>$ppxRy;~-UF;VfYG^fa)@7_ie6V5ebv zZm*qz19k_N%mJ3owSN{xg&!=ZAL0r*4$(9(o-@WlbcJ0Yt7>u_qb%Ph{PEGir5~xj zod;e^?*gF4(pGcm3$L0-15TRUUAjsl!o#gAfGd7H>DHy}M-hGJ`GPBRLs>9Xm6k=- zx+D)P%k1`N3PP~iT{Q-J}hw*lMAo66O)gP5dL z%vXkw$YPHfz;{29M&C_qMbma!Q@ng$7MPlC5IQZNlQ|P_YTx7}Xp*l3pF0Nlr*qT$ zxMVv}-i0HNEWhyjYKJdL@}7da(x&#C;t$vz*n5}kxt)gTia%%k1D;Ff03X@|*nf9_ zFPr|+bHEqwNhb+o`AYfuKJlVQi$djYUfFKo5GNC#M7oKk<89jyg@0{h{vBGXL7F}U zj@bt|Wnuc~^8C4sPaXuUSPR_ntI1A@6J&DI^oKWX50&pAHl2u2L*9KB&rUz)bHPFB zdxKrEZ45Z$KY&-?q3h@8RJ(H@coDVQAl0?eJqc8K=w9BC-nxGBcY!b7mp(@8f@xEL z&mZrnk6i<0pVS%$p^km?aJ z`?GGU*0QJlX5VGXG`%!Po31aqcd_%xP}*cab+~Ahq6$MX5za zR4Uy$RePcHI>-W~O24qq&FwpXrd$18Oq&*{7zYUyHoGGQ9ssn#oEh%*cNw}kNaemD z7n{PB?_(T9&d0HO6I~yLIWyer?=nxsL0IMYVhsja8-l}^kZ@bXCw7?%TzwKj@Cz%n z_njx)CS}#w?C_PVSq|S{>?!-&bYA&t5MtAfh8egzBzT z9o}~kkZHBO6|EhR9Y{cogV22fuxg|6rvU)=oZ()-E$W!u7rw{72r zf8`y0IgTZB%D1n}lf8Z{^Pl4RgIG4mI}gnDca7Hw2Ll3nFBYwX>+4X}Yom6V_!VpP zc{mQ)OYbEq(!LDYM$x7Bb$CXEe_!3D{;s7dyF)~bgDCKnrGV@|D~(F~hRyCsVctyp zyz3qA0PX|g^B@lVD;w;;k^a&B-Rq~$i=dnoA}8kq(pyJnPP6MXkgAa`^>>|DJr7bT z+WI_50^sSl?DC%XA^+_c!Ep}Hc#I`se%?AX$O7Vhs@d2dWl)81a6GiiF5f8&C+}-2 z0`)H9c7ZNF#6IuxHEFyjViLllJ24_L4x-^7d`(|B$8Z4r(UJb!cZq{6n+u$~)ULk( z@blNR+)o;AItm)fEiPP z8-G829gr=aSpz)xwq5;Q=LzA+j7EGO#K7OS(*AdzumHH`)MD-HAPW#r@3Av*%Y|vX zF8G(n?CS4B+O$B$IEVp{zv1?*_h*&?*M6-0>q1QfchY|8XAX{>=T`5p*8~6kV!6I` z6)_G{kpJG(cE6G1)60OHFHD1WHuY0b?J)CZ0^dA4-8qT`D6jtoFgD7!Be&g0-X#v= z%?@d697Mz|D}c3@#yZD|3xNABOO1DzJ8V_hb7$bsPXHdc960}=Vs+gA3h?6>%J-$i z$jv0S@OrI!QmKN(4Q-$G0s2+BD1XIKz?V-c*00w$rVm!#_AK!3R=R#lOB@aooUnl5 zQ-=ZPEGZ{w>)!{?yea+2X9S6f4MZG^$^}H_t;%(T(Rpon$}?uuz6(EX2;BWCV5#Bm zT^+WM0Y6^_Jo?-8E$gc{0h>MmwvW=M`{vF})uzR>f#dfDj+zgr+t*bXCFv)j?|pgF z)yW}WyB_o8vRR9Os3vgLX;b^I{1J13A6=4u;;c=$=Kp|ydunoWg!Fxmrg>puBuCY> zX_uY~DwmpSWl#1Y!{o&h;ayo0Jw(3h z1FGLaWPS<*E;tzY!tua{G7v9*MewOX_l@$z9w~-l1*?|PqARsDlRjwnYRIGek zHtqZ7r?B+t!pjZ^j@<{9jhxj4&I+&;|wA4WN=V~i+}(HghbpWR02{} z+SGoP{G#1~GZzD=F9MF7Z}*l)6W-klJoX0g(CZ2Ad68k2^hU=J;|u}w44@Zd5v~FP zc-qC~m0A8h^2F2eRGp?a>*R+6;LyE*gZE5dG`Ck%D#R4|F$t; z<5uA9_kcB9(r3qCT%UeheWcl0DMX&+trh!P1Vr}(BJ{9PM!avT-fj7B;+X`=Ro>JlX5VGXEoQ%`+8m(m;F|=?u`vMr`bmvfc>W_S(S9 z$b0Q#+9Az!yu4t`i0{P;6gInKgkMw{2QlsxRn+;kTC+ID2(m<-ZSuta<+t?vxy%{#=+rrDpd+lOck!G&t>ME5w(skrPhY@ zUMxoCRh5@HoA%qr_dE{5>TaJJi@M_=CY}-JjOv!h_8Z}K$Sw-O#38EYS;h6|uCWRs zJ`ch;&+|(>WZt&@P!LAhvpaSO)?-~ILX3mh@C-nrD<9(^t>$xAtEv8l8V4cINj%?r z6Pf3>NJQ(B)Wow;`)ATXLXCsu&S`l5YZF~w+x~>W%gB4}T9ala%U7P37i<|J$3Yz0 zNB~Uu(t|VrU18c;0!C}cp{;QcBTvLZa=QwUUo~Vj#hZ3d9am!K_02N_-*o?se4FDS zN}k&)3NS$bVV?*uXx(mMi?+o4w6f}KzVPxY7iTqJmg0(Yiz%9zH$Mn>j$c~ zQU{(fmKPF_^;_+B0iiRtMH$p`tBDAc;aQe12`2po4bQt@JEKt>QG>Xm3eJXZ0au~7>?>`t~X8V v_o4GZjRFFgCq!Ak0Z<|kLJ#B4;0gZ^_aAN|l;Xdska~HD=JFHc@J{R!bF46hWh{6{|)|P$jijQ8a2N`m>^T zQ9{J16|wg}zyJPl-}`>L_ndRj^PKy>ahB%Btjv7OR8&-~CLjYV%KY=+!AMVeRytJW zQBhs%H8B9%K#>~{{rdflZDC6r5H+Mw*vi1`^kF-BhYCj1?0CH#J7&E^BTlX~Z1)Pg zdxZ^6ya-^HbjepK&HJ$60hg$f#QDu<%^(A~(bF5W+{!la_|oC}Oo8=+4b^k#Txi>G zzv_>Ubzb|kbqDCY#lA)_-Jr08{%psr2&IYBY(r-3(+e=a&hqdkQfa!4;1QbZEF`_v zDBQPptilzbe@Zo4YIp@BVbH{s#}cX6BLPW#zf{nY^GPQhxcHYpy74?;Y5KxkO{UZ6 z{A$MY^jqN|H z%Yj% z{@!Z>NhtVhRMwK7oZ$w86UhS~{T)C8&ehXfK8C?Ia?Lj*YEoT! zwzXEiSvG24sFtTfe7wNCH2f!sQooxjZI3Ek&fNdBcvKvF+^08pIGe;w(!Z46D&|QX zCATRH@BD=wCyT52YySKDB76|bhjzW6dkLH z#H~AzJK+x}>8Ht|n7>1#?GpJWigDT2@Z6pBH)Aqf@>_=ulcFLGqYQhq7^EP}a;4JE zpnaTMy4Ua-_FK>PM>GNcahS-CtF!%HBOjH#R5AvWnY$usa(CwD5*gF}<5>(zrGuew z`FlE;sNV+fqTa5!Z-qXaY+){QKpOYH+cMP98BEA~H(ExOFO$D6TUpLsU>SR}Y(CGb zAx&odALgFqvakdHLFN^E#lh>;k{?(rU&En>422KnQ{yp@gEe1sMWw&#t`Zb3hP9z^4Ui{gnCXY`&LlzmG%|M%W0o17_ zI`u#gbFq9vv$^S!1KKQlF}sP7@=1_4Almlv>2|gHBoJOG=7Nm z`#jloi7<-}ssH19{MOWz4wQS4RM@p)k)D2qe*vWl^3y9Qd0nQb_oLP}F}N6~VY!sTN4?WTO6*07#A`A`o}`kY|UbO_mubV%w!8qqnhPj zJ0hB_4ZDyt@elQ{@a+Lsn7xx|nghm97R7CszA%eg%zoZkt?!PqdKgSm-KdyfM z%`i4=Pq`v#aDd&=FX`>u(3f98Z^fG6-4b)=xlAx}fBvNO0V-@hBo-IQv|Q$0i9#U> zbRI=55N1zFri=qzf~(7bVDUG}Hm-v2rlA+ewj9*U`b?-HnsE~lN4*}=E@79)_bb>- znkasTkI@j{wI=Ii-2!9?_k%sX(OAaBU7N?FfaRvz$R>94oBH8prvfedWplmBeP}KI z(gJ?Hr|rvmPnAwYGa+m)za-K$84Ecl+mE~*g{AkT-Ywg`O+gIb67H=I4{0rYazyAr z++RKc%oJT#PS^ZdzdhPLNJO3aBC?nh-35x4Z2Sd0Yd+u1*lfL1u?JCR+t!+ml+4}v zg$`2KR5D23U;A|7!>@nXP}l+Obb_w!h-^svzz?gRERNPrGK0n#%yXrP6G`JXoekSC zA&ufnIu&dTqIV;odMG)Jw+`{zOp_<)P>weOgP0M57w#ER*>5nxdkETaD zugF%1e<;>_d{2YTY9N*G{Q}>q2)>Gkruqjkv(fFqHz8cIShxDC?!re+>D)Un{);tB z9Gc!0B2G%O@9lfzoYlJ%E|rW0^1V|6!%tOP3j;ow^~oysz2|4B1y?BwC{zZfY`e*m z2Eoxh&PpvUWH;!}&lg`gtZE%_V=05BDVO2sZ`EjOXxII&KD5W+YQZVf%NDxt)l0v- zB^+02op)&SF5xsA_nf4c;9_iFjgweE2d3OYerJTv`9+(Vv&&jM%_5Ssi8>|s)4WcQepzh-4p*d*f z!?>a@m$Lp3mDkjyS$i6L7w6i+w>BTHh3Y1Yu?+`q`ClA&&JXi3lqRUQUWO7ILe`L) zgF_k?%PR^$6j3<%o!41f4A8#5wXq2+WI>1!BTgIvzY|pr#qQgs70S5!Js6FlY}u|j zOYIy~<)1tHxHLRFYZCC(&^ZtJLO~ef+^Z-U(8P2&$n%qY-ch`>mOstt!nw7St|)c> zMaT3Mz6L4@5>{>X{E_K9(afhkUw0*js0w&_=N+)_-IpqioE0oiBwHHmT_h*> z9ibL>4Z&zaBL3PwE}R-V;kr1sRsD9RNqUZ`A9{!F7T0Xx+P+B1)jTM3(+LdUInp)d zWAer)^Td-&RH1eoYj52;C(TRAP15Z(VVLv6A#V!IP0| zKs@21Ra+>G$G$akeJNXsZq5W}crV_MBu|LHJ&g`leSHoiyWzDXZD*hK1-=~*jdWSv z0f=@{9gb;6mk)l~$&2J{I?=&PE4JRY$@srBH^Q>RxSmgkd~FH1kRk;nkJ*ZYt=yaz z&$Rd$KJqHUR7m3i8N{>qk(bU_gpZf4t9Gw0B~dtzs8iA+wP8D~#!AzmEa;t#nAdH8 zw~OSS=*EcpFa=_dMFHwxsW@6&kF|b+4&O{i`{id09@Nvp7Gd}V9_-fp8^U}H*Qw`D zZs5@_Qhi}tt~BiD_7_?q>Pt6lU5<3B15=nt%30L95jk>ObElG|R*UYPl2jc*i#J$a z1l$I5`(=QB%b|_N7J(;9RlCNv7JK)i->128QMm3fH)tOE>_ z(vjkq9o9W}6J;7A+9w_%YQ0(IAkK^*tfp_>;(r`^LE4JeJ+5N?kAc%2*R1|IB!e{*7aD8w0g0b2PP;xa!LFKQc0FdNY$E`y(1~By-S&L%h=k{F`5G+JA_}*9xlHl*M95iBzi@;Mk3a)?Hix7 zAJ#Hh?z)I0-X(Sw_ul7Zh&w|1v~t2sTb6Cx>*yM5XxejhX-{!ko#9C|?owas`!c(O zvg4EEo^j|5JPXyyTCmyHjP8&9GXC0!0PJ&Zq6r(rV=*3^S_8kX*GF-Y$jfu?2W zBhO#rkIe{=1z{58&c+!;yQ|pSsLY9A$S=Ci35XTHXNw9pU~y0N(p*rX+!li_%jtP> z@04tV_SGZ&`g;=s0O@24SH;$pU&2_PADczzqjMGYw@IP+9^L-ND`mP~kbc9}!Elh4 zty|?E=2&X%$!^D!E{jB~F67h=kNMHfYx{Mt!IR1Iq%SAY#`(O}y74|rNt9!Ayk72Q((^;{;)ln+kRv+#c7~340 zB^mPzu{&f?Ob>A#CMdC&ZYUY3QQ-~kFJ)2s55u=PHZ91j6QK%+TqQ{$lt+EO3Vlz( z2j*)2S7q^n>7x09PAKekvM6#lEF#=@Knd42aY>YKHO;&}cDjlNM)_#k!~{1j!|=(v zb=u|_rt!g(A+=b&T75aTTV>@F%0^>lPN%$qDXF<0_q*D@%}mwV<;B52{Cbvx>H%JT z$BKYUUDfm!@T7|L_EtAnQo#+-A>f|l4NvNMi+OV(p?V}b&vYL>NsW;52ZZc|h$5)Z ziT=xD5E&v4b|C+_? zLinKb++BUkB&(y=BVW8^46du~oaSpd8@u-R2<=q&WFMOf6c#AdMisuW^Cu{XFm_i@QJXmgTS%E$0P?z)xYI9^(+R@bzKex7klZOvMcUw^qb$hVS`>`TgQx8!jM!=$Lo zLSICxh6FX;f1n~Rac|uv9@3p-xMLn`QT9jxCaUohH zDYJdH^mH%DvDXqu$HCHYX$8H}V7aWydvCDL^mWl%~|Jh#w%Nl|Ctg znq~9}Gs8bQ^AtqkQL5_1o+NmU z-seCL%)OFZvb&nAtbi6mg+<8I>qsXs`0gwHKOtRvZ*Fv>J(z^`Wi0wyut549iHVeg&vJ!9RHrfQ~OMS=M~#ZU7C>01~X`rMV#N+X1yFBn9rj7oB?78izz zEz`mW;PIzoQfX5BC8$(Y{{>81%W%%Gc=hhoVkQMF=7VNzoU$_)MM!aU;b-_lxpL1A z;3PN3R6ch^oU%Jxo+^`z&4n`#&g*9pvsiTdtVJK{l_14-tuX1_CXi#_cyuUn93U_+ z=oL}s@z_Q%!n`t<9LhmJ&+z7HXOcSid3yW=#CmgR^B?M}UbBuAj>$N*3Xv^5lQ`o2 zo}kAS`1Tsqx*SI7PU;H)!L4h`Ri)2F=207sy*=baK?Vmvz&HoP>fMD@>AfeQY49bB zUk6h@-|ePcpR4zW)O`jT()b~;6`l~Sn>M+(1)RbaGpTzCVtfpa+5w#58T;S}MLS~< z1&Z;rD;Qs;wUuvVt)KXW|267urPY-ezR%3IFt?m%Ekk=vrd;_V@qrw-Lr!KK>i2Vl zyO3sOVD9PsH~;Aou6MjSs-hEfXsk&6p;l~QOP>YQ(q#%(9xi85njaY*KBi_IPtly> z{L4T6KM+<^OCHMaT#cyy<2&-DCj4c#!sJ!?HlDt_-bIzaK4h#X$-ahG^cW-raxeu@ zO*;I0W6$1tSlN6$;VTfMZ49Mc@q0DF2DNH(?xRj|aL_Mwi62K2DXC6pEbyI#F~Zsp z91pMQ=~t&gcHa}D4>SdViT1n9?fy1NEiN z{5~$dguoQ-t>G(qQ?|eM!99-xA@soSnOt?ft~}{q3hu*S zYED;tzCW_A7hw3uyX(^A$#Bjcs-V;}=EvB6yxs!n(M{@MR5^$+oAn(fkQaGc8XR zgWCo^v^QCkXdnCA2QUYPjs3iI+y10*TPe{Wp6CYYCNDk*C~Q*`%eM=F$WU^Pa0jyH z?Dx?xI?pm;-YL`DP>*}AAenK+sSUnP-=_(j_g<98C8y6j_VRS5w0(IH3RyebZ??rX zhdy%W_FGG1)kQz(JppY??in7HFiS`&E_qFvWV_NXVLhWeYvH&NXnpzu}IgVJ*oKwaWCM7e{4I>$Fm^c{zi0QPU-=G4a9s7UkzQm5HIbL6zR4 G*Z%=iy(X9uo@miUnM4`Amk2@hUIvNiMj1jx3DHGo zj1k=o(c|+x?|Rqwt@Zsl`~28v?S1X*zSn(S_dc@RfL2#W)A;87{ojXz z{AR4Ntjz-eIQ(=q)lCC(c5Pl&bM?W4HwbmKv(^ce>`b2-c_>laok`5Rjl*NhElf}nHNX0!n{-dEjodW&sC?cDGF*`m%KP^?KnWK ze8wRPpE8Ul#5_&;*;IF*7>U@M&?}$K)iTuorAzVuNS+yA7iZ$@xqWO_?AmUb=_bZ& zX5kAosM6xX{tAo^GyWato#W3={D`v`*w(@HY{uavRG|rb_q=kRwiC;Fs7x81)Q)2C zoa12;!pxFo-)HN|9;|r(6B}u@5U|sZ4767%aum5owQf_|pdLuxpEhHz%^g0v(3ff{ z!OTJzD^P2YpE+US6qJtHyQMcpYXKMY5P5hR6*f5IsPKaKT}p?3S2?4RQQc{ep(sbM z*wKq*_7r`CsKhME9bML;Qa`WAVrs)$o2(B_kqknvU1Pqqa~r^fF(j-cyE)OUt7brr z63Kybnn%-Nr;ZR3&%=X>O&8_(*+mhSzpVXTMvrS(|9ZeP5CKXB4jS zpUY3gZDola1y|lrS^^&XAN@$CDgI)#F{w^(TEwnpnLbI#eFnS;cM-}^Al~txJpwWgJR)KS{mElq#m)98E>l>dC zBbhQweu=vem~+d1r$p}febgvQ)E4&67h}9fbuQlsz28-%(pcTYrjSo&pTeGC6(Eti zS6r5f*SmN8#`SNAGCixRr4E~{%FSd1k%w7bpkU#r?HSW9zfSY*1bEoDq!R7Ve)UCE zk9||&Zj1rx&3)=1xyQE#CHgooawQ-FsO;g^d+aCXX~vBomwLamiiW>{GSgi_?9+5c zWWCbcNtN9t}256VjuKr_lwjrcT zyb~pnK1#mj#?JwR1lYr28QxXxzx@p}dGi`{?V3HZEgrGP<8>+xJ9G$y;4z=~&tI*B9CHXr1P8q8zE{1eOneSa}6BT0Ms2FehE^B~)YCcPcaa9L6=u z17p#;Ef{O0D#InYsG|m{N?s~pFc~NhsCsX`G`(ktZoP+}6>yUJ#-=8d$^Kk5a^+4$ zFq*wV$Jyu(`xAH6|Jaf_7y`#laJj^A`I{tyT zuPgTwxy40giJojO-Qv&T_D5hL4ZZCQ_#}phKZuu1_@6;F3ux8KM~Xt{JN7Z*E$t%m zdS&rNKP{ZQ&IQ(wJ*w>}C9X_FCX*{0M7oq5nMt!dB$^;Gl(qOQdQ2z){6TB+g|No? z`ivrSW`FIN;8x+|Mqrv;D?kFhX(VA7w*0$?4-68`b|5;u6J?aOeumL*fpN<|6_J;S@^`vq>=YX_5F%k%Z%eJQ8gi@Xk?61z+vGVSGO zM@{ldrAeC$45tYdmJ3?#RIF2Wb!$A4ox~qsx7GeMwRsXb8biE~TzCnJxGNww6;}MF z;!%dd|79T18oFVWY~QO+CHzmCLW!)4#9sLLo34sWEhAe=MqT`tJbVXVyDqJ0^Q^V? zV`BT?La!7p)K`ZP!||;z7DDqqy@YcYbM1?bY(5$7hdoO2CXk1A3+k@#J=Ak0g7Hst zXT?rR16LbkPrN8Es+=lITXWWL+o!>?EDgE6rcmY4V7QF$&RpK4e&!YxcFJeVePeFS zcui_N(hKNCW4lWt+k|gptl1YWR4V6AGekvnK7nGb$^Y5lB#xVO>^N17WU#@?mA9!#FKKkgn#}o0`kbT5zsLHca zTSci+GSf9J4Q}#xSQ{te@EPn!@TmcgO;%Ox{l%Zr|OPzciO(-h0iuWWv_ zYr`oId#hROP=ey{+-0a8`4N_KdDI+QO!phbrnK;v)N}F5m#yW2zPKNk_-LuF4(My7 z={?VEi1(Ri1pim=={uSnILTf6@ZLC|mebD2gLSj3re&6({vf6`YTl~RPso>v+&{-e z*7D>IZTi&PzO@yf@2Rt&%ch#F`4%$u+yTaJ=rrnj(R6~V6~F9rNk8n_n^8G^tnUkj zhxAVP8$Wg~`Md2Vy?Svg^?mYI^HrI6tE^+X9CpAfMXg%7YM(2D_bzKWJ@f~L6Da(+ zRtzMWi{bg&tj?5d(l8=Is3`cSyTtBY9`ar;XMGB&4rD1~$ma3bE2a}}`wooQLc+a4 z0)U5&s*vK-O4rV@bvOk9V`*v;N)41P$NhVO3tEB^*Jnvvt(}SM zX#qA)PodRLb@V3MlRi!A$Ez0ri@rBIzAH;?i)VqPh(XRlx!s}fr+wcQQZPK~D|vST~g>o!NFj`4YeN_eNa28L!#JB*KQ z-vhw}dAgnr6#0pIB?HNw&E=TfyHGZcn~;Pza2S35m+@Dg`6QGQKiz)%pA7e7%pNNL zyXGB|UtH7r_r1dE2xUt0bmM?%Ffd6aEyLg5ye@TPN+}1TQ)+l-!A6&rHwB3qwP`Pu z)mi@c>vPZ)&MYZh8Zh%0B2M34hkV8<+(-Fsgk+;t0K>CxN}r1mu6XE%colLp$C8@R zUG&{6g?tmwRh{-PDLxEZ4G`+wEuX}i}!2nff-Idz^rV*P(}-( z6r|0r@M#1I0v`4bzC^o}#m}&iJZmF`TnDVQ%b=h2e`u}&b$to!-(ToSH3Q7na|gTy zAK>TF@$(2=^9OpEGKwsv*}s(OW*Lvc_ZXhM1MkDV94=}Aw=!kRmaFZRf^DDi+h;^8 zpG&dJl+h$?c@XRpobB|l2s#K%bkYvkk+-cBmtZYV(1p8fo``%}mVm6wM;9i)@6r#E4COJSx1sswu@ zZFuWkDG#vpBqvbn98{T-BOWkF$O2z)`&0>up4k0n&2nYXmv7`h_Yzu`iNd#ro0t>% zTN4GYTEFf5FXz1MOv;nqnjPWu_|k}b-7Rj$5!d9ai|*ivz)Qf)Z2+?^9SLzB3v}&`z}Y%_OFqQc z54RxhrRX{SP@m}o{u43l0KS8a3}V<{gSp?5L(a^&gpz(hvsB%w>=tPc**ZG#_EqP8 zq$E?PFMX~7g%RVlR1%R2oXQiMg?^h%vHdk_A`}QC>pbpl2u7H{a7?!tYeSeWI!w%) zN5z!Me*Y766G7r;RZ7=I8!TjI{nrDuRCZ`rFh$EwgX9RK9sSiWE%XVLIQUSXpx{83 z`=%~}LI0wR(xbjmNUm{DV*}r*_&pT9vYkxK7R=mo_O8;i!dL&^F*ovJ?d7?x(W4=7 zEA44KaL6f$8Pvpb8cw}+jGD`5g=%dR_vA+4t(ljm{Y0xRsX&<3wIFBC&#T;_oY$PQ zt>E^c<7QAM&^@@Ny6g9=$XW<9#K>sII8OWZ0BX?pOL$9(=?}J^X3G3UOlTrHY9C6)>$-k?+am?_$m!x-?3q(m^FB%K+03~9VPCpqI+3Q;Rqdbt{^G&>qba``Y>_zd z<(xih?qoIDhA8KC1nQF6gZP5(BfLt9ZM>kI=HlNB3z@#kiA@^nB2hYTL;bD8S82y< zY(qsC-BSz&<8w5dVjVH9yU_<8ohF@?i{?>G0Qajhbz`8XLPgQHt`^#s-yw)?6&DYK z{&QawqPi(n^QA^LUzhOHD$~ij?VQSvNjT?gUa8WqGm{nH(G$q zI&a-x|J3RCqysx_LunN+i5}LLyPT`=;#B<&LaFItV)S&p6=o9Bc|(1 zX`6gXBz;YnBhJX614%+A0!1#>}6xE#c?kw_xV|)ge#YhwU{4PwXoD zs~QGc-%_Va84p5`W zOK5bPj_3IN^6@9tk`CVTV=^o4q;LVMkv*p##eHG|SH?dff1@Y?b1Lr?V*qp4gAYp0 z`&LRNke{d&jIlv}+PPBc$G4xJ@d5MC`@b`LF^sjv$z=Ux=ARUwaeJ3=KL+(#>|15AwVVsSy3PGcElt|r*OmQg4=%X9nu!2% zN`On(SA;)5P%&?6oK(9;x~`Q2V@>llpB};!o8a-D6g>Uv)t7}n=)PCG@Vmj-^-4rU z)2FX9qah<+mu>lhQZ+4_GtM)_=@_0{J9vtgptZCXHxqJxHg2o_(Tn$T9~&het>e^{ z;Q8eQmDiU?KLk5>O$u^Y?w8}H$^P9l+^jEBaUed80@8P%`)ooI`Ehd(=XN{+f-jXd-NLi`>wuMyX?38Y!tirT<$@ zEGL!P6}_o zy6NTawfX)V>{>%{XvnqiO4M;_h6t(8`|a#b8KZEkhB{`z%4|EPfZ!c4DD};`i!$Wue7uw+j2JzU9m?H7rSzq8A!})l zWM__EG#7xR6ZT+}zpz~4-zQNC4C}gIYCl1@G9Ci(+d~F(sCD_Bmy5+N6klnYp4!6&+rW~rWDvjNUGQuC!g5uEñU+Fza+h~R5vpg8_LIVMa5TU~B_MS$~w*1qN_?($zvY%RD*Nq|uP0|UrN3ZDTv z(Cn0g;-{LQ^BS>jY4`1M5HHP6Ai!^+sq;2jK*Gn8a7 zzT6~1N?@280ZlMFrJ`Waof@}*UY%?*kA5@pZJXQqm`|}XX@<_)7w!^8IlMeO9Olo+ zV0+yuL}t4miuV{LTG{Qu$^l`Ebgm0TN?oi0C$^1H9KbPe?N?k-FxXuCvYR--{nZ(c zBtzlj#0%$)xT)TF>`QahJrkPs{qTPR&;e#{%RuKlypLMqGrUsL%tSf&>lL@GH%GG1 zeoL?d2bO^Y-#-^P7o;fPZ54T8lAsP5RvbAs?azCW`ylOk_Hul>`2Gd7dN}%U(lUaA z;_a?q4Zd*8oO9QIVBXM%W&G`@NkjnSc88^kCtZiim~Zn(ckAsYvgrRuLR1N^(9D1g za;C33YzXCm?{yC~Iv5xJM4`7U-tKzO@jq~F@3h^%DFTmKauy}{#pV*iA^wauF30kB zdTFe{|&MDJ_KWO$Ar9e`rECPIYWy@Pv1iELwx4f z`IW)$X59 znGE zE%w_++WE$>P=Q>U6=HH>g30nq^;g}8@^p6C$ncZee2)0qn@;|5U_~2tEI75Dc1nvk z7V?m)J;to-<`mpFZJ_@Xxmw@(u&+Mz2IKw3$|Ao65tFN75{L17F_(K8yEjQ_L7;6^CIp1+!zjbOy>nX=yemXP$m-BmEeEl91hv4;Bl zWuTEnFAf*qXU_(nkcIkUbWN|8Si|dN3rx>U1Mbrqk50(LT9YXMjAmyPd@CZ6`{X2V z<1ukh9M8g{{(F9ETVok2;}-fGc{Lrt`MgkaUJ|S`!q*_@~*%Dm^i4oUhTzvH}{>Kslsk5Bw;$wbBmsl z#^AVNI=l1uViI2Pkceo3nJ;ahD2<}z=ht>A&7NzLIneY%p=w>=&5tO6u9m)Lt%hyb F{{ionjlKW? literal 0 HcmV?d00001 diff --git a/src/images/text_images/6.png b/src/images/text_images/6.png new file mode 100644 index 0000000000000000000000000000000000000000..e385a954ba4c14f366fe1ce4c8c848d5351207d3 GIT binary patch literal 7644 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 E2Ua8%FaQ7m literal 0 HcmV?d00001 diff --git a/src/images/text_images/7.png b/src/images/text_images/7.png new file mode 100644 index 0000000000000000000000000000000000000000..55fc4f77d428bb159e85a6516fc53ddea20c8c3a GIT binary patch literal 5941 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 T^j#y4E-5M%r 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
9bJgQ-Ljsc4!hN#4Mp>G*UQYj3!kCc~qfu4eYEW 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 Date: Wed, 17 Jul 2019 14:20:27 +0530 Subject: [PATCH 101/306] kivy toolbar title updated with new ehancements --- src/bitmessagekivy/main.kv | 198 ++++++++++++++++++++++------- src/bitmessagekivy/mpybit.py | 233 ++++++++++++++++++++++++++++++++--- src/images/down-arrow.png | Bin 0 -> 2384 bytes src/images/right-arrow.png | Bin 0 -> 3145 bytes src/state.py | 6 +- 5 files changed, 371 insertions(+), 66 deletions(-) create mode 100644 src/images/down-arrow.png create mode 100644 src/images/right-arrow.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 562e9f98..7d1d380f 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,3 +1,4 @@ + #:import Toolbar kivymd.toolbar.Toolbar #:import ThemeManager kivymd.theming.ThemeManager #:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer @@ -34,6 +35,7 @@ #:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory +#:import MDTextButton kivymd.button.MDTextButton #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -67,6 +69,7 @@ values: app.variable_1 on_text:app.getCurrentAccountData(self.text) on_press: app.limit_spinner() + ArrowImg: NavigationDrawerIconButton: id: inbox_cnt icon: 'email-open' @@ -80,10 +83,11 @@ on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: app.mail_count(self.text) NavigationDrawerIconButton: + id: draft_cnt icon: 'message-draw' text: "Draft" - on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "99+" + on_release: app.root.ids.scr_mngr.current = 'draft' + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: text: "Starred" icon:'star' @@ -147,6 +151,7 @@ NavigationLayout: orientation: 'vertical' Toolbar: id: toolbar + title: app.current_address_label() opacity: 1 if app.addressexist() else 0 disabled: False if app.addressexist() else True md_bg_color: app.theme_cls.primary_color @@ -197,6 +202,9 @@ NavigationLayout: id:sc14 ShowQRCode: id:sc15 + Draft: + id:sc16 + : name: 'inbox' @@ -225,9 +233,12 @@ NavigationLayout: : name: 'draft' - Label: - text:"I have a good dialox box" - color: 0,0,0,1 + ScrollView: + do_scroll_x: False + MDList: + id: ml + ComposerButton: + : name: 'test' Label: @@ -258,8 +269,10 @@ NavigationLayout: hint_text: 'type or select sender address' size_hint_y: None height: 100 + font_size: '13sp' multiline: False required: True + allow_copy: True helper_text_mode: "on_error" BoxLayout: @@ -269,9 +282,13 @@ NavigationLayout: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 - on_text: ti.text = self.text + on_text: ti.text = self.text if self.text != 'Select' else '' option_cls: Factory.get("MySpinnerOption") + background_color: color_button if self.state == 'normal' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/spinner' + color: color_font font_size: '12.5sp' + ArrowImg: BoxLayout: orientation: 'vertical' @@ -282,6 +299,7 @@ NavigationLayout: MyTextInput: id: txt_input size_hint_y: None + font_size: '13sp' height: 100 hint_text: 'type or search recipients address starting with BM-' RV: @@ -291,6 +309,7 @@ NavigationLayout: hint_text: 'subject' required: True height: 100 + font_size: '13sp' size_hint_y: None multiline: False helper_text_mode: "on_error" @@ -300,6 +319,7 @@ NavigationLayout: multiline: True hint_text: 'body' size_hint_y: None + font_size: '13sp' required: True helper_text_mode: "on_error" BoxLayout: @@ -308,14 +328,24 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'send' on_press: root.send() + MDLabel: + font_style: 'Title' + text: 'send' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' AnchorLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'reset' - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: app.root.ids.scr_mngr.current = 'random' + MDLabel: + font_style: 'Title' + text: 'reset' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : readonly: False @@ -357,7 +387,8 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(700) + height: dp(750) + padding: dp(10) BoxLayout: MDLabel: font_style: 'Body1' @@ -404,9 +435,15 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .5 - text: 'proceed' + size_hint: .5, .35 + height: dp(40) on_press: app.root.ids.scr_mngr.current = 'random' + MDLabel: + font_style: 'Title' + text: 'proceed' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'random' @@ -415,8 +452,8 @@ NavigationLayout: orientation: 'vertical' size_hint_y: None height: self.minimum_height - padding: dp(48) - spacing: 200 + padding: dp(20) + spacing: 100 MDLabel: font_style: 'Body1' theme_text_color: 'Primary' @@ -439,13 +476,19 @@ NavigationLayout: hint_text: "Label" required: True helper_text_mode: "on_error" - MDRaisedButton: - text: 'next' - size_hint_y: 0.13 - size_hint_x: 0.8 - pos_hint: {'x': .1, 'y': 0.3} - opposite_colors: True - on_release: root.generateaddress() + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .5, None + height: dp(40) + on_release: root.generateaddress() + opposite_colors: True + MDLabel: + font_style: 'Title' + text: 'next' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'add_sucess' @@ -466,25 +509,40 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Server ' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Server' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "DATA SETTINGS" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Import or export data' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Import or export data' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "OTHER SETTINGS" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Restart background service' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Restart background service' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' BoxLayout: AnchorLayout: MDLabel: @@ -549,7 +607,7 @@ NavigationLayout: orientation: 'vertical' MDTextField: id: label - multiline: True + multiline: False hint_text: "Label" required: True helper_text_mode: "on_error" @@ -612,8 +670,14 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .5 - text: root.text_variable_1 + size_hint: .6, .35 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_1 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' MDTab: name: 'processes' text: 'Processes' @@ -628,30 +692,53 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_2 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_2 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "Brodcast" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_3 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_3 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "publickeys" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_4 - + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_4 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "objects" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_5 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_5 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'mailDetail' @@ -689,17 +776,27 @@ NavigationLayout: halign: 'left' bold: True BoxLayout: - spacing:50 + spacing:20 MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Reply' if root.page_type == 'inbox' else 'Copy' on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() + MDLabel: + font_style: 'Title' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Delete' on_press: root.delete_mail() + MDLabel: + font_style: 'Title' + text: 'Delete' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : size_hint_y: None @@ -715,7 +812,7 @@ NavigationLayout: elevation_normal: 8 md_bg_color: [0.941, 0, 0,1] on_press: app.root.ids.scr_mngr.current = 'create' - on_release: app.clear_composer() + on_press: app.clear_composer() : id: myadd_popup @@ -871,4 +968,11 @@ NavigationLayout: name: 'showqrcode' BoxLayout: orientation: 'vertical' - id: qr \ No newline at end of file + id: qr + + +: + source: './images/down-arrow.png' if self.parent.is_open == True else './images/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 \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 851375a1..b122791f 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -47,7 +47,6 @@ import kivy_helper_search from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel -from kivy.garden.qrcode import QRCodeWidget from kivy.utils import platform @@ -101,7 +100,8 @@ class Inbox(Screen): carousel.data_index = 0 carousel.min_move = 0.2 del_btn = Button(text='Delete') - del_btn.background_color = (1, 0, 0, .5) + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) @@ -135,8 +135,13 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing""" - state.navigation_drawer_obj = self.parent.parent.parent.parent.children[2].children[0].children[0].children[0].children sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + if int(state.inbox_count) > 0: + msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.inbox_count = str(int(state.inbox_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -208,7 +213,22 @@ class AddressBook(Screen): meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) - self.ids.ml.add_widget(meny) + # self.ids.ml.add_widget(meny) + carousel = Carousel(direction='right') + if platform == 'android': + carousel.height = 140 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete_address, item[1])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index=1 + self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -228,6 +248,12 @@ class AddressBook(Screen): p.open() p.set_addbook_data(address, label) + def delete_address(self, address, instance, *args): + """Delete inbox mail from inbox listing""" + self.ids.ml.remove_widget(instance.parent.parent) + sqlExecute("DELETE FROM addressbook WHERE address = '{}';".format(address)) + + class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): ''' Adds selection and focus behaviour to the view. ''' @@ -491,7 +517,6 @@ class Sent(Screen): xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - state.totalSentMail = len(queryreturn) if state.msg_counter_objs and state.association == state.check_sent_acc: state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(int(state.sent_count) + 1) @@ -513,7 +538,8 @@ class Sent(Screen): carousel.data_index = 0 carousel.min_move = 0.2 del_btn = Button(text='Delete') - del_btn.background_color = (1, 0, 0, .5) + del_btn.background_normal = '' + del_btn.background_color = (1.0, 0.0, 0.0, 1.0) del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) @@ -628,9 +654,9 @@ class NavigateApp(App): obj_1 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - total_sentmail = str(state.totalSentMail) state.screen_density = Window.size title = "PyBitmessage" + imgstatus = False count = 0 menu_items = [ {'viewclass': 'MDMenuItem', @@ -692,24 +718,30 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" + address_label = self.current_address_label(BMConfigParser().get(text, 'label')) + self.root_window.children[1].ids.toolbar.title = address_label state.association = text self.root.ids.sc1.clear_widgets() self.root.ids.sc4.clear_widgets() self.root.ids.sc5.clear_widgets() + self.root.ids.sc16.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) + self.root.ids.sc16.add_widget(Draft()) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = self.root_window.children[1].children[2].children[0].ids state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format(state.association))[0][0]) state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format(state.association))[0][0]) state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'draft' ;".format(state.association))[0][0]) if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count msg_counter_objs.inbox_cnt.badge_text = state.inbox_count msg_counter_objs.trash_cnt.badge_text = state.trash_count + msg_counter_objs.draft_cnt.badge_text = state.draft_count def getInboxMessageDetail(self, instance): @@ -748,17 +780,33 @@ class NavigateApp(App): spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 def on_key(self, window, key, *args): + """This method is used for going on previous screen""" if key == 27: # the esc key - if self.root.ids.scr_mngr.current_screen.name == "mailDetail": - self.root.ids.scr_mngr.current = 'sent' + if self.root.ids.scr_mngr.current == "mailDetail": + self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' # this is for direction of the screen comesup - # self.root.ids.scr_mngr.transition.direction = 'right' - return True - elif self.root.ids.scr_mngr.current_screen.name == "create": + elif self.root.ids.scr_mngr.current == "create": + composer_objs = self.root + from_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.ti.text) + to_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) + if from_addr and to_addr: + Draft().draft_msg(composer_objs) + # self.root.ids.scr_mngr.current self.root.ids.scr_mngr.current = 'inbox' - return True + elif self.root.ids.scr_mngr.current == "showqrcode": + self.root.ids.scr_mngr.current = 'myaddress' + elif self.root.ids.scr_mngr.current == "random": + self.root.ids.scr_mngr.current = 'login' else: - return True + 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.restart) + return True + + def restart(self, *args): + """this method is used to set transition direction""" + self.root.ids.scr_mngr.transition.direction = 'left' + self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) def status_dispatching(self, data): ackData, message = data @@ -769,7 +817,7 @@ class NavigateApp(App): """if slow down the nwe will make new composer edit screen""" composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' - composer_obj.btn.text = '' + composer_obj.btn.text = 'Select' composer_obj.txt_input.text = '' composer_obj.subject.text = '' @@ -792,6 +840,19 @@ class NavigateApp(App): elif text == 'Trash': state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) return state.trash_count + elif text == 'Draft': + state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.draft_count + + def current_address_label(self, current_address = None): + if BMConfigParser().addresses() or current_address: + if current_address: + first_name = current_address + else: + first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') + f_name = first_name.split() + return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] + return '' class GrashofPopup(Popup): @@ -805,6 +866,15 @@ class GrashofPopup(Popup): self.size_hint_x = 0.7 def savecontact(self): + my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + entered_text = str(self.ids.label.text) + if entered_text in my_addresses: + self.ids.label.focus = True + self.ids.label.helper_text = 'Please Enter corrent address' + elif entered_text == '': + self.ids.label.focus = True + self.ids.label.helper_text = 'This field is required' + label = self.ids.label.text address = self.ids.address.text if label and address: @@ -904,16 +974,23 @@ class MailDetail(Screen): self.status = data[0][4] def delete_mail(self): + msg_count_objs =self.parent.parent.parent.parent.parent.children[2].children[0].ids if state.detailPageType == 'sent': sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' elif state.detailPageType == 'inbox': sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(state.sentMailTime)) + msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) self.parent.parent.screens[0].clear_widgets() self.parent.parent.screens[0].add_widget(Inbox()) self.parent.parent.current = 'inbox' + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) @@ -1006,4 +1083,128 @@ class ShowQRCode(Screen): def qrdisplay(self): self.ids.qr.clear_widgets() - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) \ No newline at end of file + if platform == 'android': + from kivy.garden.qrcode import QRCodeWidget + self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) + + +class Draft(Screen): + """Draft screen is used to show the list of draft messages.""" + data = ListProperty() + + def __init__(self, *args, **kwargs): + super(Draft, self).__init__(*args, **kwargs) + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[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.""" + account = state.association + self.loadSent(account, 'All', '') + + def loadSent(self, account, where="", what=""): + """Load draft list for Draft messages.""" + xAddress = 'fromaddress' + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "draft", where, what, False) + if state.msg_counter_objs: + state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) + + if queryreturn: + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + self.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, 'lastactiontime': mail[6]}) + for item in self.data: + meny = TwoLineAvatarIconListItem(text='Draft', secondary_text=item['text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + # wimg = Image(source='/home/cis/transparent1.png', size= (10, 10)) + # meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) + carousel = Carousel(direction='right') + # carousel = MDCardPost(text_post='Card with text',swipe=True, callback=callback) + if platform == 'android': + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.bind(on_press=partial(self.delete_draft, item['lastactiontime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index=1 + self.ids.ml.add_widget(carousel) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def delete_draft(self, data_index, instance, *args): + """This method is used to delete draft message permanently""" + sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) + try: + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + except Exception as e: + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + if int(state.draft_count) > 0: + msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) + state.draft_count = str(int(state.draft_count) - 1) + self.ids.ml.remove_widget(instance.parent.parent) + + def draft_msg(self, src_object): + """This method is used for saving draft mails""" + composer_object = src_object.children[1].children[0].children[0].children[0].children[0].ids + fromAddress = str(composer_object.ti.text) + toAddress = str(composer_object.txt_input.text) + subject = str(composer_object.subject.text) + message = str(composer_object.body.text) + encoding = 3 + sendMessageToPeople = True + if sendMessageToPeople: + from addresses import decodeAddress + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress) + from addresses import * + toAddress = addBMIfNotPresent(toAddress) + statusIconColor = 'red' + stealthLevel = BMConfigParser().safeGetInt( + 'bitmessagesettings', 'ackstealthlevel') + from helper_ackPayload import genAckPayload + ackdata = genAckPayload(streamNumber, stealthLevel) + t = () + sqlExecute( + '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'draft', + encoding, + BMConfigParser().getint('bitmessagesettings', 'ttl')) + + state.msg_counter_objs = src_object.children[2].children[0].ids + state.draft_count = str(int(state.draft_count) + 1) + src_object.ids.sc16.clear_widgets() + src_object.ids.sc16.add_widget(Draft()) + return \ No newline at end of file diff --git a/src/images/down-arrow.png b/src/images/down-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3e864c8093738d0ab553d60af018d11f9a2ebb GIT binary patch literal 2384 zcmcImX;_l!8h()xN+DWYQtIH)Ch3T$CarTC#Thega!n1VQgTa2##|~)ktNG_lwLKnj9wHj(X*Q9KkO6;uM?Y zxf)s?kX)88LBQD*m*ptLsRtCECkkQp06Hx}6hPQ&6oh@WkWs|dD6L%J_%}y2SNL3( zC%yC9#7LkwwvA)8wL-o6AICy;_;?Jtei{a>fh!=vfDH%(EGu9Kc;J71B8&c7x(27$ zw}a^MOag1Gq4spqb%In^lQ$!>8rK;)-;@`*UszO$muJp$Vb#8~ME}I$g}dtbwog*< zHu8tjB;9HJmhVksbwt|?2BwHMAtgznoADLDwJq#_U&OS{;J6`~?4oI|L?d)%+2n3w6OC5V+6P+*{gGESC8e7e$U8rncC$ z{f?CRmKRYu>UUhUBFL7a9$6&&4+YCUe1o-rO4>GzF1lSM(HpL6oSQC+VdXkau0-JYa^!t4ak7*bQ>E@vtC z)_Vr?>;_v35wcay3DOzT+z)}rKOasaD;wx5Z6)WOtiy);O#EHWz2oH{J(BH7qv<3i zckew#+&UpBAqss@mMeFjdqndTgOWy}1Xj+cy^lt)jBVSA*5>LC|w+Qyp?WPcXHQjkm9WJsCqgNZzCDhAA{GxHb46?cM7PyWZyS7yoa5tO#y}76(3S87Pn@3yX@nOKQmQSsA-e?yn>~>P1)DM ziLfCUo9%m{K@9;^gnEpZO zTW>=Nm_jHUP(llLy*D(!HP4|Yc-VKG8b)_rL*20eiO>LAEXltf@zbqxO?Aq$*gBiT zS#asmoOCX*42rj63h}zK4*Gxjm=|T)qv;eh0bAGEIGesXpY?>ZGN)Eg?dc;_@nRX) z8F(5zA$gmnLn$u>8Qz`|J%1e0Gf(T+^dnOS$C|e6{I=)G_)HhG_6o;`^nMsUT@&>= z3*5U?PHH4n)ykxy1O3Pkk0u4&gR&iZ{9^xYT>HQ)!`g8TqTd*m&%3v*>gwL6bMA-VeHm(aJ}VBISwUa8gb;=UE?S-C~{^N(?7R&YG&Vzh8QDOVJ3f zDAOq>vmn@zc>f4AlzGgJn*}^bQ6y0aC>Uw3}7DY1sDu6dGJ-z*hQzr_N($yc5Fx_y4LEvzsS! zuCk>otY6$n`?tF1;|+w5uN_IBYe~qSh7AtZ+|v`c>9MnIVW6}1fYxE-*kL$#l?{db zl>$AeR_~n$)G=|eqRV=p*J`QPM;Q+k?q~G+$W-kI*GnHVn3wvIl(ZYeW-fUisFZZ& zTQn#5aVeU<%$4Ogk#0f9R|kz;J%JFEVR6ILes$JBCSaR!jw6Jdp<}$zVU<@ z>snP9O-Ekz0i~Rdfd;AeqXt9F2M*zR-V_OQ17z>-j`2dM6X7Y3Y3AdnmD^L3TBs{y z(Qs<#f#g=8|scm7i6~YUrf|f_8=Y-~5(x>c0{SPHX@G literal 0 HcmV?d00001 diff --git a/src/images/right-arrow.png b/src/images/right-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..8f136a774a2f1d83fc4c367a4c49d32da82eec49 GIT binary patch literal 3145 zcmYjU2~?BE7XA~AY?5H5Y&H<#v8hN{3TQ>ZB7#IvP!?HCgh!!LMdS$@AOUQsHE4rc zgIh|4*cKNMEK-F8qY;XVB^7KyLMoQ#P)JzHCXn8V`rbPyoSA>-&b{CL?lQx%ZQ+|u zjI50?3^NH035vup987VT!D1K^vc5~juqCFUL4iAR<--@3{wjQB&MDT@(=X}|FkPfy zM6om|qM+a6B08O75WK5J4C^iM7pVK`wG`4N;zEkA>7v(j5!a%(KAzLQE>OJgohne| zC+Pc!6Xzu&EOB_R1m)9Au33 zw-aeq(BI<8qj58jeW4mP6SteyDq9357~LCK?0 z6D`@6F6>b0SWeo%X(hW|HTeuZa8ml^=08(uB?@QFMP`+DxF{7Q8i34D5Q( zi*V*BRu^7>c?fc$5;N85GlFGZB8GD8t@f2}GBW2{Tq22pUIzpq>gVQHIC;3F|` zGIIq;aQbgEta!ANurxTksKlh*N~W~vWLaE8kjm;fA5zIe%$fZM_ZdaT0E1}|mj)Tj zei()PhrOIrhkfRAI#E4T+)4I@qygwpFGN5M5o&5H?$UkFyFuv@YAROv?S77bv;Dza zsSp^&<(%m>Mm*p;GOPY`8@OmP({`_mtI~w2L{$=mYGTT08GRiMw+(x2<&fz)?{kZZ zfWM4ntOO)6cTlb7?lW_gWb^UgVCTl;JOJ`_YC^Z+d(AXt!htjF75IQp^gpu@-%|?2 zOLERqjsmIxoY!C=l3v*3>-OHjJ6Bbjc9p2h2Ei!zIc00bIlU4i*`8~2~(MRek zEinwGKySCcgRZ5SVO|_iianlLSx$_?o}P0j?`yKw$?q*LtG`6-0fkdlfpOALYhGnP z2h_K3EZO3@rT@W%!i7L>%iL{w`pS#98^(tMt5r3SoSD1L|KfPpF@RxZ^GfHA>1u81 zgkmLu+LF23;&kfVIP1LVZ!K!)%4Vu_d+yxuf=K|}KB9#o(O@S_U?xtH|c7>~uF2yA&EzLDRaDgHiU0VxF4{n^5+h7L>t$rm&)U*Yibhm)wW* z9p@Vk#v(A2hm^GDFxU`tI1_ow5BOljEFel+fA&ANNbSJofzc@J)RGruiD7T3wzM9# zlGbpmu6y-oA;GLYgiZS^wcc_B)62)i7+}Z9{#P*$)M3|e0qC{_?*v0x-$s;1Ee9m8 zU|9&ue3l~9P~j-+%R=R>aw495Ig}!gj|3mwXIhoNfY?`y zr1uGeE@0}}l}}^p?w;qU{;$+>RKq{!th3Hmf6^OOcg6($#C`tcPb>?a{|z$j zc?v}83#*~#^D3=h4I4Gn;)iuP{7E~AKLp!lUZiK<2}du?ADwKEol1<*?q@$hwK&-P z?Zq)lITE~yA^ETTjOjp%yq_u2Lk;xFk?_~Qx2MRDn+3Gv=`e`xxt=!9l62E#u1xW4 zjc)27ZHuV(PJS_Us8DT@^Bn}lceHRPC*2KFwp7*^8wUyHe|wn=`*Ue%$5lrN&c;Hu zS+*OsCS1sI zn7~n%REg~}$I#&I(beSlk=lIviKZX1xU-`}AFVrDuCl2(E;xlyxEe#9L}JTIA4F{L z0JXdOKf0&83af5xe?)4lw{T&9O%TI?@oN9t`m?1hsVhGO_XT%TN2Fx1?d8LF?-{WZ z$R0;gG++PZH|p?%NMx~EF}S18MMH*n*&b>A)HS@omWMZ$)LVoh5+jXeNvl!0hLCB@ z0~YAOuT+#XZ{`;|ra)&-B?z=Og2orf+bkP_!%15mldWrep+Ij(LAnI*Bgv9_Z$X6Z z8(u{hb{vIQiC5NgFd1CfQ49o9$MU2-0 z6rD)}(~t2p@Hjmdyl}C0gn2E%I|yEMJQ6tHgPb2D>3YeJ=%q5SpPR0(BaBhx=t2dj mYd^zrwXQz0r2GCeEUlaTaqEuqpW$BwEOb+N(DjY Date: Thu, 6 Jun 2019 19:18:20 +0530 Subject: [PATCH 102/306] kivy new updates --- src/bitmessagekivy/kivy_helper_search.py | 2 +- src/bitmessagekivy/main.kv | 142 +++++++++----- src/bitmessagekivy/mpybit.py | 240 ++++++++++++++++++----- src/bitmessagekivy/uikivysignaler.py | 2 + src/state.py | 8 +- src/tr.py | 5 +- 6 files changed, 302 insertions(+), 97 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index cbf00fb4..73a8a1ff 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -42,4 +42,4 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file + return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 62d3cbe3..208253ff 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,4 +1,3 @@ - #:import Toolbar kivymd.toolbar.Toolbar #:import ThemeManager kivymd.theming.ThemeManager #:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer @@ -34,10 +33,14 @@ #:import MDBottomNavigation kivymd.tabs.MDBottomNavigation #:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton +#:import Factory kivy.factory.Factory : icon: 'checkbox-blank-circle' +: + font_size: '12.5sp' + : drawer_logo: './images/drawer_logo1.png' NavigationDrawerDivider: @@ -48,6 +51,8 @@ Spinner: pos_hint:{"x":0,"y":.25} id: btn + option_cls: Factory.get("MySpinnerOption") + font_size: '12.5sp' text: app.getDefaultAccData() values: app.variable_1 on_text:app.getCurrentAccountData(self.text) @@ -175,7 +180,7 @@ NavigationLayout: id:sc12 NetworkStat: id:sc13 - SentDetail: + MailDetail: id:sc14 : @@ -184,20 +189,8 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' + ComposerButton: : name: 'sent' @@ -205,20 +198,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' + ComposerButton: : name: 'trash' @@ -226,21 +206,8 @@ NavigationLayout: do_scroll_x: False MDList: id: ml - BoxLayout: - 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' - + ComposerButton: + : name: 'draft' Label: @@ -289,6 +256,8 @@ NavigationLayout: text: 'select' values: app.variable_1 on_text: ti.text = self.text + option_cls: Factory.get("MySpinnerOption") + font_size: '12.5sp' BoxLayout: orientation: 'vertical' @@ -530,6 +499,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml + ComposerButton: : name: 'addressbook' @@ -539,6 +509,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml + ComposerButton: : name: 'payment' @@ -648,8 +619,8 @@ NavigationLayout: size_hint: .8, .6 text: root.text_variable_5 -: - name: 'sentdetail' +: + name: 'mailDetail' ScrollView: do_scroll_x: False BoxLayout: @@ -662,6 +633,11 @@ NavigationLayout: theme_text_color: 'Primary' text: root.subject halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: "From: " + root.from_addr + halign: 'left' MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' @@ -670,11 +646,81 @@ NavigationLayout: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' - text: "From: " + root.from_addr + text: root.status halign: 'left' MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: root.message halign: 'left' - bold: True \ No newline at end of file + bold: True + BoxLayout: + spacing:50 + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Copy' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Delete' + on_press: root.delete_mail() + +: + 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' + +: + id: myadd_popup + background: './images/popup.jpeg' + separator_height: 0 + auto_dismiss: False + BoxLayout: + size_hint_y: None + spacing:50 + id: popup_box + orientation: 'vertical' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address_label + halign: 'left' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + halign: 'left' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Save' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Cancel' + on_press: root.dismiss() + MDRaisedButton: + size_hint: 1, None + height: dp(40) + text: 'Scan QR code' \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 7273aeee..046b2fe4 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -46,6 +46,7 @@ from kivy.uix.button import Button import kivy_helper_search from kivy.core.window import Window from functools import partial +from kivy.uix.carousel import Carousel class Navigatorss(MDNavigationDrawer): @@ -56,6 +57,8 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" + data = ListProperty() + def __init__(self, *args, **kwargs): super(Inbox, self).__init__(*args, **kwargs) if state.association == '': @@ -64,7 +67,7 @@ class Inbox(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method sent accounts.""" + """Clock Schdule for method inbox accounts.""" self.inboxaccounts() print(dt) @@ -74,7 +77,7 @@ class Inbox(Screen): self.loadMessagelist(account, 'All', '') def loadMessagelist(self, account, where="", what=""): - """Load Sent list for Sent messages.""" + """Load Inbox list for Inbox messages.""" xAddress = 'toaddress' data = [] queryreturn = kivy_helper_search.search_sql( @@ -82,11 +85,29 @@ class Inbox(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[2].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[2]) > 10 else mail[2] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text }) + # ('inbox', 'j\xe5(M\xcfPbe\rl\x0f\xa3\r\xef>\xf0\x0b&\t\'}"RYg\x03\x80\x14\x82\xeb&,', 'BM-2cXpNNd7dhTjsv7LHNfmphfUabZk958sA3', 'hello', 'BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe', 'test from peter', '1559121770', 0) + data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - self.ids.ml.add_widget(meny) + meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) + carousel = Carousel(direction='right') + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_color = (1, 0, 0, .5) + del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0,1,0,1) + ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) + carousel.add_widget(ach_btn) + carousel.index=1 + self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -97,6 +118,40 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) + def inbox_detail(self, receivedTime, *args): + """Load inbox page details""" + state.detailPageType = 'inbox' + state.sentMailTime = receivedTime + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + + def delete(self, data_index, instance, *args): + """Delete inbox mail from inbox listing""" + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def archive(self, data_index, instance, *args): + """Archive inbox mail from inbox listing""" + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + except Exception as e: + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) + + class MyAddress(Screen): """MyAddress Screen uses screen to show widgets of screens.""" @@ -106,13 +161,14 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or state.kivyapp.variable_1: + if BMConfigParser().addresses() or ContentNavigationDrawer().ids.btn.values: data = [] - for address in state.kivyapp.variable_1: + for address in ContentNavigationDrawer().ids.btn.values: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.bind(on_press = partial(self.myadd_detail, item['secondary_text'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -128,6 +184,11 @@ class MyAddress(Screen): except Exception as e: pass + def myadd_detail(self, fromaddress, *args): + p = MyaddDetailPopup() + p.open() + p.get_address(fromaddress) + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -278,6 +339,7 @@ class DropDownWidget(BoxLayout): self.main_pop = Popup(title="Error", content=self.box, size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) self.but.bind(on_press=self.main_pop.dismiss) + # self.main_pop.background = './images/popup.jpeg' self.main_pop.open() @@ -370,13 +432,16 @@ class Random(Screen): nonceTrialsPerByte, payloadLengthExtraBytes) ) - self.manager.current = 'add_sucess' + # self.manager.current = 'add_sucess' + self.manager.current = 'myaddress' self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - self.parent.parent.parent.parent.ids.sc10.clear_widgets() - self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 + # self.parent.parent.parent.parent.ids.sc10.clear_widgets() + # self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + class AddressSuccessful(Screen): pass @@ -410,18 +475,35 @@ class Sent(Screen): def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" xAddress = 'fromaddress' - data = [] queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) + state.totalSentMail = len(queryreturn) if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[0].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, 'lastactiontime': mail[6]}) - for item in data: + self.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, 'lastactiontime': mail[6]}) + for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) - self.ids.ml.add_widget(meny) + carousel = Carousel(direction='right') + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_color = (1, 0, 0, .5) + del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0,1,0,1) + ach_btn.bind(on_press=partial(self.archive, item['lastactiontime'])) + carousel.add_widget(ach_btn) + carousel.index=1 + self.ids.ml.add_widget(carousel) + # self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -433,14 +515,37 @@ class Sent(Screen): self.ids.ml.add_widget(content) def sent_detail(self, lastsenttime, *args): + """Load sent mail details""" + state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: src_mng_obj = self.manager else: src_mng_obj = self.parent.parent src_mng_obj.screens[13].clear_widgets() - src_mng_obj.screens[13].add_widget(SentDetail()) - src_mng_obj.current = 'sentdetail' + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + + def delete(self, data_index, instance, *args): + """delete sent mail from sent mail listing""" + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def archive(self, data_index, instance, *args): + """archive sent mail from sent mail listing""" + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + except Exception as e: + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) class Trash(Screen): @@ -451,22 +556,14 @@ class Trash(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - data = [{'text': "neha cis", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "onkar", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "amazon", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "paytm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "pol", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "akshayaura", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "codementor", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "yatra", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "mdtezm", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}, - {'text': "crewqt", 'secondary_text': "party invitation..........." + '\n' + " " + "lets gather for party on 1st JANUARY...!"}] - for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash';") + sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash';") + trash_data = inbox + sent + for item in trash_data: + meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) self.ids.ml.add_widget(meny) - class Page(Screen): pass @@ -493,7 +590,7 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() - # obj_2 = ObjectProperty() + obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() total_sentmail = str(state.totalSentMail) @@ -523,10 +620,11 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() - # self.obj_2 = MyAddress() + self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() + Window.bind(on_keyboard=self.on_key) return main_widget def run(self): @@ -541,7 +639,6 @@ class NavigateApp(App): shutdown.doCleanShutdown() def show_address_success(self): - print("9062 I am pressed...............................................................") content = MDLabel(font_style='Body1', theme_text_color='Secondary', text="Successfully Saved your contact address. " @@ -555,6 +652,7 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": + # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -574,6 +672,7 @@ class NavigateApp(App): self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) + self.root.ids.scr_mngr.current = 'inbox' def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" @@ -605,14 +704,29 @@ class NavigateApp(App): return True return False - def prnttttttttttttt(self): - pass - def limit_spinner(self): max = 2.8 - spinner_obj =ContentNavigationDrawer().ids.btn + spinner_obj = ContentNavigationDrawer().ids.btn spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 + def on_key(self, window, key, *args): + if key == 27: # the esc key + if self.root.ids.scr_mngr.current_screen.name == "mailDetail": + self.root.ids.scr_mngr.current = 'sent' + # this is for direction of the screen comesup + # self.root.ids.scr_mngr.transition.direction = 'right' + return True + elif self.root.ids.scr_mngr.current_screen.name == "create": + self.root.ids.scr_mngr.current = 'inbox' + return True + else: + return True + + def status_dispatching(self, data): + ackData, message = data + if state.ackdata == ackData: + state.status.status = message + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -685,22 +799,58 @@ class NavigationDrawerTwoLineListItem( pass -class SentDetail(Screen): - """SentDetail Screen uses to show the detail of mails.""" +class MailDetail(Screen): + """MailDetail Screen uses to show the detail of mails.""" to_addr = StringProperty() from_addr = StringProperty() subject = StringProperty() message = StringProperty() + status = StringProperty() def __init__(self, *args, **kwargs): - super(SentDetail, self).__init__(*args, **kwargs) + super(MailDetail, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method SentDetail mails.""" - data = sqlQuery("select toaddress, fromaddress, subject, message from sent where lastactiontime = {};".format(state.sentMailTime)) - if data: - self.to_addr = data[0][0] - self.from_addr = data[0][1] - self.subject = data[0][2].upper() - self.message = data[0][3] \ No newline at end of file + """Clock Schdule for method MailDetail mails.""" + if state.detailPageType == 'sent': + data = sqlQuery("select toaddress, fromaddress, subject, message , status, ackdata from sent where lastactiontime = {};".format(state.sentMailTime)) + state.status = self + state.ackdata = data[0][5] + self.assign_mail_details(data) + elif state.detailPageType == 'inbox': + data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + self.assign_mail_details(data) + + def assign_mail_details(self, data): + self.to_addr = data[0][0] + self.from_addr = data[0][1] + self.subject = data[0][2].upper() + self.message = data[0][3] + if len(data[0]) == 6: + self.status = data[0][4] + + def delete_mail(self): + if state.detailPageType == 'sent': + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) + self.parent.parent.screens[3].clear_widgets() + self.parent.parent.screens[3].add_widget(Sent()) + self.parent.parent.current = 'sent' + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) + + +class MyaddDetailPopup(Popup): + """MyaddDetailPopup pop is used for showing my address detail""" + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + super(MyaddDetailPopup, self).__init__(**kwargs) + self.size_hint_y = 0.4 + self.size_hint_x = 0.9 + + def get_address(self, address): + """Getting address for displaying details on popup""" + self.address_label = BMConfigParser().get(address, 'label') if BMConfigParser().get(address, 'label') else '' + self.address = address \ No newline at end of file diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py index 82d94a14..5681d25d 100644 --- a/src/bitmessagekivy/uikivysignaler.py +++ b/src/bitmessagekivy/uikivysignaler.py @@ -18,6 +18,8 @@ class UIkivySignaler(Thread): state.kivyapp.variable_1.append(address) elif command == 'rerenderAddressBook': state.kivyapp.obj_1.refreshs() + elif command == 'updateSentItemStatusByAckdata': + state.kivyapp.status_dispatching(data) except Exception as e: print(e) diff --git a/src/state.py b/src/state.py index 3c7dd9ea..4aca8ae7 100644 --- a/src/state.py +++ b/src/state.py @@ -78,6 +78,10 @@ totalSentMail = 0 sentMailTime = 0 -dynamicAddressList = [] +myAddressObj = None -myAddressObj = None \ No newline at end of file +detailPageType = None + +ackdata = None + +status = None \ No newline at end of file diff --git a/src/tr.py b/src/tr.py index 6f26e75d..0d9643a8 100644 --- a/src/tr.py +++ b/src/tr.py @@ -13,8 +13,11 @@ class translateClass: else: return self.text +# def _translate(context, text, disambiguation = None, encoding = None, n = None): +# return translateText(context, text, n) + def _translate(context, text, disambiguation = None, encoding = None, n = None): - return translateText(context, text, n) + return text def translateText(context, text, n = None): try: From 73aa60e554c59bdcf3fe2f91a4ba2df2dc34c9df Mon Sep 17 00:00:00 2001 From: surbhi Date: Fri, 2 Aug 2019 14:41:33 +0530 Subject: [PATCH 103/306] kivy searchbar adding with few more implementation --- src/bitmessagekivy/kivy_helper_search.py | 16 +- src/bitmessagekivy/main.kv | 90 ++++++++-- src/bitmessagekivy/mpybit.py | 211 +++++++++++++++++++---- src/state.py | 6 +- 4 files changed, 266 insertions(+), 57 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 73a8a1ff..eae6be01 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -7,7 +7,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w else: what = None - if folder == "sent": + if folder == "sent" or folder == "draft": sqlStatementBase = ''' SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' @@ -34,12 +34,20 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementParts.append("folder != ?") sqlArguments.append("trash") if what is not None: - sqlStatementParts.append("%s LIKE ?" % (where)) - sqlArguments.append(what) + for colmns in where: + if len(where) > 1: + if where[0] == colmns: + filter_col = "(%s LIKE ?" % (colmns) + else: + filter_col += " or %s LIKE ? )" % (colmns) + else: + filter_col = "%s LIKE ?" % (colmns) + sqlArguments.append(what) + sqlStatementParts.append(filter_col) if unreadOnly: sqlStatementParts.append("read = 0") if len(sqlStatementParts) > 0: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) + return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 7d1d380f..861bbbac 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -36,6 +36,8 @@ #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory #:import MDTextButton kivymd.button.MDTextButton +#:import FadeTransition kivy.uix.screenmanager.FadeTransition +#:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -57,7 +59,7 @@ NavigationDrawerTwoLineListItem: text: "Accounts" NavigationDrawerIconButton: - Spinner: + CustomSpinner: pos_hint:{"x":0,"y":.25} id: btn option_cls: Factory.get("MySpinnerOption") @@ -68,7 +70,6 @@ color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - on_press: app.limit_spinner() ArrowImg: NavigationDrawerIconButton: id: inbox_cnt @@ -76,43 +77,51 @@ text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: draft_cnt icon: 'message-draw' text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Starred" icon:'star' on_release: app.root.ids.scr_mngr.current = 'inbox' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'archive' text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: "9+" + on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'email-open-outline' text: "Spam" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "8+" + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "All Mails" icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "999+" + on_press: app.check_search_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -120,26 +129,32 @@ text: "Address Book" icon:'book-multiple' on_release: app.root.ids.scr_mngr.current = 'addressbook' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Settings" icon:'settings' - on_release: app.root.ids.scr_mngr.current = 'set' + on_release: app.root.ids.scr_mngr.current = 'set' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Subscriptions/Payment" icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'payment' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "new address" icon:'account-plus' on_release: app.root.ids.scr_mngr.current = 'login' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Network Status" icon:'server-network' on_release: app.root.ids.scr_mngr.current = 'networkstat' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "My Addresses" icon:'account-multiple' on_release: app.root.ids.scr_mngr.current = 'myaddress' + on_press: app.check_search_screen(self) NavigationLayout: id: nav_layout @@ -148,6 +163,7 @@ NavigationLayout: id: nav_drawer BoxLayout: + id: box_layout orientation: 'vertical' Toolbar: id: toolbar @@ -158,6 +174,45 @@ NavigationLayout: background_palette: 'Primary' background_hue: '500' left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] + Button: + id: reset_navbar + size_hint_y: 0.35 + size_hint_x: 0.2 + opacity: 0 + disabled: True + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.reset_navdrawer(self) + Image: + source: './images/left_arrow.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 40, 40 + TextInput: + id: search_input + hint_text: 'search' + opacity: 0 + size_hint: 1,None + height: dp(32) + disabled: True + pos_hint: {'center_x':.565,'center_y': .5} + multiline: False + padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0] + padding_x: 20,20 + Button: + id: serch_btn + size_hint_y: 0.35 + size_hint_x: 0.2 + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.searchQuery(self, search_input.text) + Image: + source: './images/search_mail.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 55, 55 Button: id: myButton size_hint_y: 0.35 @@ -170,6 +225,7 @@ NavigationLayout: source: './images/addressbookadd.png' center_x: self.parent.center_x center_y: self.parent.center_y + size: 55, 55 ScreenManager: id: scr_mngr Inbox: @@ -208,12 +264,14 @@ NavigationLayout: : name: 'inbox' - ScrollView: - do_scroll_x: False - MDList: - id: ml - - ComposerButton: + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml + ComposerButton : name: 'sent' @@ -272,13 +330,12 @@ NavigationLayout: font_size: '13sp' multiline: False required: True - allow_copy: True helper_text_mode: "on_error" BoxLayout: size_hint_y: None height: dp(40) - Spinner: + CustomSpinner: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 @@ -569,10 +626,13 @@ NavigationLayout: : name: 'myaddress' - ScrollView: - do_scroll_x: False - MDList: - id: ml + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml ComposerButton: : diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b122791f..067eb4e5 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -4,7 +4,7 @@ from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ObjectProperty from kivy.uix.image import Image -from kivy.uix.screenmanager import Screen +from kivy.uix.screenmanager import Screen, NoTransition from kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet from kivymd.button import MDIconButton from kivymd.date_picker import MDDatePicker @@ -48,7 +48,7 @@ from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel from kivy.utils import platform - +from kivy.uix.spinner import Spinner class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') @@ -79,6 +79,9 @@ class Inbox(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox list for Inbox messages.""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text xAddress = 'toaddress' data = [] queryreturn = kivy_helper_search.search_sql( @@ -86,15 +89,16 @@ class Inbox(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - # ('inbox', 'j\xe5(M\xcfPbe\rl\x0f\xa3\r\xef>\xf0\x0b&\t\'}"RYg\x03\x80\x14\x82\xeb&,', 'BM-2cXpNNd7dhTjsv7LHNfmphfUabZk958sA3', 'hello', 'BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe', 'test from peter', '1559121770', 0) data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -109,7 +113,7 @@ class Inbox(Screen): ach_btn.background_color = (0,1,0,1) ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) carousel.add_widget(ach_btn) - carousel.index=1 + carousel.index = 1 self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', @@ -129,6 +133,8 @@ class Inbox(Screen): src_mng_obj = self.manager else: src_mng_obj = self.parent.parent + + hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -160,6 +166,23 @@ class Inbox(Screen): self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + def refresh_callback(self, *args): + """A method that updates the state of your application + while the spinner remains on the screen.""" + + def refresh_callback(interval): + """This methods is used for loading the inbox screen data""" + self.ids.ml.clear_widgets() + self.remove_widget(self.children[1]) + try: + screens_obj = self.parent.screens[0] + except Exception as e: + screens_obj = self.parent.parent.screens[0] + screens_obj.add_widget(Inbox()) + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) class MyAddress(Screen): @@ -176,7 +199,7 @@ class MyAddress(Screen): data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper() if (item['text'][0].upper() >= 'A' and item['text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: @@ -198,6 +221,24 @@ class MyAddress(Screen): p.open() p.set_address(fromaddress, label) + def refresh_callback(self, *args): + """A method that updates the state of your application + while the spinner remains on the screen.""" + + def refresh_callback(interval): + """This methods is used for loading the myaddress screen data""" + self.ids.ml.clear_widgets() + self.remove_widget(self.children[1]) + try: + screens_obj = self.parent.screens[9] + except Exception as e: + screens_obj = self.parent.parent.screens[9] + screens_obj.add_widget(MyAddress()) + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -211,12 +252,13 @@ class AddressBook(Screen): if data: for item in data: meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper() if (item[0][0].upper() >= 'A' and item[0][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) - # self.ids.ml.add_widget(meny) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 140 + carousel.height = 140 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -358,6 +400,8 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' + self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 + self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False return None else: @@ -487,10 +531,6 @@ class AddressSuccessful(Screen): pass -class NavigationLayout(): - pass - - class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" data = ListProperty() @@ -514,6 +554,9 @@ class Sent(Screen): def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) @@ -528,11 +571,13 @@ class Sent(Screen): self.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, 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -549,7 +594,6 @@ class Sent(Screen): carousel.add_widget(ach_btn) carousel.index=1 self.ids.ml.add_widget(carousel) - # self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -568,6 +612,7 @@ class Sent(Screen): src_mng_obj = self.manager else: src_mng_obj = self.parent.parent + hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -575,7 +620,7 @@ class Sent(Screen): def delete(self, data_index, instance, *args): """delete sent mail from sent mail listing""" try: - msg_count_objs = self.parent.parent.parent.parent.children[2].ids + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids except Exception as e: msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.sent_count) > 0: @@ -586,7 +631,6 @@ class Sent(Screen): sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) - # self.update_mail_count() self.update_trash() def archive(self, data_index, instance, *args): @@ -623,7 +667,7 @@ class Trash(Screen): for item in trash_data: meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper() if (item[2][0].upper() >= 'A' and item[2][0].upper() <= 'Z') else '!'))) self.ids.ml.add_widget(meny) class Page(Screen): @@ -676,7 +720,7 @@ class NavigateApp(App): ] def build(self): - import os + import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -705,7 +749,6 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": - # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -774,16 +817,12 @@ class NavigateApp(App): return True return False - def limit_spinner(self): - max = 2.8 - spinner_obj = ContentNavigationDrawer().ids.btn - spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 - def on_key(self, window, key, *args): """This method is used for going on previous screen""" if key == 27: # the esc key if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' + show_search_btn(self) # this is for direction of the screen comesup elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root @@ -791,19 +830,21 @@ class NavigateApp(App): to_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) if from_addr and to_addr: Draft().draft_msg(composer_objs) - # self.root.ids.scr_mngr.current + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False self.root.ids.scr_mngr.current = 'inbox' elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' elif self.root.ids.scr_mngr.current == "random": - self.root.ids.scr_mngr.current = 'login' + self.root.ids.scr_mngr.current = 'login' else: self.root.ids.scr_mngr.current = 'inbox' + show_search_btn(self) self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.restart) return True - def restart(self, *args): + def restart(self, *args): """this method is used to set transition direction""" self.root.ids.scr_mngr.transition.direction = 'left' self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) @@ -815,6 +856,8 @@ class NavigateApp(App): def clear_composer(self): """if slow down the nwe will make new composer edit screen""" + self.root.ids.serch_btn.opacity = 0 + self.root.ids.serch_btn.disabled = True composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -844,16 +887,77 @@ class NavigateApp(App): state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) return state.draft_count - def current_address_label(self, current_address = None): + def current_address_label(self, current_address=None): if BMConfigParser().addresses() or current_address: if current_address: first_name = current_address - else: + else: first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') f_name = first_name.split() return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] return '' + def searchQuery(self, instance, text): + '''This method is used for showing searched mails''' + if self.root.ids.search_input.opacity == 0: + self.root.ids.search_input.opacity = 1 + self.root.ids.search_input.size_hint = 4,None + # self.root.ids.serch_btn.opacity = 0 + # self.root.ids.serch_btn.disabled = True + self.root.ids.search_input.disabled = False + self.root.ids.search_input.focus = True + self.root.ids.toolbar.left_action_items = [] + self.root.ids.toolbar.title = '' + self.root.ids.myButton.opacity = 0 + self.root.ids.myButton.disabled = True + self.root.ids.reset_navbar.opacity = 1 + self.root.ids.reset_navbar.disabled = False + elif str(text): + state.search_screen = self.root.ids.scr_mngr.current + state.searcing_text = str(text).strip() + if state.search_screen == 'inbox': + self.root.ids.sc1.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + else: + self.root.ids.sc4.clear_widgets() + self.root.ids.sc4.add_widget(Sent()) + self.root.ids.scr_mngr.current = state.search_screen + + def reset_navdrawer(self, instance): + '''This methos is used for reseting navigation drawer''' + self.root.ids.search_input.text = '' + self.root.ids.search_input.opacity = 0 + self.root.ids.search_input.size_hint = 1,None + self.root.ids.search_input.disabled = True + self.root.ids.toolbar.left_action_items = [['menu', lambda x: self.root.toggle_nav_drawer()]] + self.root.ids.toolbar.title = self.current_address_label() + self.root.ids.myButton.opacity = 1 + self.root.ids.myButton.disabled = False + self.root.ids.reset_navbar.opacity = 0 + self.root.ids.reset_navbar.disabled = True + state.searcing_text = '' + if state.search_screen == 'inbox': + self.root.ids.sc1.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + else: + self.root.ids.sc4.clear_widgets() + self.root.ids.sc4.add_widget(Sent()) + + def check_search_screen(self, instance): + '''This method is used for showing search button only on inbox or sent screen''' + if instance.text == 'Inbox' or instance.text == 'Sent': + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False + state.searcing_text = '' + self.root.ids.sc1.clear_widgets() + self.root.ids.sc4.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + self.root.ids.sc4.add_widget(Sent()) + else: + self.root.ids.serch_btn.opacity = 0 + self.root.ids.serch_btn.disabled = True + return + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -882,6 +986,8 @@ class GrashofPopup(Popup): queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + self.parent.children[1].ids.serch_btn.opacity = 0 + self.parent.children[1].ids.serch_btn.disabled = True self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): @@ -993,6 +1099,8 @@ class MailDetail(Screen): state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 + self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False def inbox_reply(self): """This method is used for replying inbox messages""" @@ -1124,12 +1232,11 @@ class Draft(Screen): for item in self.data: meny = TwoLineAvatarIconListItem(text='Draft', secondary_text=item['text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - # wimg = Image(source='/home/cis/transparent1.png', size= (10, 10)) - # meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - # carousel = MDCardPost(text_post='Card with text',swipe=True, callback=callback) if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -1207,4 +1314,34 @@ class Draft(Screen): state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() src_object.ids.sc16.add_widget(Draft()) - return \ No newline at end of file + return + + +def show_search_btn(self): + '''This method is used to show search button''' + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False + + +def hide_search_btn(mgr_objs): + '''This method is used to hide search button and search box''' + mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 + mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True + mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1,None + mgr_objs.parent.parent.parent.ids.search_input.disabled = True + mgr_objs.parent.parent.parent.ids.search_input.opacity = 0 + mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] + mgr_objs.parent.parent.parent.ids.toolbar.title = NavigateApp().current_address_label() + mgr_objs.parent.parent.parent.ids.myButton.opacity = 1 + mgr_objs.parent.parent.parent.ids.myButton.disabled = False + mgr_objs.parent.parent.parent.ids.reset_navbar.opacity = 0 + mgr_objs.parent.parent.parent.ids.reset_navbar.disabled = True + + +class CustomSpinner(Spinner): + '''This class is used for setting spinner size''' + def __init__(self, *args, **kwargs): + '''This methods is used for setting size of spinner''' + super(CustomSpinner, self).__init__(*args, **kwargs) + max = 2.8 + self.dropdown_cls.max_height = self.height * max + max * 4 \ No newline at end of file diff --git a/src/state.py b/src/state.py index 34bef37b..745f2f4c 100644 --- a/src/state.py +++ b/src/state.py @@ -96,4 +96,8 @@ inbox_count = 0 trash_count = 0 -draft_count = 0 \ No newline at end of file +draft_count = 0 + +searcing_text = '' + +search_screen = '' \ No newline at end of file From 2fc2101e8071a604f346c62ce667bb8ecebd0f10 Mon Sep 17 00:00:00 2001 From: surbhi Date: Fri, 28 Jun 2019 20:24:47 +0530 Subject: [PATCH 104/306] Implement qrcode display feature with Ui enhancement and message avtar display based on message --- src/bitmessagekivy/main.kv | 306 ++++++++++++++++++++++++++--------- src/bitmessagekivy/mpybit.py | 223 +++++++++++++++++++++---- src/images/text_images/A.png | Bin 0 -> 6857 bytes src/images/text_images/B.png | Bin 0 -> 6533 bytes src/images/text_images/C.png | Bin 0 -> 7662 bytes src/images/text_images/D.png | Bin 0 -> 6381 bytes src/images/text_images/E.png | Bin 0 -> 5009 bytes src/images/text_images/F.png | Bin 0 -> 4972 bytes src/images/text_images/G.png | Bin 0 -> 7593 bytes src/images/text_images/H.png | Bin 0 -> 5054 bytes src/images/text_images/I.png | Bin 0 -> 4713 bytes src/images/text_images/J.png | Bin 0 -> 5841 bytes src/images/text_images/K.png | Bin 0 -> 6719 bytes src/images/text_images/L.png | Bin 0 -> 4878 bytes src/images/text_images/M.png | Bin 0 -> 6569 bytes src/images/text_images/N.png | Bin 0 -> 6509 bytes src/images/text_images/O.png | Bin 0 -> 7912 bytes src/images/text_images/P.png | Bin 0 -> 5914 bytes src/images/text_images/Q.png | Bin 0 -> 8271 bytes src/images/text_images/R.png | Bin 0 -> 6404 bytes src/images/text_images/S.png | Bin 0 -> 7826 bytes src/images/text_images/T.png | Bin 0 -> 4793 bytes src/images/text_images/U.png | Bin 0 -> 6113 bytes src/images/text_images/V.png | Bin 0 -> 6761 bytes src/images/text_images/W.png | Bin 0 -> 7805 bytes src/images/text_images/X.png | Bin 0 -> 7367 bytes src/images/text_images/Y.png | Bin 0 -> 6459 bytes src/images/text_images/Z.png | Bin 0 -> 6166 bytes src/state.py | 14 +- 29 files changed, 428 insertions(+), 115 deletions(-) create mode 100644 src/images/text_images/A.png create mode 100644 src/images/text_images/B.png create mode 100644 src/images/text_images/C.png create mode 100644 src/images/text_images/D.png create mode 100644 src/images/text_images/E.png create mode 100644 src/images/text_images/F.png create mode 100644 src/images/text_images/G.png create mode 100644 src/images/text_images/H.png create mode 100644 src/images/text_images/I.png create mode 100644 src/images/text_images/J.png create mode 100644 src/images/text_images/K.png create mode 100644 src/images/text_images/L.png create mode 100644 src/images/text_images/M.png create mode 100644 src/images/text_images/N.png create mode 100644 src/images/text_images/O.png create mode 100644 src/images/text_images/P.png create mode 100644 src/images/text_images/Q.png create mode 100644 src/images/text_images/R.png create mode 100644 src/images/text_images/S.png create mode 100644 src/images/text_images/T.png create mode 100644 src/images/text_images/U.png create mode 100644 src/images/text_images/V.png create mode 100644 src/images/text_images/W.png create mode 100644 src/images/text_images/X.png create mode 100644 src/images/text_images/Y.png create mode 100644 src/images/text_images/Z.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 208253ff..562e9f98 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -35,11 +35,18 @@ #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory +#: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 + : icon: 'checkbox-blank-circle' : font_size: '12.5sp' + background_color: color_button if self.state == 'down' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/button' + color: color_font : drawer_logo: './images/drawer_logo1.png' @@ -54,19 +61,24 @@ option_cls: Factory.get("MySpinnerOption") font_size: '12.5sp' text: app.getDefaultAccData() + background_color: color_button if self.state == 'normal' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/spinner' + color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) on_press: app.limit_spinner() NavigationDrawerIconButton: + id: inbox_cnt icon: 'email-open' text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "99+" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: + id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' - badge_text: "0" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: icon: 'message-draw' text: "Draft" @@ -87,10 +99,11 @@ on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "8+" NavigationDrawerIconButton: + id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' - badge_text: "9+" + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: text: "All Mails" icon:'contact-mail' @@ -182,6 +195,8 @@ NavigationLayout: id:sc13 MailDetail: id:sc14 + ShowQRCode: + id:sc15 : name: 'inbox' @@ -233,7 +248,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(app.scr_size) + height: dp(600) padding: dp(32) spacing: 15 BoxLayout: @@ -249,11 +264,10 @@ NavigationLayout: BoxLayout: size_hint_y: None - height: 100 + height: dp(40) Spinner: background_color: app.theme_cls.primary_dark id: btn - text: 'select' values: app.variable_1 on_text: ti.text = self.text option_cls: Factory.get("MySpinnerOption") @@ -289,17 +303,19 @@ NavigationLayout: required: True helper_text_mode: "on_error" BoxLayout: + spacing:50 AnchorLayout: MDRaisedButton: - size_hint: .8, .3 + size_hint: 1, None + height: dp(40) text: 'send' on_press: root.send() - BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .3 + size_hint: 1, None + height: dp(40) text: 'reset' - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: app.root.ids.scr_mngr.current = 'random' : readonly: False @@ -341,7 +357,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(800) + height: dp(700) BoxLayout: MDLabel: font_style: 'Body1' @@ -483,7 +499,7 @@ NavigationLayout: MDCheckbox: id: chkbox size_hint: None, None - size: dp(48), dp(48) + size: dp(48), dp(64) active: True MDLabel: font_style: 'Body1' @@ -519,44 +535,62 @@ NavigationLayout: id: popup title: 'add contact\'s' background: './images/popup.jpeg' - title_size: sp(30) + title_size: sp(20) title_color: 0.4, 0.3765, 0.3451, 1 size_hint: 1, 1 auto_dismiss: False separator_color: 0.3529, 0.3922, 0.102, 0.7 BoxLayout: - size_hint_y: None + size_hint_y: 0.5 orientation: 'vertical' - spacing:50 + spacing:dp(20) id: popup_box - orientation: 'vertical' - MDTextField: - id: label - multiline: True - hint_text: "Label" - required: True - helper_text_mode: "on_error" - MDTextField: - id: address - hint_text: "Address" - required: True - helper_text_mode: "on_error" - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Save' - on_release: - root.savecontact() - app.root.ids.scr_mngr.current = 'addressbook' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Cancel' - on_press: root.dismiss() - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Scan QR code' + BoxLayout: + orientation: 'vertical' + MDTextField: + id: label + multiline: True + hint_text: "Label" + required: True + helper_text_mode: "on_error" + MDTextField: + id: address + hint_text: "Address" + required: True + helper_text_mode: "on_error" + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_release: + root.savecontact() + MDLabel: + font_style: 'Title' + text: 'Save' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Scan QR code' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'networkstat' @@ -659,7 +693,8 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Copy' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() MDRaisedButton: size_hint: 1, None height: dp(40) @@ -680,6 +715,7 @@ NavigationLayout: elevation_normal: 8 md_bg_color: [0.941, 0, 0,1] on_press: app.root.ids.scr_mngr.current = 'create' + on_release: app.clear_composer() : id: myadd_popup @@ -688,39 +724,151 @@ NavigationLayout: auto_dismiss: False BoxLayout: size_hint_y: None - spacing:50 - id: popup_box + spacing:dp(70) + id: myadd_popup_box orientation: 'vertical' - MDLabel: - font_style: 'Title' - theme_text_color: 'Primary' - text: "Label" - halign: 'left' - MDLabel: - font_style: 'Subhead' - theme_text_color: 'Primary' - text: root.address_label - halign: 'left' - MDLabel: - font_style: 'Title' - theme_text_color: 'Primary' - text: "Address" - halign: 'left' - MDLabel: - font_style: 'Subhead' - theme_text_color: 'Primary' - text: root.address - halign: 'left' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Save' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Cancel' - on_press: root.dismiss() - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Scan QR code' \ No newline at end of file + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:dp(25) + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address_label + font_size: '15sp' + halign: 'left' + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + font_size: '15sp' + halign: 'left' + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + on_press: root.send_message_from() + MDLabel: + font_style: 'Title' + text: 'Send message from' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + on_press: app.root.ids.scr_mngr.current = 'showqrcode' + on_press: app.root.ids.sc15.qrdisplay() + MDLabel: + font_style: 'Title' + text: 'Show QR code' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + id: addbook_popup + background: './images/popup.jpeg' + separator_height: 0 + auto_dismiss: False + BoxLayout: + size_hint_y: None + spacing:dp(70) + id: addbook_popup_box + orientation: 'vertical' + BoxLayout: + size_hint_y: None + orientation: 'vertical' + spacing:dp(20) + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Label" + font_size: '17sp' + halign: 'left' + MDTextField: + id: add_label + font_style: 'Subhead' + font_size: '15sp' + halign: 'left' + text: root.address_label + theme_text_color: 'Primary' + required: True + helper_text_mode: "on_error" + MDLabel: + font_style: 'Title' + theme_text_color: 'Primary' + text: "Address" + font_size: '17sp' + halign: 'left' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: root.address + font_size: '15sp' + halign: 'left' + BoxLayout: + spacing:5 + orientation: 'horizontal' + MDRaisedButton: + size_hint: 2, None + height: dp(40) + on_press: root.send_message_to() + MDLabel: + font_style: 'Title' + text: 'Send message to' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + font_size: '10sp' + on_press: root.update_addbook_label(root.address) + MDLabel: + font_style: 'Title' + text: 'Save' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1.5, None + height: dp(40) + on_press: root.dismiss() + MDLabel: + font_style: 'Title' + text: 'Cancel' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + name: 'showqrcode' + BoxLayout: + orientation: 'vertical' + id: qr \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 046b2fe4..851375a1 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -47,6 +47,8 @@ import kivy_helper_search from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel +from kivy.garden.qrcode import QRCodeWidget +from kivy.utils import platform class Navigatorss(MDNavigationDrawer): @@ -89,10 +91,11 @@ class Inbox(Screen): data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') - carousel.height = 150 + if platform == 'android': + carousel.height = 150 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -132,6 +135,7 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing""" + state.navigation_drawer_obj = self.parent.parent.parent.parent.children[2].children[0].children[0].children[0].children sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -161,14 +165,14 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or ContentNavigationDrawer().ids.btn.values: + if BMConfigParser().addresses() or state.kivyapp.variable_1: data = [] - for address in ContentNavigationDrawer().ids.btn.values: + for address in state.kivyapp.variable_1: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - meny.bind(on_press = partial(self.myadd_detail, item['secondary_text'])) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper()))) + meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -184,10 +188,10 @@ class MyAddress(Screen): except Exception as e: pass - def myadd_detail(self, fromaddress, *args): + def myadd_detail(self, fromaddress, label, *args): p = MyaddDetailPopup() p.open() - p.get_address(fromaddress) + p.set_address(fromaddress, label) class AddressBook(Screen): @@ -202,7 +206,8 @@ class AddressBook(Screen): if data: for item in data: meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) + meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', @@ -218,6 +223,10 @@ class AddressBook(Screen): state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) + def addBook_detail(self, address, label, *args): + p = AddbookDetailPopup() + p.open() + p.set_addbook_data(address, label) class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): @@ -307,6 +316,10 @@ class DropDownWidget(BoxLayout): 'sent', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) + state.check_sent_acc = fromAddress + state.msg_counter_objs = self.parent.parent.parent.parent.parent.parent.children[0].children[2].children[0].ids + # state.msg_counter_objs.send_cnt.badge_text = str(int(state.sent_count) + 1) + # state.sent_count = str(int(state.sent_count) + 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' @@ -319,6 +332,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' + return None else: msg = 'Enter a valid recipients address' @@ -438,10 +452,10 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 - # self.parent.parent.parent.parent.ids.sc10.clear_widgets() - # self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) - + # state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 + self.parent.parent.parent.parent.ids.sc10.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + class AddressSuccessful(Screen): pass @@ -478,16 +492,22 @@ class Sent(Screen): queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) state.totalSentMail = len(queryreturn) + if state.msg_counter_objs and state.association == state.check_sent_acc: + state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) + state.sent_count = str(int(state.sent_count) + 1) + state.check_sent_acc = None + if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') self.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, 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - carousel.height = 150 + if platform == 'android': + carousel.height = 150 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -528,8 +548,19 @@ class Sent(Screen): def delete(self, data_index, instance, *args): """delete sent mail from sent mail listing""" + try: + msg_count_objs = self.parent.parent.parent.parent.children[2].ids + except Exception as e: + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + if int(state.sent_count) > 0: + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.sent_count = str(int(state.sent_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) + # self.update_mail_count() self.update_trash() def archive(self, data_index, instance, *args): @@ -556,12 +587,17 @@ class Trash(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash';") - sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash';") + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + + inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) trash_data = inbox + sent + for item in trash_data: meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper()))) self.ids.ml.add_widget(meny) class Page(Screen): @@ -590,11 +626,10 @@ class NavigateApp(App): theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() - obj_2 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() total_sentmail = str(state.totalSentMail) - scr_size = Window.size[0] + state.screen_density = Window.size title = "PyBitmessage" count = 0 menu_items = [ @@ -620,7 +655,6 @@ class NavigateApp(App): os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() self.obj_1 = AddressBook() - self.obj_2 = MyAddress() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() @@ -631,13 +665,6 @@ class NavigateApp(App): kivyuisignaler.release() super(NavigateApp, self).run() - def say_exit(self): - """Exit the application as uses shutdown PyBitmessage.""" - print("**************************EXITING FROM APPLICATION*****************************") - App.get_running_app().stop() - import shutdown - shutdown.doCleanShutdown() - def show_address_success(self): content = MDLabel(font_style='Body1', theme_text_color='Secondary', @@ -674,6 +701,17 @@ class NavigateApp(App): self.root.ids.sc5.add_widget(Trash()) self.root.ids.scr_mngr.current = 'inbox' + msg_counter_objs = self.root_window.children[1].children[2].children[0].ids + state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format(state.association))[0][0]) + state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format(state.association))[0][0]) + state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + + if msg_counter_objs: + msg_counter_objs.send_cnt.badge_text = state.sent_count + msg_counter_objs.inbox_cnt.badge_text = state.inbox_count + msg_counter_objs.trash_cnt.badge_text = state.trash_count + + def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" try: @@ -727,12 +765,44 @@ class NavigateApp(App): if state.ackdata == ackData: state.status.status = message + def clear_composer(self): + """if slow down the nwe will make new composer edit screen""" + composer_obj = self.root.ids.sc3.children[0].ids + composer_obj.ti.text = '' + composer_obj.btn.text = '' + composer_obj.txt_input.text = '' + composer_obj.subject.text = '' + + def on_stop(self): + """On stop methos is used for stoping the runing script""" + print("**************************EXITING FROM APPLICATION*****************************") + import shutdown + shutdown.doCleanShutdown() + + def mail_count(self, text): + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + if text == 'Sent': + state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.sent_count + elif text == 'Inbox': + state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.inbox_count + elif text == 'Trash': + state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + return state.trash_count + class GrashofPopup(Popup): def __init__(self, **kwargs): super(GrashofPopup, self).__init__(**kwargs) - self.size_hint_y = 0.7 - self.size_hint_x = 0.9 + if state.screen_density[0] <= 720: + self.size_hint_y = 0.4 + self.size_hint_x = 0.9 + else: + self.size_hint_y = 0.42 + self.size_hint_x = 0.7 def savecontact(self): label = self.ids.label.text @@ -742,6 +812,7 @@ class GrashofPopup(Popup): queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): content = MDLabel(font_style='Body1', @@ -806,6 +877,7 @@ class MailDetail(Screen): subject = StringProperty() message = StringProperty() status = StringProperty() + page_type = StringProperty() def __init__(self, *args, **kwargs): super(MailDetail, self).__init__(*args, **kwargs) @@ -813,6 +885,7 @@ class MailDetail(Screen): def init_ui(self, dt=0): """Clock Schdule for method MailDetail mails.""" + self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent': data = sqlQuery("select toaddress, fromaddress, subject, message , status, ackdata from sent where lastactiontime = {};".format(state.sentMailTime)) state.status = self @@ -836,9 +909,28 @@ class MailDetail(Screen): self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' + elif state.detailPageType == 'inbox': + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(state.sentMailTime)) + self.parent.parent.screens[0].clear_widgets() + self.parent.parent.screens[0].add_widget(Inbox()) + self.parent.parent.current = 'inbox' self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + def inbox_reply(self): + """This method is used for replying inbox messages""" + data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + composer_obj = self.parent.parent.screens[2].children[0].ids + composer_obj.ti.text = data[0][1] + composer_obj.btn.text = data[0][1] + composer_obj.txt_input.text = data[0][0] + composer_obj.subject.text = data[0][2] + self.parent.parent.current = 'create' + + def copy_sent_mail(self): + """This method is used for copying sent mail to the composer""" + pass + class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail""" @@ -847,10 +939,71 @@ class MyaddDetailPopup(Popup): def __init__(self, **kwargs): super(MyaddDetailPopup, self).__init__(**kwargs) - self.size_hint_y = 0.4 - self.size_hint_x = 0.9 + if state.screen_density[0] <= 720: + self.size_hint_y = 0.32 + self.size_hint_x = 0.9 + else: + self.size_hint_y = 0.32 + self.size_hint_x = 0.7 - def get_address(self, address): + def set_address(self, address, label): """Getting address for displaying details on popup""" - self.address_label = BMConfigParser().get(address, 'label') if BMConfigParser().get(address, 'label') else '' - self.address = address \ No newline at end of file + self.address_label = label + self.address = address + + def send_message_from(self): + """This method used to fill from address of composer autofield""" + window_obj = self.parent.children[1].ids + window_obj.sc3.children[0].ids.ti.text = self.address + window_obj.sc3.children[0].ids.btn.text = self.address + window_obj.sc3.children[0].ids.txt_input.text = '' + window_obj.sc3.children[0].ids.subject.text = '' + window_obj.sc3.children[0].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.dismiss() + +class AddbookDetailPopup(Popup): + """AddbookDetailPopup pop is used for showing my address detail""" + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + super(AddbookDetailPopup, self).__init__(**kwargs) + if state.screen_density[0] <= 720: + self.size_hint_y = 0.35 + self.size_hint_x = 0.95 + else: + self.size_hint_y = 0.35 + self.size_hint_x = 0.7 + + def set_addbook_data(self, address, label): + """Getting address book data for detial dipaly""" + self.address_label = label + self.address = address + + def update_addbook_label(self, address): + """Updating the label of address book address""" + if str(self.ids.add_label.text): + sqlExecute("UPDATE addressbook SET label = '{}' WHERE address = '{}';".format(str(self.ids.add_label.text), address)) + self.parent.children[1].ids.sc11.clear_widgets() + self.parent.children[1].ids.sc11.add_widget(AddressBook()) + self.dismiss() + + def send_message_to(self): + """This method used to fill to_address of composer autofield""" + window_obj = self.parent.children[1].ids + window_obj.sc3.children[0].ids.txt_input.text = self.address + window_obj.sc3.children[0].ids.ti.text = '' + window_obj.sc3.children[0].ids.btn.text = '' + window_obj.sc3.children[0].ids.subject.text = '' + window_obj.sc3.children[0].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.dismiss() + + +class ShowQRCode(Screen): + """ShowQRCode Screen uses to show the detail of mails.""" + + def qrdisplay(self): + self.ids.qr.clear_widgets() + self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) \ No newline at end of file diff --git a/src/images/text_images/A.png b/src/images/text_images/A.png new file mode 100644 index 0000000000000000000000000000000000000000..64ed6110e2cabcfe663e2b0c5ac459477d2020f3 GIT binary patch literal 6857 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/D.png b/src/images/text_images/D.png new file mode 100644 index 0000000000000000000000000000000000000000..2549ffc2e8bdc6e63dad4ba8d03e20e1ad08b4c3 GIT binary patch literal 6381 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/E.png b/src/images/text_images/E.png new file mode 100644 index 0000000000000000000000000000000000000000..5d6316114ef0eff37bd721612d3c9112f89b5c4b GIT binary patch literal 5009 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 I#Wv#q07IPYQ~&?~ literal 0 HcmV?d00001 diff --git a/src/images/text_images/H.png b/src/images/text_images/H.png new file mode 100644 index 0000000000000000000000000000000000000000..279bd1ce6db1edf17782fdb3babb05b5cfc39ecb GIT binary patch literal 5054 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 OU~F*fdX=7Y-2VXhe*nn< literal 0 HcmV?d00001 diff --git a/src/images/text_images/I.png b/src/images/text_images/I.png new file mode 100644 index 0000000000000000000000000000000000000000..c88f048d7a0a28879958c158d554a7457d21481d GIT binary patch literal 4713 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/J.png b/src/images/text_images/J.png new file mode 100644 index 0000000000000000000000000000000000000000..1533117129f4e267b4e475d10a41eb7fd378f7ce GIT binary patch literal 5841 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Ν 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 P0T}2#zE`8;^zQ!vHTMmM literal 0 HcmV?d00001 diff --git a/src/images/text_images/N.png b/src/images/text_images/N.png new file mode 100644 index 0000000000000000000000000000000000000000..2d235d0618e32ec6c2d4d0f2f488a4c1e5289011 GIT binary patch literal 6509 zcmY*;XIK+m+bz9GmtF!QAkENJT7V}YN>RFiQl*H7sz}L00zzn_0)jN@O+X+t=^+Us zy@`UYj zd$BN4?==p{d>R_zYbH0rwqdy&&f&v1dhVT%kUQsxRut*J2|TXcb(fE|j=3@aahSVn3+*mC;l1!GrFmcSsv+V#AFAp&g7{FjppKrR##5F5Zvz|=NfO0bAjtY zrcIG^bFge%abUpO!Q>=7Cn3P;gr@YZ_0OI`qhGYZSgk@hVy^G$`ZNkqD0|1SblHm_ zO17xn$J|JYc?^o=e_6->(M{x~&!gRRxbby2-@JEkXBC~K&@a<1_Vj5h6dmnzX&u`9 zlk#~g^>bS0vR1e?kyZ(=2W7vTw%g(j&@Bq3@AT=`Ox0-|@I@@@}!%_B~f2kFz!jP+)zz~8;ot}Dh5T(68DMNYE$MJ0+arp9e_bq2< z76uP)Hrqh4=&|%yKb`%C!9ugKbIxHWu!>VRy`Q6Yrq?Q}OhpmK{z+9xi(WpBg0@6{ zRS$v3Vj@OP1@iS?V_)}``kb%EwTl+*JK?9|4%s>G1q?pxx>Z~h?i^upv3SXS`%Tdd zM}lFN6yRxLZvL>SDF1XC(5`=DQKV0(usJ07exHD8(KfvI>-GMTF`-wXn0`OJSYrgT z>mT8&?2dkMx4xZ6&|U}Me=v0Ia~c;~@6)I@#^%#yCA#+SF$uK4_odxX`qR-hQNlBS zFK#e-n&_ndv2K3)RLxnegKL$T_1;xTfWO2yTSGpiPl4gL(vT9fJ=>HAV1k$*?W*z! zLvEs5)_U#GBKZ^RaK`P(^eDW*Zl6Bxh7%YxWqjwz_D9y@-A({nb<7Xz3kn_H;gks% z7y`!AO{9p84NlVRHv1WEXE{q^j2IhUMBZvfm~|>l6YsRy!V5r+HC-AvTsb^4vPPOo z{<6-CA6nOH?BH7H)5s3abp2_04L!7bMwSuHR&aeO!m@pDJvAV2%LG@KS6Ei^OJ_RV zVVq$_`*%B<9W`*gBN@dkBf6Ben0JcI5>Ir#+iXDp`dH3%{Xva{`?5&JWtA=Ac(_x& zF`r-#LukD;l$+cpm$_c@=1b$V>v!pW12oK?WnJqv`GP$VTcv%TBO5RBX61uA?hVel zkj-A+cJi-e4L=xdnNbZwTd_d~&z^Wfui$Kd0FG~Oa&A@g`D36uj`bJk*uw(e*isDl zn&r&sPNG!rjWMsy-BLocl1BHxU0tz;P7w?1z#!qY(jQx*_U3}GX5Xqk+?4VQ7-}E_ zTL!!0XPJ*7Lkc}|3J(1ut?^DZg|C|OfBx$DhzYk>qkq3Rb6vNPy|M6qAh+u{xVft5 zS$##~zeZn~xMzzX9CD~vWl#K>J(#Q?%U>hTdwRUOtYFgm+Io==xo?Z6_!bI#~^;R*x541ve%s!M#0k^60y zBxRhK%0fyh#VfzyJ@Ewva){*d<69_wCqbc0m0qZpdjc5>6dISzS0`r-`%G6Mv&pLG z>q{KVIUk;orRA4x4h%Dyg<1Oc>iHF#nqi6M+5;=_e~EOX*T?&ShI1-t+V+7j4o7^& z_S_$Gz8;Blm@vzLCY9}vzl9B4ubeibUxtVHR5?Q^QKtQjEO{D9oh@@>az&CqdV=gz zzP&D%Voeo!*(sVMZ9H`*X5~K|)b@|?qrvniY-ocRPy6q9!ps1owWaNI#M8!$414Tt znU2epX~tXeU^ltf^qUAP*MJep;gA`jK0NrQS=_tRE2* zVh_ny(zxp}_Du~cLZNVl)W3Uho=vym@lot!?bs1}mtcU>Rjx&Y3i!%Wn54Vl(9&j| z*rjmNTwc>keAqFJGZd&%3%<+Q9A3BuUI{S%VTVJXh3kGJiMF-*-zPoR5QtYHTEyOK4L1xf_yH!G5@?^<8Y_5;y z{-FE%D(Rh$dr%NTG1WbkpXWNHeZ+bNEE3N2{OGyI!-@_&HrKZdi&daUfEX|7OH{+28T*=Dem@kTDfJyu=4hxg{#R!kKNV+Xc6s*%Z8oc_LD6_t6*+Do-}- zP;43ohCcE~dY9Bj`T{&PHc34a@0#Kk`4yT2w^8VJ+<4_tk(^&ikz2l)e6Hi76BvdF z=*xS0ww$e1XE>Khxlrqj@-%Z;D^9mtefHjazGP6e+^t3$xxWhC&$PGcD_R-&6Jutl z6p*iO-}p7rj@Q)+n5$?^VA_ws_D2p7E!^5%?EbO!OVehgt z-bRH<74!b>vp$%5;f9{&=1nEc^LMMfz&9G}(;n?l=v-YogBS`64lEM|@8tA_xD_;r zy>ivP*m}Ya?dZ#A1Y&5zpgPX3cVc82*Oo5 z*6Q(wowq&lqU`_L^VNv)zGQGVA7-EDCJPS_$9?;xG#c9y%2k1jaX?=?nVpOJ?viZ| zm`WEPw5W-M;Hxhuf+t4TKiQ^QX4=z|ciN0AhsxZ17@fkOXhU;Nbz0b{gS zP2pS`b?U~ECMepMsk8RRgFC~K0;H% z#Ga}I?iqE@K9emHih!KjkZsxNx;b-!0^@S+K{>wC`XM5LK|-OSJN zy^&ODV9NdhXWcrYgGRKf9$+3$MDRs6)R{5 zT#)Xz8sO3L|7*cb)&ALY`wp+1T4+j$IC@c*P)6Sn(kIRdBjm9kz5c(%gZL3y70?uh zFp>_|mFv)@dT5LW|1W5yY?c_ht>ii3$|fOluFYj&H_%DnAPqYi!Wvo(%vReTt1Lkf z$nV2nCqTwhs4$w=9ofD+OI^ZOXfUK7XHZCip3IoRty7tuVxcbrH`_GksT1*sIuX+I zdn}~3+QB(E!5MoXZXWbk2waz1&QinF9i~>gFloTpp+uYQGD7=Y)Rp|SCapDYw*|(A z8}s}iHl7{gaL&@lRWR?;Z^0K;0qHHrl^V2L+Le*`mfIG7cb`E8q?X6tgicmMQ`is7 znWIF{9r2s9W>JXhc;PnWA4|QMc}n@}h<34%=f-&zu3=;flpuQS&$y3~_90U`u>rX_ z-M;J?_e1Vy>jm%2-MKGT$&$W9^e(&$@lSibJnsDhBSaD!3^?Zw{ATt0uVgL=?@<*4 zDx&Ba--1zG2>E@Uew;YSf@q~2{dKNXp1HfnLW#S?86fm3sib`1U|Z%tuk^oi=XT^? z!3WM|i`OT69DRFw-V$YTmV?5@1L=}969nCQNtc#?xbg-tt+zXoB`*^wI#B^I`yZ=c z>}fEe`8h-+!73p|-y1Jx-vwgP$YPCp_I4O_OUYHuMU%z}+K9r{=CY!GJ5Xll9Mi1x zV_A-ZmYf~3(>Ho=tg3lrCMfH&pPWv4`Ze282d=5;1$3iQRN-g5WZ4-nH1kpoEDqd5 zYsiy&aftqMn>Zk5*_CWW7}y%{%!f;n$mQ`GCZ(VYR62TXoW8&2LmWCar6^wc>EW5Q zosB*Qk$%oCwZJg{%R-{j=FLY9+O;gA0ctFGX{S>EVrJxK+5VhmY3nL4p{{0s8gNk5z-N6F zq!2GVW95+o(_R(tjNHz_>f@Dt$nQ&D92De~>*ug3=w&ZI!B1zE=wFuG5~$ZTJJbZ0 z?!ZAbu;m+sN}?D1aIY~+VtTG11}1vh+H%8ihd4L~eEj_r6K@;Mas7iD<|r-63b0zt zR9{eE+JaBPWU8CbWW>0kk=~s(_cGG!3^y@~`bqcH3mrg4lkV1atOZ63UT}lworY>+ zlqEPcA(LUl>D2I$+kIv3gkOVh45PH(E#b-{22aSCIwj+L;8U`D>l~ssel>LvKd^Cu2l54UorQ{al{`E@zZ)8jT=Wyxv^JJb7_t zpML7>RW;5hnKoiw{1k-cK7DljjS3NkT#9}oc|VtbDq~h#Wet#n0>+0S&o04O^QL4TOQ6k5Q?XR06gnn$)rn^xXKrTkMaGlm=EEg zFpG6aSw2ICE$3a!>s;1y6`}`UZ8o;*%>ugyuokFG&X|nX6upG_Oaq05KAXTAm4ZWi zLev#6I4<;I$Egkj@=dzT4)OrpP`nEMW}qJ@bzePMzxed(KAV;=y@}og3~#|U_L#Nz zr;E|A3(pVEX$m?mJ}e0?Fy%&|>O4f5Jig&NFH;j;#n?iIx`FHD$2Y4bE%eE{Lt8`u zBWzdgh$Hm3tCR)q)q7^1K@rD@P-};+CH-Tmx-Eh1>XtkjG5BMVQ?sAJ;(~JYCTpKs zn7sX5syq=oZKlm$ zfw$0%q2;zP40@+Q%JH%le`S(8$wTuuj(>|E9XGO8K)Jb;V{OsNi@nb4DtN%4A3`vQ7E*MtXrQ)pPm?Rlt`&&ilH%Gm)hH6|q2j zwx;+}`%|{%M4}6|1jMfG4jiS-)qreV)jwO=ht|AH`Bk9vzwwf`$QaTygknr`QR#&K zZI`L1mpmoMIbZvj`H2e!C*O6+Gz8h7bL++MQQ*PtQx?HzHYd)>pSF@pqixUU5A*6* zP}E#f``VK_m^>aJYFPopZEQFuR7y_jmp^+Py(nZnA(kV>&9yEB9_S}jCjmjH2FHMK z#tR+xZL44qit09c`OyKfMRu2S&QIvEcU?0hf%f{P6k`9>0r&>HJ#Idt#jYnXki(P2 zy$jWs2bIVO#fS61?D!{H?|X!fN9@HsMT?qW|7F>XEXj8sdO&-AmgN}9Qcod%u{khs zmqZZPzA8zGrY(O}2Adz@Ou*=|NH-!sF0-Y4+*PG^SQ}W8Rx4;xVAA}WN^!U^mlWA4 zq1-d>c}8!C{aY+Y^$B;ru9x3a#oiYe<1K^#;Fyq3Npttq0=m%yO}R*4^Ur*7UnHgC zFZE)G|G_HMe(J;%L;h&JJs_u;VE3rwUS*j0aK;~lqp*Rs$3gXq0V`8|wgBmlsA{`i zYy!tHeA~pxNP!)<>cwTUc}J7aOeM()nvw`Wm6WZ5AN7{^BWxp3pahQndEEn$u|Gb3 zv((ZS@X#MMxUFZ*(&ZSy^*r2hgcG?j9o-$YmpOR6_Pn-W?W7izV-M6@jw)sO#!s*S zJX=he#<3vLTBIA4j*uoLIYo&8i|HF{2k!iAqiYUt1+>VLUH85;KM23mN21Owl(|-V zBZvq#zDzv>CB97Yw4GQmQKs4C_l6=p1`6kACz!rItz6 z#YXZBUvpV@0RMYS%~R2K(VtPr7HhX@`TR<3F`2!L1R37yNsQC|y5ViWYTbL{9#L-$a1O(OC0+^?1R0>H@RXYKCZ6TAx^cWn>6!1Q7=1C-m%8hO6#xAyNb+*8N#` z1qY75=J6%=tG~lm*;2o52!7~CJP&F4LzqpvstK}>tVGqCZ-TJw(54uWF>|hX_B4+D zzwOTb=xg4}_u*d$t4j}GG<|W)Xw>!>N=*`GlZjBypj#wMU*~EFb74G`rkI_&R42XV z20=%Yj1&Z3nQZyXZz0&xEM_X42Z@cKDXRplE#S(JjNML$#EUe*PxZ=!1jNY^}I87tzQ9JIw!`%i=zaOzB(qXxHENMz^NB4BEwo%Mh;KA+(N8bHc zMuK7vQ<$x(aoP2NLq~#>J`mim#|lB(+F&V@G$Dq5I;34Evp< zFL}w5VlK3gVH-XG&mXWY$lXZ{HNcj&UQL+=c#yRPDzn5NJ)JTgKm?9=RQylvPnnJI z*9U8^%5xb2E)x0bMzaIy7E|743@WQ|6%SvX|3Q25p zi^Z8<-^A(nU?(|Mu7;uYhWM5xh1xS~sB7Ll^u^n-dysPjfH765crC74eZQrup$!XG z)SELT&Ua9u0lwd$`*2Q9i%aV3IL$Q9Oj(WQoz$lWzSlGOc&ZmggWfX#u2J|W@<*L2 zzr+JwxYL)xocH#$5o>3RM_NR1E-LAsnB|M}c(_8UTSyh7V9*d^7aM4p=(>qhG~aG^ zK50sS@yw@Dw0}S3JL{L0mK@v?ckPfKe!lnnug&mKx?Vg-*=*)#8)!;I-uTgIuu@&5 zy9=US@Uk!YH&B10 O(3lvR-$WX?MgJd&$OdNs literal 0 HcmV?d00001 diff --git a/src/images/text_images/O.png b/src/images/text_images/O.png new file mode 100644 index 0000000000000000000000000000000000000000..c0cc972ad641d61181a66c2858e783b6f6ead93a GIT binary patch literal 7912 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 S?#+Gx0000Y`X9O literal 0 HcmV?d00001 diff --git a/src/images/text_images/P.png b/src/images/text_images/P.png new file mode 100644 index 0000000000000000000000000000000000000000..57ec50124111d42dffe70bec13bb3d7487843791 GIT binary patch literal 5914 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 N002ovPDHLkV1kMUAfNyM literal 0 HcmV?d00001 diff --git a/src/images/text_images/R.png b/src/images/text_images/R.png new file mode 100644 index 0000000000000000000000000000000000000000..090646f5d6690043e424755a6f039ad23379595c GIT binary patch literal 6404 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/S.png b/src/images/text_images/S.png new file mode 100644 index 0000000000000000000000000000000000000000..444419cf0d38b0b6f03a567558a54831fab69811 GIT binary patch literal 7826 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/T.png b/src/images/text_images/T.png new file mode 100644 index 0000000000000000000000000000000000000000..ace7b36b257305def81f8856ac85fdbe798dfa6a GIT binary patch literal 4793 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 ShpVT13SCXZM^)E&HB3ksGXp`uS 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 K6jAaPq5lIkL3H8( literal 0 HcmV?d00001 diff --git a/src/images/text_images/X.png b/src/images/text_images/X.png new file mode 100644 index 0000000000000000000000000000000000000000..be919fc4b9003ea5d3e15c7bacd1aad66a292c8c GIT binary patch literal 7367 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/Y.png b/src/images/text_images/Y.png new file mode 100644 index 0000000000000000000000000000000000000000..4819bbd197ec6177f5a2cc3d575e77a108a1f405 GIT binary patch literal 6459 zcmZ9RbzD=?-^b|=rI9HhC=G(r2#!!f+5rj-1Qh9xDLq0Og#nVHAn6c^(F~-dks6Gi zbj?j*FyfiN=lA^c{Bh6yN5NZ3of-ssB53{_3pL+@|O7!glTQJ0H;Cy9YyWo^l6l+F4?O<)`7G+0m^!_0lKjiutiKKiBBj zhL3C^0ZXq}CHR&oTwKMx9UO%IQe}1JjlqBJt!m;;z{V!*Uj%#)1CW;Mg=UB0QUH2W z=)G()juQq86Ovt^Q zi@P$_-#2<{CO^zv@S%VU1a5>XbU4{HFH%ME#zHHL(Kxy!}Iys&fjCg+NuxJBcgCvG$~tf43&uHO^s z&mGH|-dObD%596fYUsS-w)xWyF=k~p9pgdF&Fi#DeI;+p<{UC* zZTN45>@#Q>#ZZga!#h@Fwck(nDK-=Ne;(32Y|gDBI~3o&X1_oEcFZ<5F?GzZffJMs zf7S7rGw!JK?0P6(=tr4*2B%+|!+i^NUCUWyT~O(_h4s$!eRaZBM{Gegy+G>o?h0yp zkzPV6O6d;DCufY0NzDCWNLgC;p`WQ^iXu7y3xjylTVRSD(}Xg1!IC*gyk+gL0jieN zSWk4+uB?()Sj=4~^5cZZ$p&o_V}38&Y{D!V@nOUl%Zy@nQU~J9{;^0UNFC zLE`sv^=G;yN)QO?|LiGR?j&klurl&cJ^co|d?}6UhFEPSXy7Rr?^yH5-L;&4yUkBo zm1e|JA9y&ck!)0;r^r{Cx^OoLhIom~vQrUEOpg3;0 z+GTlT@fmpAYy^flXJIkuu2s<6KC;CRR5(qk6_cVL=z6G zBJ&>$rLGWA)ht6_YDL&F+==>LCF{r*nMgM8*Ql?AC}sb^`lu(8(w`Tv){zm^p45|_ zv{~h_?AZ@#<2*{5ikliu%C0tPpY3jKQ`c4R&2grGMo;Kj^rpnY!Gu4^TB<;;JeBSO1Sf3@cq=dZxWsy(~>_c!idl#Gz$>Gj}t>nH6e zSG=oZ3%Ng)tX5_m62TAN{~k_w|EZ28@k;%wmc?Qogt>VqN0uMop$^t;uc%NldjBcR zQ_a5_77<;hUI#3B`F`||jffV+vPBEnFF)R=0JN5Cr&x!^*Btu2T?A50MK>M1(p3>% zX$qSi*yuHY>vdie|A>Bru-N|k#ifk!glq|dK`GC#YyaV`QBe1%{b?x5@Lr%i&BV){ zO~`h~?{Tx-XaKd*9rOLip;+ph!Yw(Iowe6!Yg(GlUi;L$Qpr;_UA1PKs=3w5*nZ@v zhjv$CaDBy9Fjkphf<6tnfma&PwKD`VevlpWlL283qfz&Icvc0}5A^kFw<;<&#ic5Z zwd^jZ#WT%nHEK0q50!+T94coCH0~zX^Z?zlFqselt9Eb=VB09|rnZR2p5)i1z6rc- znV&8G+WhK+Da!jaF`ak0jS_K`p*16(>Q5c-M=fw1T+i0_jG}g);ak z?9w>gTHcnK$lFPR0L7mqJ{p!m}&XI<1f1ZcdSAGt~d%Vm2Ea+H}FD9tvumH44_X6eDgyDwrQ0m7e zVJr2?S&h*p;?F#{OpNg4j!%Ly9Q{TP5?%$YVG#MCU39^a5o$YOZP;(!a~(bIyUK`* z384MMWRIa#fa50Leo-}$s*jz2=n&xLSqcKk< zlC7|4+0F|7F>}xrG`ORdZlX0qGZS%qf7a$GPQr^n1XzIG7f8}Kc{-vxn1d~U#8zO< z>#m?b(kd0cl8*Ot%~ZZIj~WW)kIv0#h%JUb<~ufY7vrC+o+p?@ifz)gE8j|n)>&|H zm9(%jJD%Hq5DLCg9V(KKAK&p)*&lzHs<89%(uL21P$TpsxXX$#@Y`c9eTGKXZn(eP z5zd)b!J4OXbujgMQ+c!_W?0SN$P%`(HdXnEEXRknq$|kIWjIkmQ!-yH)0;T7MAei0U@lY`Q@^g2nP&Tm(1RWd=?)sk4W}7!YcW$rtMiTQ$NV zm{xE9sSfpEq!!-ZcD&xqX^$z# zDHNc|Z9)t~h?L74zBzbThsyph`?}AkftSXme?lZjmYx|?iCz5lxBpSOiazdK`#e*b zpL#j=r~X{H$8MfX?II+EsI}|?X?^#1%irQxM%9(bqD9J)+$)29t2G-D#tQ;6L1P8T zIAeV@H%n1P6?0rG4PlHP7kKa*K+=$Cve0q*Ii%MTL zt1|7eggpj?G%6aHF6lG^%`2Sw&`$L>aoC+of7=@;9K|79+^^c}VFUpCC-mMudpKW_ zOPdxwlstzk0?uLFYSMyabdBx?TD=jPG(eu0{5D^$RitE9my$tjk!;v^A>PDdYR}%J zkfo@bEbjNrP>i+$mM*S9-Z5)RtWM^Rk>a%JBU#8Mvqv?uASn~HOtUQ1k=Gz|O_1hx zPpl<5zuU@m+t%~t%Ah`k#*@W+(*ZemYuT#@hf`20+&@aY0$9oIS{{M-5h>J*-@I`9 zRx5MB%Vll*%ll4;dwC-=EJfG4=uVpW{Ib+px>i=*B1*yUVOsx~C`;pdKP9+1p`3*)&XHCimd`^8!jb`bNq_UMZ5*EaHHTVVG&G{U$Dxw#W{ z8uu25*d3rx>c-@{fl6mP$B}&enOSK6Yu}tTq4%Ax{!&^qS@wwgiEgx)z^;yvyzKW= zpkq@0R$=wHXmfAsCXSQ5a9DKo*`M&?S9{Klrk}0V*aOogdn{6SdYt@g3bj zK=5)Y@&%%QFmyRPko8v2a@(Vy=nx+f@6M@(zs{1PK379B6}Oh;EJ z@j@cx#Hy^RmUF#jMnv3Hhh(cu)lQwu%b?~P=wc<#rCXk%RD_L#fk6+I>%oVk#Rsf+ ztoK;Ze8HFFINSz!Dnvi6GMpDOVIt#`_Q1wB^xQp~invF9=2P6cj~kZ&wFFp3S6>nl zEs@qYR%~I3Lft|xObwVkwMp`B`|nQ_%hG(;hVwj`6C|eT1(fq9oM4bWdI<0m`#U1V92-Sb!A9#6DYIy*Q7hHi{)Q~v*Ecw9 z#JKv;czWavUCiFVC3(B^-&xS*cic_BXp8Q0#iF&LlrfA|JL_&mL~V7&r2)46bEG2U z68+70^rLVBs?)o*eOF8_P8u-N5j&$i5!vym`iM_U|l;ItQ7PqJEX(JdH zpUnt$_Eo#I&xt;vw0gLhXL*Z-EwZDzyd7i{g|TC7B@VBg4DVbV*_9ojVE>x)Wg`Nz zxISlNv6xxf4ZMl%l0bgpO5OBSV@64g#g0)n5j_K(z){y*BJd5-PV= zZY~2d)+DDhFR3rwTB?THcOp{@*fK3yQM9R*g<4( zw%BO(-tHMwWHD-h8b)6)J90tK^S!DTy4XV2dry-Oi&R5aa_?-w6j|6@hX}}W-IoBN z%u(vBh1Fw#>Dl_b;hAW-9r=i|p~dKe2KmKG%4v49v~rx@3T2Z2-Mdnc-=P!og#vdg z_{U-PpSGP*hn7K=41_lJh?#v}@S~VhvCe$+FywHJL`XV<{#W-cp1kX0T< zZ02RRJf8J-%<`^zWZMjR?udz%2w`(LU1pk9(}hqM+0_DJ&u8pE>-LfC5c*+kN1+~8 zUp2J26Cu;8brCs63PXoMqW}}*p@UdS>yaVf;tMUG3SQ9lmer0h8Si8a`vAa5O*`{a zHI>ZnWbsVd6Cn|zl*BI>>iOGk%<5c!ATIhrHr6V5iwfz0oBGeffc9@v6H(Ib@+S}CC5?o00 zUI!38=vaXNBRwT0axpP8bFA01OgadiSZ|D)3QBEZ>%89CmNEab1 z31q~6c7E?)8WB-z{JJSuaeDm~oG!tZbJLFHO!0uSy(eT`jOti}I^;qDfzc|IXw6du z$qXAtlp)4~Wj_qvj#D;m{5cUj)2G#SVjZ~=6kIF+&87AXk{+e>x5A-hEGhOj;DJY6 z$TrQ>57kSQ^VrXxr{*Tm+DBYB1@gxCFt;AQc|}zIb9qAfhL>dt1>bSo{<;25jH?DED2B9r1GntqSmBi~40#?)ZZ@YC1X6 zj50V?#>=gfugy$0(5+~pN8e=${D(BoTl8Z$@HNJ960VM+aWt5q&i&L4WMHsZNr3vZ zh}ZiY^Auj9+m&^ z1C7yx_u^9ipUe^0G#7*7mlf?YO`}Ud&l&)Voxurt z7&@(urW$ddG$w+{Zypj$H6FFhp0-(3!k*teRpw*pk$6SD?i>K2_e~OF%D2n6o;D?| zE+FvKSB^GzqJH^zexWn1`818pI7PH2Q{OYYV^KAHz()J?ZK`RTu&Ue2j}x4lE->;+ z5x8pF{LX(Zpc@*#;pt3z{}w>Rd{amd-ssi8De!e>TLEqo-#n#5O#H3&&Jpk&*(!%e zeFO)U2SW_L-!Oyb8r{U_rEYBht^dI1#V0)S+?4Q2J^1H8en>*zDk&DFZ=oh{Ib#1y z^WDC?If}9B8+eLDl##WYl99LoVboBS_DPGP5S(jcMdZM*iCtpL^x&r8Eg+ zM}BLzkoD@q9HJe;9z6T6R=ad9BUFQV9OAlP3u&VHD2&Jd&cW&gzS^kSeiIvbQzNI- zzi*YsW!npEZJ~obQz>;MkP@>s#_~PRwhw3}C`N)TNOQ8tI4E`|`wyP1v$v~I064?z532snR0=2Fu=;J7g=5`4|pV!uy>TSq+6f; zepB-aD54TjX^P32;}Q&cMQp;s)ff}lC8Z7~9yB*U^%=2etoULB7I@1; zPr?O4sx<#5sHo)+G1-TX3Qj?i*;;?6wlR>j`uu2psr(7qka(!%{c5!klk?E~te+}e zZwuFs+`~7l)JvIttK0Pd%gssqJY1V$_!U#v^Ch3&QkB~ee~oWU&grPLetMk6_oKE? zFvOk+#TWp(e@d{*zzg{jb;9|hVFarHgR!v8Rz`fHCYMhvAQ)B=Mrsr4s{($DQm!`U z=$p~39vYU5u+kkRBpF0LR;eGLsU}ymm^5}2i~Ns(d~pxyM!;$FQ&YjBNcsQZ+sFy$ z-v#)F$YfHiVuWw8$h`(b2*P_Cr{F4O!RNt8fO;KZkSm_}dhS_ex=5S_Q=eFamc zh({s^6AP55-ey&x=#|an|FJhFNIps?u_r*k^$jUg4>{Zxq^U91^;>(yLu>klQ4w+B z_c06!mFMai+c4=d?C0r$yS-BTD9h@JCorL=~6iOTnOauVz zfvp4e;p)u7GfKLcJm^eEgYO#io-vD>&V-v{c3pzx5+p|&Me46WDvu{*(;-_=uSJ*< z0yC3jQ9eAbfbPM&K54yhihGvK3GKm4`&+9w0~aS-aoEt~(Lq*a7KgR^uMUwE^ZZ9* zx>22bTtz(30L77H^1{Tu#deI740_hinqH~C!H@idQKhn0h|1ULl+aeAmf(rxQrUy! zg1bC?lmoEQn2l9|VKv5$4Y*_MIXmf#l$9iMxKhPP5$#W(q)x46avFGeI)<=Jmb?>M zzr=f>xuKxT9T+E(8cpdFj}R?PLNGgwrpKMrty7>6@(*kta2-;5SeHjw>dVInKR*Yy z*goV*_P7d-nRj*Qat`jry)*eO<0ibgaIK@wYpT}khSj$OP>a*vsAo6scF0+ky2!zk zPKp6q{QW)QSs98@$LEnAbOHth)46VZalaBkT?&qkEEa=h-gbL lQ7T>SFN%BNtQ&nv%gzPmTmlzllYWYj>FF40!!_-r{s-(B?mhqj literal 0 HcmV?d00001 diff --git a/src/images/text_images/Z.png b/src/images/text_images/Z.png new file mode 100644 index 0000000000000000000000000000000000000000..7d1c8e016888f107ae07afa9f570de3945b86ba5 GIT binary patch literal 6166 zcmY*dc{tSV_qLBcYj#EZD%M(bKosq)9zY%k~`iVCDH~mNZ@>K0hc~`_iYTM($-&+-LfuZsqfv zi+>~B7Z9UCxZ&LQizgC}?JE1Zvwk?lC_*9N5vHRm=90nWMde_Gap|GTr;U!fI+ALW zdQt0iI|#Eg3qd}`bElSGj^+j_>6nnLv$$vOG}+sEhz@Qtd3N*YqT5BugQw;d=a{&w zS7osUKyIsW0VDC6s#oY*mL@4ypEPc>=ANf3mFUBOvr(#@!NHWYDBjtnU%YQlKB~*P zmV`4tN=BZ3P_V3gWvKCL)wV?kcMOQyy3J%gQj-`E6#GM{@tGi)_$Y2-JtC>=N-gM&~kt-J8a zlG$1_ss7fw!~tSiNl8?h2r3wMKk#1DrJuI+6q0cB_eR(Uy}C(`Zn5SBxkYyuJ?cFa z;I0geE2*^m<@=_>mpmB1hrTuJSJsGhEn&IL#WugW7naS*#tX9JuV6#{jK8_X$uju+ zYi*6i3yn&bzu(cO%ltICUeMAypCTUFDZc}IRQq2h*P{)-&Gl{9Nut*+|8CEI`D3N( zmOZ!7?yM^94w~EZ%8LBgqaIHqgQ;Kjjjo2$D$YN&iVo$4v)u^x()}gh)2H`KWj0ap zJ=&wgh&TSI>r}*bU$N&O?{v$6)aKBCkT30@(oQVob;EN2e_F6h?ytUvwOd7z`5!>* zfcW053!WT+l$tTp@o5WRQb{;N1x6H$ zv!rgFwK7$gav#7ve{p@u;Y~TLJeWQd_fO^!v10VP7m0W6{tc;wuZ?laSAO60Oq5$3 zG-wgcyeL>-UIA?W9_(Y0O3>#g8S{eRT>Z@vK8I=hRW_N!+_!^yG-9f9cpv&#q~SIb zJ9An=>?=)=KHo}FS(x$bS~cDB{k)OmRMha{d&T66RKIE0Xa04$7nMaHYNjnndK$CAaprE&%JeU->janAKfjxC ze-9%(ha2T$(qja_L<+X4r}-*biM6=zsQQhpDs&+8tI#a7bRq63cH1X=RnOnjHL|(N z7qHCDK45f2gn0e6&U{|px*hCqeI>t6|9Jy38*0Uyv=4cIqYdKa1se;INnA*NOg*xJ3Q+B2a?`GK;!^M^Y^dZdc7X{TrWDe5 z5{fG52Z(*+fgXSsBZ);T8-wg5mN>yThP?{;XwkxOpDA>9Y!wy#Vw5Lr#vlGLR`@r( zV>5&`?}=-rseB8ro_6-Y6>8fZzwhOB$^tnkzwU6|Ufc&;Yd(BF7NCjO`k~^aDgO0v zNL@=wjAmz&^ibSJwtet%2a#Ul@xnj+=IKA2IX_5fK3S7{KULU*7TCXev5A*lt*ofP zOQ>uR`tOyd(MjkY7O~0Jr6N-Zsse*8GkMH9=mgDrrkS_9yx&-*;8g|p2qF@u4?U22 zS4&Vg)u$9}|BjQhysrGbOMehX{NdR)S8k}-_CJ~PLY7S&7km7r@m5OM12#+(ULQS;e&2IFf~lIt?4rrQF{^G zH5DQAEa#z~HrvBxrZzO=ryrR8ENtGZgF~L$Q~}!gkn$M6D}fKqhsD`f_R)~+hfvG= z(BF;6w+{|YtZLG2PT%v6yUK45VMd$ix}N$C%dxwlFs-EdkU|vSP|*&Zj85R*1aAB| zTwP-^UUf5k^wMKqZo=0z5Ue%bzR~rFy9*aPXT>wK&p-B<6<04! zG4*9`1%i~|Z_0EmzgVNeko(ZPImXI7W|MVhA=;O99oNM1Ky95Bb2%N0OB25mpLL|y zj+A^Xd{II|Ao8&4I8H!$Z7OUdb-Jvlk(gd`wz3DcjLYD)l<>=+z-kf`i%}EF8EO_^ z#-=*FgrD^6_)m-F)*f&1;_9n+ox|%YKf3OhOOK41-WbKDr;69?0MTC?&^T)?gqyK< z!HHQ1X{I0B80%_TJ3d~NyH48=3BmIW7`uS{@-Iao?gVem<_{bH+}Ie*Aq>wCH+;U7K`PYp2S8#7FLlA#iXyuI7T06In~v9sKA{86*N)I zH-_6thzQbRz$|Yzkk0m0M-9q~yii`9*nDsKlb(!VRtHn5RyD?tTo&*4ai67-8;@8= zt5}tUK0R4@=Sbc{-W$1vMG58f|Iu#Lf953(Pkn}OPY@Z3KdQW~Y2ie7)~Q_Tf(L$0 z>^5ya`F>++(Gna(*zFGVH#bfFPD(hntbh5Xiw0-7t-6)+B3G~ZIfqU3pdgV%1p^* z|8Y^CG{>u#rF!WnVcZ}S{NmD32|Lp|fWZDCIUp~kM*Df63bK{aS&Lsy{x-0q$nE|# zu=c~ZeWi#p@JpaVztV^J)pAprwb!U8iYR-tTom8x{jQy9P4WZd0EhdLy^3%%&u6RW z6G~W__4Qp?}FFO<7S`=!AC|+_${o`SuBx5mYXA2Gt?fY2xaI6pHaiupy z>*+$49`7|4CElb%yHA0>i8^~fzjTURIyC>o0Y0;KA_$ES?u3`0JDTOXbb?Y zXkCo(eOjdVAL5JBFj26}mDx6Vp9vnI;|$1)JY-$si@05tcTzxe?q|!W?^`@DV zVRzWAOI6gw4xx~9-mtUwBSPow9z?j{hga1u@kb**m0N}Ue zc~?;HWRpe2WB>KtPJjXgbh5YzK+oHY@d?NC=P9!VC7^iN_XUOPe1pA>Yt_)LEFrMS z9$RxGVHfX(cX}(pxSrFt$RppS;*aASfANvDqECH0uj}^-pp^Gxd$k4QHahD4f7SMC zAIFQRE%WVZ;TqEu3%^jZ16o5k3 zT0JT$0&p%3onitLnACad#n_RnW=?mO11bRy^yo&GpTWS$j(2n!z1qxiW>GXG0+GSk zs8&t$6w`?xeSxKZmq#H&FGCODGX$NC5UG{tIv|-m?$UYxtGNuF)`8#>h6^u(5vD=6w$!W9 zAt=PBDWsZf=LS1_+5FWatCM;c)>Sq>d)LVzlQO}OB66onXIyD<#@PXPXQ^nzzN=7| z`AYdWX-Qb>7;Gn@lPD2!<6!dwfFuQ|L!bZep$p)bmHw<{6%X+I_J3toeqN1Ilc!da zJbjT_H}BjuDr=$0(f+=~daQVKeyu{6<25h+X`k^@X~;u)&*0cg>_2u>pzObovy;c{ zEy!pjO4JRYKYebuLr7I^sV_)cERIrBs6xfaG%iOh32nmlEGI|Tvryj5Wu)C!oNEtI z=_O)V;QRW`JJt8d-;S_L7>$nhJPG;&BrCb};>N65@LW`2GA1sxHpWGMS?K{omQ4|K;~b> z2>=Lm+PmSIWo}z6VHfOhM)qdb-1Rs!25AfMTlNhW31mnK6OTEU5(|t#C*&`kVj9(u z%raG+K<8q(Zo1S5V8Qa*a9pl-wPR4-yrUV1Jv?abCJP6<4x^fBk)tM5=Ri5q92aHKBb2 zhA^Cen22(`U|3%((7}0joEA~h40T4aZF>NS4{`5 zr|rcB4aW+a1lc|C_pIvG<|3!1(D=6f zoJX@MYyr^6!`(anbqcUlXN2!{33jfpehU_n7W-v#%iB4PN198sms?QxpjsUyUk5@> z7f-4~Iiw!$Ix8~TL1P!B?C&AhYBaDT zJ-~txm3X7&&0W2D%gHuo{t^L$?*B!_Aw4-H zGAG3}ptOS2NTqyDn+?lhn{aFwbYhkw(ADb7m$?8nq<9}1xIMGC#`RW_WaiGvKQtyp z7O%y}nb_9~NM#Bl(cG#37_j91`d;-Q*~`;5mO>>gDKbQyv@WvqS!wI|7U}N=v)^Kd z`xdxs4)Fji_)#3j!JrkXN&@)>5o(r;h*S*`H!<6j?!r#f6M14EhG5_1^hB6{^reC>(yD(^Xg|xEfAjo*q__#=pkGBqc^be{ zFI}*b@LIW6N4WSXKzl~1Sj^bBY<+oN&`|AAc~ZcDq;Ln>wNs%@vT7@{op$c%(?R{V z8jk9?{O&!Nrw>u~-H7cP9&hna^^wo%QBQQv!rFzLl6n(g$i=kvR+F3Ux(eT@j@+K7 zJABAD+CsbB|c|U%Z_i57^#wY)kgK@AZcv^9P>X$iQUqf(21G$PCvL#Hq z%6ln4B=m1B=W6b$L+*+Uv8p~Zh{*p48Xbw_r`C6=q`~uu`76iq znJ^xh+a*0fvuT+@8F$Fx9Y_;e4MR$DO+Ycyy@3SnGnjn+mT`kOfP?)cMNw-K_5|#n z)T=GkKNMC|!V4&3bZ99R1^mtlE^3nIp%`aD%=0!r5W_-IDR*A;WEt$CPZEb_?U@+@ zn!kQ%o_x^_*dOdaxt%KfpqXZ_tA|7Ff8r}c;_<=c6<-}6?3U!72LgcI zohufezjJrG4TW_>STHVwe<&sITmb#`jCl8<0M{`r`#9HI9;nBw=Cy58YV@4NZN9hgN^@Cf}P zz$K;Mn<4-nh5M6&ctmP)UaWy!-h_Qf0_wU3MjdH-=Bjb&LxrcfL=vuczl1b%ne)0_ zsK{B-3UKT7K#{6nlTUkS^>8e;)Ig;Q z#Xd6b4g?;$#nvm+=YQC)OAAETHZ48p-*mel_ln_%aPoBOJnU;~5YAtEx6PXQm*}-O z;DIf~+VYoL$BnQWL7i^WmWpQ*qg&D=y@qsx_FIK+;n<#b{IE&TtKPzoL*;dnZG46> zgwL7`-}w1=vgB)2S8zkrBO`*?fIL0p5`D+HRP_ZQDyKAzPp`gECRe8ti!XOz{O<=?{EF|tx5I15^ z?>>U!4NMf^-Lv0pLMI>pFo%hd||G2kL3DibjU=7-DRz=$|ag+PV9*DN!Kbo z$<#=WeOxC>(CifMw+Ktj++M->u!8IAgQ*|eRtml#&)C$#w(vnSeL24B$t8;|&Nu2A z(m{^QqkY;l2nK@CR88mk{e8hXYu2T8OO4W5pJuuT1u^2%t}UVA{Iiu0E@#!u5R-$8 zf`y7Nwe)0MdqE3JxRyTJKg$4H{n`^j7tnd6M+oCfEs7}g0VOYGnE8l*wT}Ge3*~Tg zwGHe7He_d!1oG|wrkJi`Jf1Af+jN9`PX>64@>};+*nd89S8m>uqO7DfuMsV}Xei6( ztJ@NN3N)^+)pwm2yTlSxC&iuPKDB Date: Tue, 17 Sep 2019 20:14:26 +0530 Subject: [PATCH 105/306] code fixes for PR#11 --- src/bitmessagekivy/mpybit.py | 8 ++-- src/bitmessagemain.py | 76 +++++++++++++++++++++--------------- src/identiconGeneration.py | 16 ++++++-- src/pyelliptic/openssl.py | 41 ++++++++++++------- 4 files changed, 90 insertions(+), 51 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index be4be868..e3225c8c 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,5 +1,7 @@ -"""Coding: utf-8.""" -# pylint: disable=relative-import, too-many-lines +""" +src/bitmessagekivy/mpybit.py +================================= +""" import os import time from functools import partial @@ -53,7 +55,7 @@ import queues from semaphores import kivyuisignaler import state from uikivysignaler import UIkivySignaler -# pylint: disable=unused-argument, too-few-public-methods +# pylint: disable=unused-argument, too-few-public-methods, import-error if platform == 'linux': diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 6d80ced0..7a8fc475 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,8 @@ -#!/usr/bin/python2.7 +""" +src/bitmessagemain.py +================================= +""" +# !/usr/bin/python2.7 # Copyright (c) 2012-2016 Jonathan Warren # Copyright (c) 2012-2019 The Bitmessage developers # Distributed under the MIT/X11 software license. See the accompanying @@ -11,16 +15,6 @@ import os import sys - -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) - - -import depends - -depends.check_dependencies() - import ctypes import getopt import multiprocessing @@ -38,6 +32,7 @@ from helper_startup import ( from singleinstance import singleinstance import defaults +import depends import shared import knownnodes import state @@ -67,8 +62,15 @@ from network.uploadthread import UploadThread # Helper Functions import helper_threading +app_dir = os.path.dirname(os.path.abspath(__file__)) +os.chdir(app_dir) +sys.path.insert(0, app_dir) + +depends.check_dependencies() + def connectToStream(streamNumber): + """Connecting to stream""" state.streamsInWhichIAmParticipating.append(streamNumber) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -109,6 +111,7 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): + """inet ntop""" if family == socket.AF_INET: if len(host) != 4: raise ValueError("invalid IPv4 host") @@ -130,6 +133,7 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): + """inet pton""" buf = "\0" * 28 lengthBuf = pack("I", len(buf)) if stringToAddress(str(host), @@ -175,16 +179,18 @@ def signal_handler(signum, frame): if shared.thisapp.daemon or not state.enableGUI: shutdown.doCleanShutdown() else: - print('# Thread: %s(%d)' % (thread.name, thread.ident)) + print '# Thread: %s(%d)' % (thread.name, thread.ident) for filename, lineno, name, line in traceback.extract_stack(frame): - print('File: "%s", line %d, in %s' % (filename, lineno, name)) + print 'File: "%s", line %d, in %s' % (filename, lineno, name) if line: - print(' %s' % line.strip()) - print('Unfortunately you cannot use Ctrl+C when running the UI' - ' because the UI captures the signal.') + print ' %s' % line.strip() + print 'Unfortunately you cannot use Ctrl+C when running the UI \ + because the UI captures the signal.' -class Main: +class Main: # pylint: disable=no-init, old-style-class + """Main Method""" + @staticmethod def start_proxyconfig(config): """Check socksproxytype and start any proxy configuration plugin""" @@ -206,7 +212,8 @@ class Main: 'Started proxy config plugin %s in %s sec', proxy_type, time.time() - proxyconfig_start) - def start(self): + def start(self): # pylint: disable=too-many-statements, too-many-branches, too-many-locals + """Start the main method""" _fixSocket() config = BMConfigParser() @@ -274,7 +281,7 @@ class Main: if daemon: with shared.printLock: - print('Running as a daemon. Send TERM signal to end.') + print 'Running as a daemon. Send TERM signal to end.' self.daemonize() self.setSignalHandler() @@ -397,7 +404,7 @@ class Main: if state.curses: if not depends.check_curses(): sys.exit() - print('Running with curses') + print 'Running with curses' import bitmessagecurses bitmessagecurses.runwrapper() @@ -415,8 +422,7 @@ class Main: if daemon: while state.shutdown == 0: time.sleep(1) - if ( - state.testmode and time.time() - state.last_api_response >= 30): + if (state.testmode and time.time() - state.last_api_response >= 30): self.stop() elif not state.enableGUI: from tests import core as test_core # pylint: disable=relative-import @@ -430,7 +436,9 @@ class Main: else 0 ) - def daemonize(self): + @staticmethod + def daemonize(): + """Daemonize""" grandfatherPid = os.getpid() parentPid = None try: @@ -440,7 +448,7 @@ class Main: # wait until grandchild ready while True: time.sleep(1) - os._exit(0) + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass @@ -461,7 +469,7 @@ class Main: # wait until child ready while True: time.sleep(1) - os._exit(0) + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass @@ -482,12 +490,15 @@ class Main: os.kill(parentPid, signal.SIGTERM) os.kill(grandfatherPid, signal.SIGTERM) - def setSignalHandler(self): + def setSignalHandler(self): # pylint: disable=no-self-use + """Set Signal Handler""" signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # signal.signal(signal.SIGINT, signal.SIG_DFL) - def usage(self): + @staticmethod + def usage(): + """getting usages""" print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' print ''' Options: @@ -499,13 +510,15 @@ Options: All parameters are optional. ''' - def stop(self): + def stop(self): # pylint: disable=no-self-use + """Stopping Bitmessage Deamon""" with shared.printLock: - print('Stopping Bitmessage Deamon.') + print 'Stopping Bitmessage Deamon.' shutdown.doCleanShutdown() - # TODO: nice function but no one is using this - def getApiAddress(self): + # ..todo: nice function but no one is using this + def getApiAddress(self): # pylint: disable=no-self-use + """Getting Api Addresses""" if not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'apienabled'): return None @@ -515,6 +528,7 @@ All parameters are optional. def main(): + """Start of main thread""" mainprogram = Main() mainprogram.start() diff --git a/src/identiconGeneration.py b/src/identiconGeneration.py index 2465c030..dfafbfb7 100644 --- a/src/identiconGeneration.py +++ b/src/identiconGeneration.py @@ -1,9 +1,15 @@ +""" +src/identiconGeneration +================================= +""" import hashlib from PIL import Image from kivy.core.image import Image as CoreImage -# Core classes for loading images and converting them to a Texture. The raw image data can be keep in memory for further access from kivy.uix.image import Image as kiImage from io import BytesIO +""" Core classes for loading images and converting them to a Texture. +The raw image data can be keep in memory for further access """ + # constants RESOLUTION = 128, 128 @@ -13,6 +19,7 @@ MODE = "RGB" def generate(Generate_string=None): + """Generating string""" hash_string = generate_hash(Generate_string) color = random_color(hash_string) image = Image.new(MODE, V_RESOLUTION, BACKGROUND_COLOR) @@ -32,20 +39,22 @@ def generate(Generate_string=None): def generate_hash(string): + """Generating hash""" try: # make input case insensitive string = str.lower(string) hash_object = hashlib.md5(str.encode(string)) - print(hash_object.hexdigest()) + print hash_object.hexdigest() # returned object is a hex string return hash_object.hexdigest() except IndexError: - print("Error: Please enter a string as an argument.") + print "Error: Please enter a string as an argument." def random_color(hash_string): + """Getting random color""" # remove first three digits from hex string split = 6 rgb = hash_string[:split] @@ -62,6 +71,7 @@ def random_color(hash_string): def generate_image(image, color, hash_string): + """Generating images""" hash_string = hash_string[6:] lower_x = 1 diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 7fb78233..c7048dac 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -1,4 +1,15 @@ -#!/usr/bin/env python +""" +src/pyelliptic/openssl.py +================================= +""" + +import sys +import ctypes +from kivy.utils import platform + +OpenSSL = None + +# !/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2011 Yann GUIBET @@ -6,13 +17,9 @@ # # Software slightly changed by Jonathan Warren -import sys -import ctypes -OpenSSL = None -from kivy.utils import platform - -class CipherName: +class CipherName: # pylint: disable=old-style-class + """Getting CipherName""" def __init__(self, name, pointer, blocksize): self._name = name self._pointer = pointer @@ -24,16 +31,20 @@ class CipherName: " | Function pointer : " + str(self._pointer) def get_pointer(self): + """Getting pointer""" return self._pointer() def get_name(self): + """Getting Name""" return self._name def get_blocksize(self): + """Getting blocksize""" return self._blocksize def get_version(library): + """Getting versions""" version = None hexversion = None cflags = None @@ -64,14 +75,11 @@ def get_version(library): return (version, hexversion, cflags) -class _OpenSSL: - """ - Wrapper for OpenSSL using ctypes - """ +class _OpenSSL: # pylint: disable=too-many-instance-attributes, old-style-class, too-many-statements + """Wrapper for OpenSSL using ctypes""" + def __init__(self, library): - """ - Build the wrapper - """ + """Build the wrapper""" self._lib = ctypes.CDLL(library) self._version, self._hexversion, self._cflags = get_version(self._lib) self._libreSSL = self._version.startswith("LibreSSL") @@ -594,6 +602,7 @@ class _OpenSSL: """ returns the name of a elliptic curve with his id """ + # pylint: disable=redefined-builtin res = None for i in self.curves: if self.curves[i] == id: @@ -607,6 +616,7 @@ class _OpenSSL: """ OpenSSL random function """ + # pylint: disable=redefined-builtin buffer = self.malloc(0, size) # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is # evidently possible that it returned an error and not-actually-random data. However, in @@ -623,6 +633,7 @@ class _OpenSSL: """ returns a create_string_buffer (ctypes) """ + # pylint: disable=redefined-builtin buffer = None if data != 0: if sys.version_info.major == 3 and isinstance(data, type('')): @@ -634,6 +645,8 @@ class _OpenSSL: def loadOpenSSL(): + """Loading OpenSSL""" + # pylint: disable=global-statement, protected-access, too-many-branches global OpenSSL from os import path, environ from ctypes.util import find_library From af9afcb3659a5012668b7cc615612f543b457891 Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 18 Sep 2019 13:14:00 +0530 Subject: [PATCH 106/306] workred on identicon issue for android devices --- src/bitmessagekivy/main.kv | 2 +- src/bitmessagekivy/mpybit.py | 20 +++++++++----------- src/buildozer.spec | 3 ++- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 78b52d97..b69b633a 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -650,7 +650,7 @@ NavigationLayout: do_scroll_x: False BoxLayout: orientation: 'vertical' - padding: [dp(app.window_size[0]/4*1.1), dp(10)] + padding: [dp(app.window_size[0]/16 if app.window_size[0] <= 720 else app.window_size[0]/4*1.1), dp(10)] spacing: 12 size_hint_y: None height: self.minimum_height + dp(app.window_size[1]) if app.window_size[1] > app.window_size[0] else dp(app.window_size[0]) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index e3225c8c..a3ce0960 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -57,9 +57,10 @@ import state from uikivysignaler import UIkivySignaler # pylint: disable=unused-argument, too-few-public-methods, import-error - -if platform == 'linux': - import identiconGeneration +import identiconGeneration +import os +from kivy.core.clipboard import Clipboard +# pylint: disable=unused-argument, too-few-public-methods def toast(text): @@ -1028,8 +1029,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def getCurrentAccountData(self, text): """Get Current Address Account Data.""" - if platform == 'linux': - self.set_identicon(text) + self.set_identicon(text) address_label = self.current_address_label( BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label @@ -1089,10 +1089,9 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def getDefaultAccData(self): """Getting Default Account Data.""" if BMConfigParser().addresses(): - if platform == 'linux': - img = identiconGeneration.generate(BMConfigParser().addresses()[0]) - self.createFolder('./images/default_identicon/') - img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) + img = identiconGeneration.generate(BMConfigParser().addresses()[0]) + self.createFolder('./images/default_identicon/') + img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' @@ -1109,8 +1108,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def get_default_image(): """Getting default image on address""" if BMConfigParser().addresses(): - if platform == 'linux': - return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) return '' @staticmethod diff --git a/src/buildozer.spec b/src/buildozer.spec index 25080ba6..9ed79860 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -44,7 +44,8 @@ requirements = bitmsghash, kivymd, kivy-garden, - qrcode + qrcode, + Pillow # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes From c86ab075b7f6a7bdf7f88ae1f0bdc9856b727716 Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 18 Sep 2019 14:39:29 +0530 Subject: [PATCH 107/306] added sending message feature for android --- src/bitmsghash/bitmsghash.cpp | 46 +++++++++++++++++------------------ src/buildozer.spec | 3 ++- src/class_singleWorker.py | 1 + src/messagetypes/__init__.py | 7 ++++-- src/tr.py | 20 ++++++--------- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index 7c2188e6..ce305ebf 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -78,7 +78,7 @@ void getnumthreads() #ifdef _WIN32 DWORD_PTR dwProcessAffinity, dwSystemAffinity; #elif __linux__ - // cpu_set_t dwProcessAffinity; + cpu_set_t dwProcessAffinity; #elif __OpenBSD__ int mib[2], core_count = 0; int dwProcessAffinity = 0; @@ -87,13 +87,13 @@ void getnumthreads() int dwProcessAffinity = 0; int32_t core_count = 0; #endif - // size_t len = sizeof(dwProcessAffinity); - // if (numthreads > 0) - // return; + size_t len = sizeof(dwProcessAffinity); + if (numthreads > 0) + return; #ifdef _WIN32 GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); #elif __linux__ - // sched_getaffinity(0, len, &dwProcessAffinity); + sched_getaffinity(0, len, &dwProcessAffinity); #elif __OpenBSD__ len2 = sizeof(core_count); mib[0] = CTL_HW; @@ -106,22 +106,22 @@ void getnumthreads() else if (sysctlbyname("hw.ncpu", &core_count, &len, 0, 0) == 0) numthreads = core_count; #endif -// for (unsigned int i = 0; i < len * 8; i++) -// #if defined(_WIN32) -// #if defined(_MSC_VER) -// if (dwProcessAffinity & (1i64 << i)) -// #else // CYGWIN/MINGW -// if (dwProcessAffinity & (1ULL << i)) -// #endif -// #elif defined __linux__ -// if (CPU_ISSET(i, &dwProcessAffinity)) -// #else -// if (dwProcessAffinity & (1 << i)) -// #endif -// numthreads++; -// if (numthreads == 0) // something failed -// numthreads = 1; -// printf("Number of threads: %i\n", (int)numthreads); + for (unsigned int i = 0; i < len * 8; i++) +#if defined(_WIN32) +#if defined(_MSC_VER) + if (dwProcessAffinity & (1i64 << i)) +#else // CYGWIN/MINGW + if (dwProcessAffinity & (1ULL << i)) +#endif +#elif defined __linux__ + if (CPU_ISSET(i, &dwProcessAffinity)) +#else + if (dwProcessAffinity & (1 << i)) +#endif + numthreads++; + if (numthreads == 0) // something failed + numthreads = 1; + printf("Number of threads: %i\n", (int)numthreads); } extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) @@ -146,7 +146,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # else pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); # ifdef __linux__ - pthread_setschedparam(threads[i], 0, &schparam); + pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); # else pthread_setschedparam(threads[i], SCHED_RR, &schparam); # endif @@ -162,4 +162,4 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un free(threads); free(threaddata); return successval; -} +} \ No newline at end of file diff --git a/src/buildozer.spec b/src/buildozer.spec index 9ed79860..444bf8ca 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -45,7 +45,8 @@ requirements = kivymd, kivy-garden, qrcode, - Pillow + Pillow, + msgpack # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 5c33af58..ca8c0b95 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -1213,6 +1213,7 @@ class singleWorker(StoppableThread): powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) + print("nonce calculated value#############################", nonce) logger.info( '(For msg message) Found proof of work %s Nonce: %s', trialValue, nonce diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 06783eac..ad1aee9c 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,7 +1,10 @@ from importlib import import_module from os import path, listdir from string import lower - +try: + from kivy.utils import platform +except: + platform = '' from debug import logger import messagetypes import paths @@ -32,7 +35,7 @@ def constructObject(data): else: return returnObj -if paths.frozen is not None: +if paths.frozen is not None or platform == "android": import messagetypes.message import messagetypes.vote else: diff --git a/src/tr.py b/src/tr.py index 0d9643a8..af42145e 100644 --- a/src/tr.py +++ b/src/tr.py @@ -13,28 +13,24 @@ class translateClass: else: return self.text -# def _translate(context, text, disambiguation = None, encoding = None, n = None): -# return translateText(context, text, n) - def _translate(context, text, disambiguation = None, encoding = None, n = None): - return text + return translateText(context, text, n) + +# def _translate(context, text, disambiguation = None, encoding = None, n = None): +# return translateClass(context, text.replace('%','',1)) def translateText(context, text, n = None): try: enableGUI = state.enableGUI except AttributeError: # inside the plugin enableGUI = True - if enableGUI: + if not state.kivy and enableGUI: try: from PyQt4 import QtCore, QtGui except Exception as err: - try: - if state.kivy: - pass - except Exception as err: - print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' - print 'Error message:', err - os._exit(0) + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' + print 'Error message:', err + os._exit(0) if n is None: return QtGui.QApplication.translate(context, text) else: From 65ebb5d670e206eea13ce790d1352806f2994ef3 Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 18 Sep 2019 15:39:20 +0530 Subject: [PATCH 108/306] move identiconGeneration into kivy folder --- src/{ => bitmessagekivy}/identiconGeneration.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => bitmessagekivy}/identiconGeneration.py (100%) diff --git a/src/identiconGeneration.py b/src/bitmessagekivy/identiconGeneration.py similarity index 100% rename from src/identiconGeneration.py rename to src/bitmessagekivy/identiconGeneration.py From 581ef84ffa67b43386d4f491623222ca27c94737 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 18 Sep 2019 14:16:09 +0530 Subject: [PATCH 109/306] Code Fixes 2 regarding PR#11 --- src/bitmessagekivy/identiconGeneration.py | 2 +- src/bitmessagekivy/mpybit.py | 12 ++++-------- src/bitmessagemain.py | 24 +++++++++++------------ src/pyelliptic/openssl.py | 14 ++++++------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/bitmessagekivy/identiconGeneration.py b/src/bitmessagekivy/identiconGeneration.py index dfafbfb7..43e0dbc5 100644 --- a/src/bitmessagekivy/identiconGeneration.py +++ b/src/bitmessagekivy/identiconGeneration.py @@ -1,5 +1,5 @@ """ -src/identiconGeneration +src/identiconGeneration.py ================================= """ import hashlib diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a3ce0960..0f67cc06 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -5,6 +5,7 @@ src/bitmessagekivy/mpybit.py import os import time from functools import partial +import identiconGeneration from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlQuery from kivy.app import App @@ -57,16 +58,12 @@ import state from uikivysignaler import UIkivySignaler # pylint: disable=unused-argument, too-few-public-methods, import-error -import identiconGeneration -import os -from kivy.core.clipboard import Clipboard -# pylint: disable=unused-argument, too-few-public-methods - def toast(text): """Method will display the toast message.""" + # pylint: disable=redefined-outer-name if platform == 'linux': - from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name + from kivymd.toast.kivytoast import toast toast(text) return @@ -104,7 +101,7 @@ class Inbox(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox list for Inbox messages.""" - # pylint: disable=too-many-locals + # pylint: disable=too-many-locals, unused-variable if state.searcing_text: where = ['subject', 'message'] what = state.searcing_text @@ -1866,7 +1863,6 @@ class Draft(Screen): 'draft', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) - state.msg_counter_objs = src_object.children[2].children[0].ids state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 7a8fc475..929961f9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -70,7 +70,7 @@ depends.check_dependencies() def connectToStream(streamNumber): - """Connecting to stream""" + """Method helps us to connect with the stream""" state.streamsInWhichIAmParticipating.append(streamNumber) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -111,7 +111,7 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): - """inet ntop""" + """Method converts an IP address in packed binary format to string format""" if family == socket.AF_INET: if len(host) != 4: raise ValueError("invalid IPv4 host") @@ -133,7 +133,7 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): - """inet pton""" + """Method converts an IP address in string format to a packed binary format""" buf = "\0" * 28 lengthBuf = pack("I", len(buf)) if stringToAddress(str(host), @@ -189,7 +189,7 @@ def signal_handler(signum, frame): class Main: # pylint: disable=no-init, old-style-class - """Main Method""" + """Method starts the proxy config plugin""" @staticmethod def start_proxyconfig(config): @@ -213,7 +213,7 @@ class Main: # pylint: disable=no-init, old-style-class proxy_type, time.time() - proxyconfig_start) def start(self): # pylint: disable=too-many-statements, too-many-branches, too-many-locals - """Start the main method""" + """This method helps to start the daemon""" _fixSocket() config = BMConfigParser() @@ -276,7 +276,7 @@ class Main: # pylint: disable=no-init, old-style-class # is the application already running? If yes then exit. try: shared.thisapp = singleinstance("", daemon) - except Exception as e: + except Exception: pass if daemon: @@ -438,7 +438,7 @@ class Main: # pylint: disable=no-init, old-style-class @staticmethod def daemonize(): - """Daemonize""" + """Running as a daemon. Send signal in end.""" grandfatherPid = os.getpid() parentPid = None try: @@ -491,14 +491,14 @@ class Main: # pylint: disable=no-init, old-style-class os.kill(grandfatherPid, signal.SIGTERM) def setSignalHandler(self): # pylint: disable=no-self-use - """Set Signal Handler""" + """Setting the Signal Handler""" signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # signal.signal(signal.SIGINT, signal.SIG_DFL) @staticmethod def usage(): - """getting usages""" + """After passing argument, method displays the usages""" print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' print ''' Options: @@ -511,14 +511,14 @@ All parameters are optional. ''' def stop(self): # pylint: disable=no-self-use - """Stopping Bitmessage Deamon""" + """Method helps to stop the Bitmessage Deamon""" with shared.printLock: print 'Stopping Bitmessage Deamon.' shutdown.doCleanShutdown() # ..todo: nice function but no one is using this def getApiAddress(self): # pylint: disable=no-self-use - """Getting Api Addresses""" + """This method returns the Api Addresses""" if not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'apienabled'): return None @@ -528,7 +528,7 @@ All parameters are optional. def main(): - """Start of main thread""" + """Start of the main thread""" mainprogram = Main() mainprogram.start() diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index c7048dac..0fc445e6 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -2,7 +2,6 @@ src/pyelliptic/openssl.py ================================= """ - import sys import ctypes from kivy.utils import platform @@ -19,7 +18,8 @@ OpenSSL = None class CipherName: # pylint: disable=old-style-class - """Getting CipherName""" + """Method helps to get pointers, name and blocksize""" + def __init__(self, name, pointer, blocksize): self._name = name self._pointer = pointer @@ -31,20 +31,20 @@ class CipherName: # pylint: disable=old-style-class " | Function pointer : " + str(self._pointer) def get_pointer(self): - """Getting pointer""" + """Method returns the pointer""" return self._pointer() def get_name(self): - """Getting Name""" + """Method returns the name""" return self._name def get_blocksize(self): - """Getting blocksize""" + """Method returns the blocksize""" return self._blocksize def get_version(library): - """Getting versions""" + """Method returns the version of the OpenSSL Library""" version = None hexversion = None cflags = None @@ -645,7 +645,7 @@ class _OpenSSL: # pylint: disable=too-many-instance-attributes, old-style-cl def loadOpenSSL(): - """Loading OpenSSL""" + """Method find and load the OpenSSL library""" # pylint: disable=global-statement, protected-access, too-many-branches global OpenSSL from os import path, environ From 31a73d66bbe479a0bf5b057e5a4789d88d234c2b Mon Sep 17 00:00:00 2001 From: Navjot Date: Thu, 19 Sep 2019 22:00:26 +0530 Subject: [PATCH 110/306] wokred on android device send mail issue or worked on app response issue --- src/bitmessagekivy/main.kv | 57 ++++++++++++++----- src/bitmessagekivy/mpybit.py | 105 +++++++++++++++++------------------ 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index b69b633a..4ffab336 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -72,61 +72,61 @@ on_text:app.getCurrentAccountData(self.text) Image: source: app.get_default_image() - x: self.width/4 - y: self.parent.y + self.parent.height/2 - self.height + 10 - size: 20, 20 + x: self.width/4-2 + y: self.parent.y + self.parent.height/2 - self.height + 14 + size: 28, 28 ArrowImg: NavigationDrawerIconButton: id: inbox_cnt icon: 'email-open' text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: app.mail_count(self.text) + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' - badge_text: app.mail_count(self.text) + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: draft_cnt icon: 'message-draw' text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' - badge_text: app.mail_count(self.text) + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Starred" icon:'star' - on_release: app.root.ids.scr_mngr.current = 'inbox' + on_release: app.root.ids.scr_mngr.current = 'starred' on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'archive' text: "Archieve" - on_release: app.root.ids.scr_mngr.current = 'trash' - badge_text: "9+" + on_release: app.root.ids.scr_mngr.current = 'archieve' + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'email-open-outline' text: "Spam" - on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "8+" + on_release: app.root.ids.scr_mngr.current = 'spam' + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' - badge_text: app.mail_count(self.text) + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: allmail_cnt text: "All Mails" icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'allmails' - badge_text: app.mail_count(self.text) + badge_text: "0" on_press: app.check_search_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: @@ -237,7 +237,12 @@ NavigationLayout: id:sc17 Credits: id:sc18 - + Starred: + id:sc19 + Archieve: + id:sc20 + Spam: + id:sc21 : name: 'inbox' @@ -274,6 +279,30 @@ NavigationLayout: id: ml ComposerButton: +: + name: 'starred' + ScrollView: + do_scroll_x: False + MDList: + id: ml + ComposerButton: + +: + name: 'archieve' + ScrollView: + do_scroll_x: False + MDList: + id: ml + ComposerButton: + +: + name: 'spam' + ScrollView: + do_scroll_x: False + MDList: + id: ml + ComposerButton: + : name: 'allmails' FloatLayout: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 0f67cc06..5bc27fe7 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -5,7 +5,6 @@ src/bitmessagekivy/mpybit.py import os import time from functools import partial -import identiconGeneration from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlQuery from kivy.app import App @@ -58,12 +57,16 @@ import state from uikivysignaler import UIkivySignaler # pylint: disable=unused-argument, too-few-public-methods, import-error +import identiconGeneration +import os +from kivy.core.clipboard import Clipboard +# pylint: disable=unused-argument, too-few-public-methods + def toast(text): """Method will display the toast message.""" - # pylint: disable=redefined-outer-name if platform == 'linux': - from kivymd.toast.kivytoast import toast + from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name toast(text) return @@ -101,7 +104,7 @@ class Inbox(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox list for Inbox messages.""" - # pylint: disable=too-many-locals, unused-variable + # pylint: disable=too-many-locals if state.searcing_text: where = ['subject', 'message'] what = state.searcing_text @@ -110,6 +113,11 @@ class Inbox(Screen): queryreturn = kivy_helper_search.search_sql( xAddress, account, "inbox", where, what, False) if queryreturn: + src_mng_obj = state.kivyapp.root.children[2].children[0].ids + src_mng_obj.inbox_cnt.badge_text = str(len(queryreturn)) + state.inbox_count = str(len(queryreturn)) + state.kivyapp.root.ids.sc17.clear_widgets() + state.kivyapp.root.ids.sc17.add_widget(Allmails()) for mail in queryreturn: third_text = mail[3].replace('\n', ' ') data.append({ @@ -124,9 +132,6 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - # img_latter = item['secondary_text'][0].upper() if ( - # item['secondary_text'][0].upper() >= 'A' and item[ - # 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) @@ -192,10 +197,14 @@ class Inbox(Screen): int(state.inbox_count) - 1) msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str( + int(state.all_count) - 1) state.inbox_count = str( int(state.inbox_count) - 1) state.trash_count = str( int(state.trash_count) + 1) + state.all_count = str( + int(state.all_count) - 1) self.ids.ml.remove_widget( instance.parent.parent) toast('Deleted') @@ -753,6 +762,9 @@ class Sent(Screen): state.check_sent_acc = None if queryreturn: + src_mng_obj = state.kivyapp.root.children[2].children[0].ids + src_mng_obj.send_cnt.badge_text = str(len(queryreturn)) + state.sent_count = str(len(queryreturn)) for mail in queryreturn: self.data.append({ 'text': mail[1].strip(), @@ -891,6 +903,9 @@ class Trash(Screen): trash_data = inbox + sent if trash_data: + src_mng_obj = state.kivyapp.root.children[2].children[0].ids + src_mng_obj.trash_cnt.badge_text = str(len(trash_data)) + state.trash_count = str(len(trash_data)) for item in trash_data: meny = ThreeLineAvatarIconListItem( text=item[1], @@ -1199,45 +1214,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods import shutdown shutdown.doCleanShutdown() - @staticmethod - def mail_count(text): - """Counting Mail numbers.""" - if state.association == '': - if BMConfigParser().addresses(): - state.association = BMConfigParser().addresses()[0] - if text == 'Sent': - state.sent_count = str(sqlQuery( - "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and \ - folder = '{0}' ;".format( - text.lower(), state.association))[0][0]) - return state.sent_count - elif text == 'Inbox': - state.inbox_count = str(sqlQuery( - "SELECT COUNT(*) FROM {0} WHERE toaddress = '{1}' and \ - folder = '{0}' ;".format( - text.lower(), state.association))[0][0]) - return state.inbox_count - elif text == 'Trash': - state.trash_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' \ - and folder = 'trash' )+(SELECT count(*) FROM inbox where \ - toaddress = '{0}' and folder = 'trash') AS SumCount".format( - state.association))[0][0]) - return state.trash_count - elif text == 'Draft': - state.draft_count = str(sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and \ - folder = '{0}' ;".format( - text.lower(), state.association))[0][0]) - return state.draft_count - elif text == 'All Mails': - state.all_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' \ - and folder = 'sent' )+(SELECT count(*) FROM inbox where \ - toaddress = '{0}' and folder != 'trash') AS SumCount".format( - state.association))[0][0]) - return state.all_count - @staticmethod def current_address_label(current_add_label=None, current_addr=None): """Getting current address labels.""" @@ -1250,7 +1226,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods first_name = BMConfigParser().get(addr, 'label') f_name = first_name.split() label = f_name[0][:14].capitalize() + '...' if len(f_name[0]) > 15 else f_name[0].capitalize() - address = ' (' + addr[:6] + '...)' + address = ' (' + addr + '...)' return label + address return '' @@ -1317,10 +1293,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def set_identicon(self, text): """This method is use for showing identicon in address spinner""" img = identiconGeneration.generate(text) - img.size = 20, 20 - img.y = self.root.children[2].children[0].ids.btn.children[0].y - img.x = 5 - self.root.children[2].children[0].ids.btn.add_widget(img) + self.root.children[2].children[0].ids.btn.children[1].texture = img.texture @staticmethod def address_identicon(): @@ -1348,6 +1321,7 @@ class GrashofPopup(Popup): def __init__(self, **kwargs): """Grash of pop screen settings.""" super(GrashofPopup, self).__init__(**kwargs) + print("sssssssssssssssssssiiiiiiiiiiiiiiizzzzzzzzzzeeeeee...............", state.screen_density) if state.screen_density[0] <= 720: self.size_hint_y = 0.4 self.size_hint_x = 0.9 @@ -1535,9 +1509,9 @@ class MailDetail(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ received = {};".format(state.sentMailTime)) - msg_count_objs.inbox_cnt.badge_text = str( - int(state.inbox_count) - 1) - state.inbox_count = str(int(state.inbox_count) - 1) + # msg_count_objs.inbox_cnt.badge_text = str( + # int(state.inbox_count) - 1) + # state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].clear_widgets() self.parent.screens[0].add_widget(Inbox()) elif state.detailPageType == 'draft': @@ -1737,6 +1711,9 @@ class Draft(Screen): # state.msg_counter_objs = None if queryreturn: + src_mng_obj = state.kivyapp.root.children[2].children[0].ids + src_mng_obj.draft_cnt.badge_text = str(len(queryreturn)) + state.draft_count = str(len(queryreturn)) for mail in queryreturn: third_text = mail[3].replace('\n', ' ') self.data.append({ @@ -1863,6 +1840,7 @@ class Draft(Screen): 'draft', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) + state.msg_counter_objs = src_object.children[2].children[0].ids state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() @@ -1926,6 +1904,8 @@ class Allmails(Screen): all_mails = inbox + sent_and_draft if all_mails: + state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) + state.all_count = str(len(all_mails)) for item in all_mails: meny = ThreeLineAvatarIconListItem( text=item[1], @@ -2051,3 +2031,20 @@ def avatarImageFirstLetter(letter_string): img_latter = '!' return img_latter + + +class Starred(Screen): + """Starred Screen show widgets of page.""" + + pass + + +class Archieve(Screen): + """Archieve Screen show widgets of page.""" + + pass + +class Spam(Screen): + """Spam Screen show widgets of page.""" + + pass \ No newline at end of file From 8a3074f3ff40b4568b2296f821f996b3c440b994 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 13 Nov 2018 17:03:38 +0200 Subject: [PATCH 111/306] ui-file based Settings dialog --- src/bitmessageqt/__init__.py | 610 +++--------------- src/bitmessageqt/dialogs.py | 11 +- src/bitmessageqt/settings.py | 1150 ++++++++++++++++------------------ src/bitmessageqt/settings.ui | 403 +++++++----- 4 files changed, 872 insertions(+), 1302 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2c5f1485..94c00e38 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -23,7 +23,6 @@ from addresses import decodeAddress, addBMIfNotPresent import shared from bitmessageui import Ui_MainWindow from bmconfigparser import BMConfigParser -import defaults import namecoin from messageview import MessageView from migrationwizard import Ui_MigrationWizard @@ -31,15 +30,12 @@ from foldertree import ( AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget, MessageList_AddressWidget, MessageList_SubjectWidget, Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress) -from settings import Ui_settingsDialog import settingsmixin import support -import debug from helper_ackPayload import genAckPayload from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure import helper_search import l10n -import openclpow from utils import str_broadcast_subscribers, avatarize from account import ( getSortedAccounts, getSortedSubscriptions, accountClass, BMAccount, @@ -47,16 +43,15 @@ from account import ( import dialogs from network.stats import pendingDownload, pendingUpload from uisignaler import UISignaler -import knownnodes import paths from proofofwork import getPowType import queues import shutdown import state from statusbar import BMStatusBar -from network.asyncore_pollchoose import set_rates import sound - +# This is needed for tray icon +import bitmessage_icons_rc # noqa:F401 pylint: disable=unused-import try: from plugins.plugin import get_plugin, get_plugins @@ -64,49 +59,6 @@ except ImportError: get_plugins = False -def change_translation(newlocale): - global qmytranslator, qsystranslator - try: - if not qmytranslator.isEmpty(): - QtGui.QApplication.removeTranslator(qmytranslator) - except: - pass - try: - if not qsystranslator.isEmpty(): - QtGui.QApplication.removeTranslator(qsystranslator) - except: - pass - - qmytranslator = QtCore.QTranslator() - translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale) - qmytranslator.load(translationpath) - QtGui.QApplication.installTranslator(qmytranslator) - - qsystranslator = QtCore.QTranslator() - if paths.frozen: - translationpath = os.path.join (paths.codePath(), 'translations', 'qt_' + newlocale) - else: - translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) - qsystranslator.load(translationpath) - QtGui.QApplication.installTranslator(qsystranslator) - - lang = locale.normalize(l10n.getTranslationLanguage()) - langs = [lang.split(".")[0] + "." + l10n.encoding, lang.split(".")[0] + "." + 'UTF-8', lang] - if 'win32' in sys.platform or 'win64' in sys.platform: - langs = [l10n.getWindowsLocale(lang)] - for lang in langs: - try: - l10n.setlocale(locale.LC_ALL, lang) - if 'win32' not in sys.platform and 'win64' not in sys.platform: - l10n.encoding = locale.nl_langinfo(locale.CODESET) - else: - l10n.encoding = locale.getlocale()[1] - logger.info("Successfully set locale to %s", lang) - break - except: - logger.error("Failed to set locale to %s", lang, exc_info=True) - - # TODO: rewrite def powQueueSize(): """Returns the size of queues.workerQueue including current unfinished work""" @@ -122,9 +74,6 @@ def powQueueSize(): class MyForm(settingsmixin.SMainWindow): - # the last time that a message arrival sound was played - lastSoundTime = datetime.now() - timedelta(days=1) - # the maximum frequency of message sounds in seconds maxSoundFrequencySec = 60 @@ -132,6 +81,58 @@ class MyForm(settingsmixin.SMainWindow): REPLY_TYPE_CHAN = 1 REPLY_TYPE_UPD = 2 + def change_translation(self, newlocale=None): + """Change translation language for the application""" + if newlocale is None: + newlocale = l10n.getTranslationLanguage() + try: + if not self.qmytranslator.isEmpty(): + QtGui.QApplication.removeTranslator(self.qmytranslator) + except: + pass + try: + if not self.qsystranslator.isEmpty(): + QtGui.QApplication.removeTranslator(self.qsystranslator) + except: + pass + + self.qmytranslator = QtCore.QTranslator() + translationpath = os.path.join( + paths.codePath(), 'translations', 'bitmessage_' + newlocale) + self.qmytranslator.load(translationpath) + QtGui.QApplication.installTranslator(self.qmytranslator) + + self.qsystranslator = QtCore.QTranslator() + if paths.frozen: + translationpath = os.path.join( + paths.codePath(), 'translations', 'qt_' + newlocale) + else: + translationpath = os.path.join( + str(QtCore.QLibraryInfo.location( + QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) + self.qsystranslator.load(translationpath) + QtGui.QApplication.installTranslator(self.qsystranslator) + + lang = locale.normalize(l10n.getTranslationLanguage()) + langs = [ + lang.split(".")[0] + "." + l10n.encoding, + lang.split(".")[0] + "." + 'UTF-8', + lang + ] + if 'win32' in sys.platform or 'win64' in sys.platform: + langs = [l10n.getWindowsLocale(lang)] + for lang in langs: + try: + l10n.setlocale(locale.LC_ALL, lang) + if 'win32' not in sys.platform and 'win64' not in sys.platform: + l10n.encoding = locale.nl_langinfo(locale.CODESET) + else: + l10n.encoding = locale.getlocale()[1] + logger.info("Successfully set locale to %s", lang) + break + except: + logger.error("Failed to set locale to %s", lang, exc_info=True) + def init_file_menu(self): QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL( "triggered()"), self.quit) @@ -605,6 +606,13 @@ class MyForm(settingsmixin.SMainWindow): self.ui = Ui_MainWindow() self.ui.setupUi(self) + self.qmytranslator = self.qsystranslator = None + self.indicatorUpdate = None + self.actionStatus = None + + # the last time that a message arrival sound was played + self.lastSoundTime = datetime.now() - timedelta(days=1) + # Ask the user if we may delete their old version 1 addresses if they # have any. for addressInKeysFile in getSortedAccounts(): @@ -620,26 +628,13 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().remove_section(addressInKeysFile) BMConfigParser().save() - # Configure Bitmessage to start on startup (or remove the - # configuration) based on the setting in the keys.dat file - if 'win32' in sys.platform or 'win64' in sys.platform: - # Auto-startup for Windows - RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" - self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat) - self.settings.remove( - "PyBitmessage") # In case the user moves the program and the registry entry is no longer valid, this will delete the old registry entry. - if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): - self.settings.setValue("PyBitmessage", sys.argv[0]) - elif 'darwin' in sys.platform: - # startup for mac - pass - elif 'linux' in sys.platform: - # startup for linux - pass + self.updateStartOnLogon() + + self.change_translation() # e.g. for editing labels self.recurDepth = 0 - + # switch back to this when replying self.replyFromTab = None @@ -828,6 +823,28 @@ class MyForm(settingsmixin.SMainWindow): finally: self._contact_selected = None + def updateStartOnLogon(self): + # Configure Bitmessage to start on startup (or remove the + # configuration) based on the setting in the keys.dat file + if 'win32' in sys.platform or 'win64' in sys.platform: + # Auto-startup for Windows + RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" + self.settings = QtCore.QSettings( + RUN_PATH, QtCore.QSettings.NativeFormat) + # In case the user moves the program and the registry entry is + # no longer valid, this will delete the old registry entry. + self.settings.remove("PyBitmessage") + if BMConfigParser().getboolean( + 'bitmessagesettings', 'startonlogon' + ): + self.settings.setValue("PyBitmessage", sys.argv[0]) + elif 'darwin' in sys.platform: + # startup for mac + pass + elif 'linux' in sys.platform: + # startup for linux + pass + def updateTTL(self, sliderPosition): TTL = int(sliderPosition ** 3.199 + 3600) self.updateHumanFriendlyTTLDescription(TTL) @@ -1622,7 +1639,6 @@ class MyForm(settingsmixin.SMainWindow): # The window state has just been changed to # Normal/Maximised/FullScreen pass - # QtGui.QWidget.changeEvent(self, event) def __icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: @@ -2434,225 +2450,7 @@ class MyForm(settingsmixin.SMainWindow): dialogs.AboutDialog(self).exec_() def click_actionSettings(self): - self.settingsDialogInstance = settingsDialog(self) - if self._firstrun: - self.settingsDialogInstance.ui.tabWidgetSettings.setCurrentIndex(1) - if self.settingsDialogInstance.exec_(): - if self._firstrun: - BMConfigParser().remove_option( - 'bitmessagesettings', 'dontconnect') - BMConfigParser().set('bitmessagesettings', 'startonlogon', str( - self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) - BMConfigParser().set('bitmessagesettings', 'minimizetotray', str( - self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) - BMConfigParser().set('bitmessagesettings', 'trayonclose', str( - self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) - BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', str( - self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked())) - BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str( - self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) - BMConfigParser().set('bitmessagesettings', 'startintray', str( - self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked())) - BMConfigParser().set('bitmessagesettings', 'willinglysendtomobile', str( - self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked())) - BMConfigParser().set('bitmessagesettings', 'useidenticons', str( - self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) - BMConfigParser().set('bitmessagesettings', 'replybelow', str( - self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) - - lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) - BMConfigParser().set('bitmessagesettings', 'userlocale', lang) - change_translation(l10n.getTranslationLanguage()) - - if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): - QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( - "MainWindow", "You must restart Bitmessage for the port number change to take effect.")) - BMConfigParser().set('bitmessagesettings', 'port', str( - self.settingsDialogInstance.ui.lineEditTCPPort.text())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): - BMConfigParser().set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked(): - import upnp - upnpThread = upnp.uPnPThread() - upnpThread.start() - #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText()', self.settingsDialogInstance.ui.comboBoxProxyType.currentText() - #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText())[0:5]', self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': - if shared.statusIconColor != 'red': - QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( - "MainWindow", "Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any).")) - if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': - self.statusbar.clearMessage() - state.resetNetworkProtocolAvailability() # just in case we changed something in the network connectivity - if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': - BMConfigParser().set('bitmessagesettings', 'socksproxytype', str( - self.settingsDialogInstance.ui.comboBoxProxyType.currentText())) - else: - BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') - BMConfigParser().set('bitmessagesettings', 'socksauthentication', str( - self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked())) - BMConfigParser().set('bitmessagesettings', 'sockshostname', str( - self.settingsDialogInstance.ui.lineEditSocksHostname.text())) - BMConfigParser().set('bitmessagesettings', 'socksport', str( - self.settingsDialogInstance.ui.lineEditSocksPort.text())) - BMConfigParser().set('bitmessagesettings', 'socksusername', str( - self.settingsDialogInstance.ui.lineEditSocksUsername.text())) - BMConfigParser().set('bitmessagesettings', 'sockspassword', str( - self.settingsDialogInstance.ui.lineEditSocksPassword.text())) - BMConfigParser().set('bitmessagesettings', 'sockslisten', str( - self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked())) - try: - # Rounding to integers just for aesthetics - BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', str( - int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text())))) - BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str( - int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) - except ValueError: - QtGui.QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( - "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) - else: - set_rates(BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"), - BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate")) - - BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', str( - int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text())))) - - BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', - self.settingsDialogInstance.getNamecoinType()) - BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str( - self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcport', str( - self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcuser', str( - self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( - self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) - self.resetNamecoinConnection() - - # Demanded difficulty tab - if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: - BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: - BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) - - if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): - BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) - queues.workerQueue.put(('resetPoW', '')) - - acceptableDifficultyChanged = False - - if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: - if BMConfigParser().get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): - # the user changed the max acceptable total difficulty - acceptableDifficultyChanged = True - BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: - if BMConfigParser().get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes)): - # the user changed the max acceptable small message difficulty - acceptableDifficultyChanged = True - BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) - if acceptableDifficultyChanged: - # It might now be possible to send msgs which were previously marked as toodifficult. - # Let us change them to 'msgqueued'. The singleWorker will try to send them and will again - # mark them as toodifficult if the receiver's required difficulty is still higher than - # we are willing to do. - sqlExecute('''UPDATE sent SET status='msgqueued' WHERE status='toodifficult' ''') - queues.workerQueue.put(('sendmessage', '')) - - #start:UI setting to stop trying to send messages after X days/months - # I'm open to changing this UI to something else if someone has a better idea. - if ((self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')):#We need to handle this special case. Bitmessage has its default behavior. The input is blank/blank - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '') - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '') - shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') - try: - float(self.settingsDialogInstance.ui.lineEditDays.text()) - lineEditDaysIsValidFloat = True - except: - lineEditDaysIsValidFloat = False - try: - float(self.settingsDialogInstance.ui.lineEditMonths.text()) - lineEditMonthsIsValidFloat = True - except: - lineEditMonthsIsValidFloat = False - if lineEditDaysIsValidFloat and not lineEditMonthsIsValidFloat: - self.settingsDialogInstance.ui.lineEditMonths.setText("0") - if lineEditMonthsIsValidFloat and not lineEditDaysIsValidFloat: - self.settingsDialogInstance.ui.lineEditDays.setText("0") - if lineEditDaysIsValidFloat or lineEditMonthsIsValidFloat: - if (float(self.settingsDialogInstance.ui.lineEditDays.text()) >=0 and float(self.settingsDialogInstance.ui.lineEditMonths.text()) >=0): - shared.maximumLengthOfTimeToBotherResendingMessages = (float(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60) + (float(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12) - if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give zero values to all fields. No message will be sent again. - QtGui.QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate( - "MainWindow", "Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent.")) - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '0') - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '0') - shared.maximumLengthOfTimeToBotherResendingMessages = 0 - else: - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', str(float( - self.settingsDialogInstance.ui.lineEditDays.text()))) - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float( - self.settingsDialogInstance.ui.lineEditMonths.text()))) - - BMConfigParser().save() - - if 'win32' in sys.platform or 'win64' in sys.platform: - # Auto-startup for Windows - RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" - self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat) - if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): - self.settings.setValue("PyBitmessage", sys.argv[0]) - else: - self.settings.remove("PyBitmessage") - elif 'darwin' in sys.platform: - # startup for mac - pass - elif 'linux' in sys.platform: - # startup for linux - pass - - if state.appdata != paths.lookupExeFolder() and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... - # Write the keys.dat file to disk in the new location - sqlStoredProcedure('movemessagstoprog') - with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: - BMConfigParser().write(configfile) - # Write the knownnodes.dat file to disk in the new location - knownnodes.saveKnownNodes(paths.lookupExeFolder()) - os.remove(state.appdata + 'keys.dat') - os.remove(state.appdata + 'knownnodes.dat') - previousAppdataLocation = state.appdata - state.appdata = paths.lookupExeFolder() - debug.resetLogging() - try: - os.remove(previousAppdataLocation + 'debug.log') - os.remove(previousAppdataLocation + 'debug.log.1') - except: - pass - - if state.appdata == paths.lookupExeFolder() and not self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we ARE using portable mode now but the user selected that we shouldn't... - state.appdata = paths.lookupAppdataFolder() - if not os.path.exists(state.appdata): - os.makedirs(state.appdata) - sqlStoredProcedure('movemessagstoappdata') - # Write the keys.dat file to disk in the new location - BMConfigParser().save() - # Write the knownnodes.dat file to disk in the new location - knownnodes.saveKnownNodes(state.appdata) - os.remove(paths.lookupExeFolder() + 'keys.dat') - os.remove(paths.lookupExeFolder() + 'knownnodes.dat') - debug.resetLogging() - try: - os.remove(paths.lookupExeFolder() + 'debug.log') - os.remove(paths.lookupExeFolder() + 'debug.log.1') - except: - pass + dialogs.SettingsDialog(self, firstrun=self._firstrun).exec_() def on_action_Send(self): """Send message to current selected address""" @@ -4253,237 +4051,6 @@ class MyForm(settingsmixin.SMainWindow): obj.loadSettings() -class settingsDialog(QtGui.QDialog): - - def __init__(self, parent): - QtGui.QWidget.__init__(self, parent) - self.ui = Ui_settingsDialog() - self.ui.setupUi(self) - self.parent = parent - self.ui.checkBoxStartOnLogon.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'startonlogon')) - self.ui.checkBoxMinimizeToTray.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray')) - self.ui.checkBoxTrayOnClose.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'trayonclose')) - self.ui.checkBoxHideTrayConnectionNotifications.setChecked( - BMConfigParser().getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) - self.ui.checkBoxShowTrayNotifications.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications')) - self.ui.checkBoxStartInTray.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'startintray')) - self.ui.checkBoxWillinglySendToMobile.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) - self.ui.checkBoxUseIdenticons.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) - self.ui.checkBoxReplyBelow.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) - - if state.appdata == paths.lookupExeFolder(): - self.ui.checkBoxPortableMode.setChecked(True) - else: - try: - import tempfile - tempfile.NamedTemporaryFile( - dir=paths.lookupExeFolder(), delete=True - ).close() # should autodelete - except: - self.ui.checkBoxPortableMode.setDisabled(True) - - if 'darwin' in sys.platform: - self.ui.checkBoxStartOnLogon.setDisabled(True) - self.ui.checkBoxStartOnLogon.setText(_translate( - "MainWindow", "Start-on-login not yet supported on your OS.")) - self.ui.checkBoxMinimizeToTray.setDisabled(True) - self.ui.checkBoxMinimizeToTray.setText(_translate( - "MainWindow", "Minimize-to-tray not yet supported on your OS.")) - self.ui.checkBoxShowTrayNotifications.setDisabled(True) - self.ui.checkBoxShowTrayNotifications.setText(_translate( - "MainWindow", "Tray notifications not yet supported on your OS.")) - elif 'linux' in sys.platform: - self.ui.checkBoxStartOnLogon.setDisabled(True) - self.ui.checkBoxStartOnLogon.setText(_translate( - "MainWindow", "Start-on-login not yet supported on your OS.")) - # On the Network settings tab: - self.ui.lineEditTCPPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'port'))) - self.ui.checkBoxUPnP.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp')) - self.ui.checkBoxAuthentication.setChecked(BMConfigParser().getboolean( - 'bitmessagesettings', 'socksauthentication')) - self.ui.checkBoxSocksListen.setChecked(BMConfigParser().getboolean( - 'bitmessagesettings', 'sockslisten')) - if str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'none': - self.ui.comboBoxProxyType.setCurrentIndex(0) - self.ui.lineEditSocksHostname.setEnabled(False) - self.ui.lineEditSocksPort.setEnabled(False) - self.ui.lineEditSocksUsername.setEnabled(False) - self.ui.lineEditSocksPassword.setEnabled(False) - self.ui.checkBoxAuthentication.setEnabled(False) - self.ui.checkBoxSocksListen.setEnabled(False) - elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': - self.ui.comboBoxProxyType.setCurrentIndex(1) - elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': - self.ui.comboBoxProxyType.setCurrentIndex(2) - - self.ui.lineEditSocksHostname.setText(str( - BMConfigParser().get('bitmessagesettings', 'sockshostname'))) - self.ui.lineEditSocksPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'socksport'))) - self.ui.lineEditSocksUsername.setText(str( - BMConfigParser().get('bitmessagesettings', 'socksusername'))) - self.ui.lineEditSocksPassword.setText(str( - BMConfigParser().get('bitmessagesettings', 'sockspassword'))) - QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL( - "currentIndexChanged(int)"), self.comboBoxProxyTypeChanged) - self.ui.lineEditMaxDownloadRate.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxdownloadrate'))) - self.ui.lineEditMaxUploadRate.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxuploadrate'))) - self.ui.lineEditMaxOutboundConnections.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxoutboundconnections'))) - - # Demanded difficulty tab - self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) - - # Max acceptable difficulty tab - self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) - - # OpenCL - if openclpow.openclAvailable(): - self.ui.comboBoxOpenCL.setEnabled(True) - else: - self.ui.comboBoxOpenCL.setEnabled(False) - self.ui.comboBoxOpenCL.clear() - self.ui.comboBoxOpenCL.addItem("None") - self.ui.comboBoxOpenCL.addItems(openclpow.vendors) - self.ui.comboBoxOpenCL.setCurrentIndex(0) - for i in range(self.ui.comboBoxOpenCL.count()): - if self.ui.comboBoxOpenCL.itemText(i) == BMConfigParser().safeGet('bitmessagesettings', 'opencl'): - self.ui.comboBoxOpenCL.setCurrentIndex(i) - break - - # Namecoin integration tab - nmctype = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') - self.ui.lineEditNamecoinHost.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpchost'))) - self.ui.lineEditNamecoinPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcport'))) - self.ui.lineEditNamecoinUser.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser'))) - self.ui.lineEditNamecoinPassword.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword'))) - - if nmctype == "namecoind": - self.ui.radioButtonNamecoinNamecoind.setChecked(True) - elif nmctype == "nmcontrol": - self.ui.radioButtonNamecoinNmcontrol.setChecked(True) - self.ui.lineEditNamecoinUser.setEnabled(False) - self.ui.labelNamecoinUser.setEnabled(False) - self.ui.lineEditNamecoinPassword.setEnabled(False) - self.ui.labelNamecoinPassword.setEnabled(False) - else: - assert False - - QtCore.QObject.connect(self.ui.radioButtonNamecoinNamecoind, QtCore.SIGNAL( - "toggled(bool)"), self.namecoinTypeChanged) - QtCore.QObject.connect(self.ui.radioButtonNamecoinNmcontrol, QtCore.SIGNAL( - "toggled(bool)"), self.namecoinTypeChanged) - QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( - "clicked()"), self.click_pushButtonNamecoinTest) - - #Message Resend tab - self.ui.lineEditDays.setText(str( - BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) - self.ui.lineEditMonths.setText(str( - BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) - - - #'System' tab removed for now. - """try: - maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') - except: - maxCores = 99999 - if maxCores <= 1: - self.ui.comboBoxMaxCores.setCurrentIndex(0) - elif maxCores == 2: - self.ui.comboBoxMaxCores.setCurrentIndex(1) - elif maxCores <= 4: - self.ui.comboBoxMaxCores.setCurrentIndex(2) - elif maxCores <= 8: - self.ui.comboBoxMaxCores.setCurrentIndex(3) - elif maxCores <= 16: - self.ui.comboBoxMaxCores.setCurrentIndex(4) - else: - self.ui.comboBoxMaxCores.setCurrentIndex(5)""" - - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - def comboBoxProxyTypeChanged(self, comboBoxIndex): - if comboBoxIndex == 0: - self.ui.lineEditSocksHostname.setEnabled(False) - self.ui.lineEditSocksPort.setEnabled(False) - self.ui.lineEditSocksUsername.setEnabled(False) - self.ui.lineEditSocksPassword.setEnabled(False) - self.ui.checkBoxAuthentication.setEnabled(False) - self.ui.checkBoxSocksListen.setEnabled(False) - elif comboBoxIndex == 1 or comboBoxIndex == 2: - self.ui.lineEditSocksHostname.setEnabled(True) - self.ui.lineEditSocksPort.setEnabled(True) - self.ui.checkBoxAuthentication.setEnabled(True) - self.ui.checkBoxSocksListen.setEnabled(True) - if self.ui.checkBoxAuthentication.isChecked(): - self.ui.lineEditSocksUsername.setEnabled(True) - self.ui.lineEditSocksPassword.setEnabled(True) - - # Check status of namecoin integration radio buttons and translate - # it to a string as in the options. - def getNamecoinType(self): - if self.ui.radioButtonNamecoinNamecoind.isChecked(): - return "namecoind" - if self.ui.radioButtonNamecoinNmcontrol.isChecked(): - return "nmcontrol" - assert False - - # Namecoin connection type was changed. - def namecoinTypeChanged(self, checked): - nmctype = self.getNamecoinType() - assert nmctype == "namecoind" or nmctype == "nmcontrol" - - isNamecoind = (nmctype == "namecoind") - self.ui.lineEditNamecoinUser.setEnabled(isNamecoind) - self.ui.labelNamecoinUser.setEnabled(isNamecoind) - self.ui.lineEditNamecoinPassword.setEnabled(isNamecoind) - self.ui.labelNamecoinPassword.setEnabled(isNamecoind) - - if isNamecoind: - self.ui.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) - else: - self.ui.lineEditNamecoinPort.setText("9000") - - def click_pushButtonNamecoinTest(self): - """Test the namecoin settings specified in the settings dialog.""" - self.ui.labelNamecoinTestResult.setText(_translate( - "MainWindow", "Testing...")) - options = {} - options["type"] = self.getNamecoinType() - options["host"] = str(self.ui.lineEditNamecoinHost.text().toUtf8()) - options["port"] = str(self.ui.lineEditNamecoinPort.text().toUtf8()) - options["user"] = str(self.ui.lineEditNamecoinUser.text().toUtf8()) - options["password"] = str(self.ui.lineEditNamecoinPassword.text().toUtf8()) - nc = namecoin.namecoinConnection(options) - status, text = nc.test() - self.ui.labelNamecoinTestResult.setText(text) - if status == 'success': - self.parent.namecoin = nc - - # In order for the time columns on the Inbox and Sent tabs to be sorted # correctly (rather than alphabetically), we need to overload the < # operator and use this class instead of QTableWidgetItem. @@ -4558,7 +4125,6 @@ def init(): def run(): global myapp app = init() - change_translation(l10n.getTranslationLanguage()) app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 1acdbc3f..b4bcd2fd 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -5,22 +5,25 @@ src/bitmessageqt/dialogs.py from PyQt4 import QtGui -from version import softwareVersion - import paths import widgets from address_dialogs import ( - AddAddressDialog, EmailGatewayDialog, NewAddressDialog, NewSubscriptionDialog, RegenerateAddressesDialog, + AddAddressDialog, EmailGatewayDialog, NewAddressDialog, + NewSubscriptionDialog, RegenerateAddressesDialog, SpecialAddressBehaviorDialog ) from newchandialog import NewChanDialog from retranslateui import RetranslateMixin +from settings import SettingsDialog from tr import _translate +from version import softwareVersion + __all__ = [ "NewChanDialog", "AddAddressDialog", "NewAddressDialog", "NewSubscriptionDialog", "RegenerateAddressesDialog", - "SpecialAddressBehaviorDialog", "EmailGatewayDialog" + "SpecialAddressBehaviorDialog", "EmailGatewayDialog", + "SettingsDialog" ] diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 3a3db962..fc96b137 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -1,630 +1,544 @@ -# -*- coding: utf-8 -*- -# pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,attribute-defined-outside-init -""" -src/bitmessageqt/settings.py -============================ +import os +import sys -Form implementation generated from reading ui file 'settings.ui' +from PyQt4 import QtGui -Created: Thu Dec 25 23:21:20 2014 - by: PyQt4 UI code generator 4.10.3 - -WARNING! All changes made in this file will be lost! -""" - -from sys import platform - -from PyQt4 import QtCore, QtGui - -from . import bitmessage_icons_rc # pylint: disable=unused-import -from .languagebox import LanguageBox - -try: - _fromUtf8 = QtCore.QString.fromUtf8 -except AttributeError: - def _fromUtf8(s): - return s - -try: - _encoding = QtGui.QApplication.UnicodeUTF8 - - def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig, _encoding) -except AttributeError: - def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig) +import debug +import defaults +import knownnodes +import namecoin +import openclpow +import paths +import queues +import shared +import state +import tempfile +import widgets +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute, sqlStoredProcedure +from network.asyncore_pollchoose import set_rates +from tr import _translate -class Ui_settingsDialog(object): - """Encapsulate a UI settings dialog object""" +class SettingsDialog(QtGui.QDialog): + """The "Settings" dialog""" + def __init__(self, parent=None, firstrun=False): + super(SettingsDialog, self).__init__(parent) + widgets.load('settings.ui', self) - def setupUi(self, settingsDialog): - """Set up the UI""" + self.parent = parent + self.firstrun = firstrun + self.config = BMConfigParser() - settingsDialog.setObjectName(_fromUtf8("settingsDialog")) - settingsDialog.resize(521, 413) - self.gridLayout = QtGui.QGridLayout(settingsDialog) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.buttonBox = QtGui.QDialogButtonBox(settingsDialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) - self.buttonBox.setObjectName(_fromUtf8("buttonBox")) - self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) - self.tabWidgetSettings = QtGui.QTabWidget(settingsDialog) - self.tabWidgetSettings.setObjectName(_fromUtf8("tabWidgetSettings")) - self.tabUserInterface = QtGui.QWidget() - self.tabUserInterface.setEnabled(True) - self.tabUserInterface.setObjectName(_fromUtf8("tabUserInterface")) - self.formLayout = QtGui.QFormLayout(self.tabUserInterface) - self.formLayout.setObjectName(_fromUtf8("formLayout")) - self.checkBoxStartOnLogon = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxStartOnLogon.setObjectName(_fromUtf8("checkBoxStartOnLogon")) - self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.checkBoxStartOnLogon) - self.groupBoxTray = QtGui.QGroupBox(self.tabUserInterface) - self.groupBoxTray.setObjectName(_fromUtf8("groupBoxTray")) - self.formLayoutTray = QtGui.QFormLayout(self.groupBoxTray) - self.formLayoutTray.setObjectName(_fromUtf8("formLayoutTray")) - self.checkBoxStartInTray = QtGui.QCheckBox(self.groupBoxTray) - self.checkBoxStartInTray.setObjectName(_fromUtf8("checkBoxStartInTray")) - self.formLayoutTray.setWidget(0, QtGui.QFormLayout.SpanningRole, self.checkBoxStartInTray) - self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.groupBoxTray) - self.checkBoxMinimizeToTray.setChecked(True) - self.checkBoxMinimizeToTray.setObjectName(_fromUtf8("checkBoxMinimizeToTray")) - self.formLayoutTray.setWidget(1, QtGui.QFormLayout.LabelRole, self.checkBoxMinimizeToTray) - self.checkBoxTrayOnClose = QtGui.QCheckBox(self.groupBoxTray) - self.checkBoxTrayOnClose.setChecked(True) - self.checkBoxTrayOnClose.setObjectName(_fromUtf8("checkBoxTrayOnClose")) - self.formLayoutTray.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxTrayOnClose) - self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.groupBoxTray) - self.checkBoxHideTrayConnectionNotifications = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxHideTrayConnectionNotifications.setChecked(False) - self.checkBoxHideTrayConnectionNotifications.setObjectName( - _fromUtf8("checkBoxHideTrayConnectionNotifications")) - self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxHideTrayConnectionNotifications) - self.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications")) - self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.checkBoxShowTrayNotifications) - self.checkBoxPortableMode = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxPortableMode.setObjectName(_fromUtf8("checkBoxPortableMode")) - self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.checkBoxPortableMode) - self.PortableModeDescription = QtGui.QLabel(self.tabUserInterface) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.PortableModeDescription.sizePolicy().hasHeightForWidth()) - self.PortableModeDescription.setSizePolicy(sizePolicy) - self.PortableModeDescription.setWordWrap(True) - self.PortableModeDescription.setObjectName(_fromUtf8("PortableModeDescription")) - self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.PortableModeDescription) - self.checkBoxWillinglySendToMobile = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxWillinglySendToMobile.setObjectName(_fromUtf8("checkBoxWillinglySendToMobile")) - self.formLayout.setWidget(6, QtGui.QFormLayout.SpanningRole, self.checkBoxWillinglySendToMobile) - self.checkBoxUseIdenticons = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxUseIdenticons.setObjectName(_fromUtf8("checkBoxUseIdenticons")) - self.formLayout.setWidget(7, QtGui.QFormLayout.LabelRole, self.checkBoxUseIdenticons) - self.checkBoxReplyBelow = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxReplyBelow.setObjectName(_fromUtf8("checkBoxReplyBelow")) - self.formLayout.setWidget(8, QtGui.QFormLayout.LabelRole, self.checkBoxReplyBelow) - self.groupBox = QtGui.QGroupBox(self.tabUserInterface) - self.groupBox.setObjectName(_fromUtf8("groupBox")) - self.formLayout_2 = QtGui.QFormLayout(self.groupBox) - self.formLayout_2.setObjectName(_fromUtf8("formLayout_2")) - self.languageComboBox = LanguageBox(self.groupBox) - self.languageComboBox.setMinimumSize(QtCore.QSize(100, 0)) - self.languageComboBox.setObjectName(_fromUtf8("languageComboBox")) # pylint: disable=not-callable - self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.languageComboBox) - self.formLayout.setWidget(9, QtGui.QFormLayout.FieldRole, self.groupBox) - self.tabWidgetSettings.addTab(self.tabUserInterface, _fromUtf8("")) - self.tabNetworkSettings = QtGui.QWidget() - self.tabNetworkSettings.setObjectName(_fromUtf8("tabNetworkSettings")) - self.gridLayout_4 = QtGui.QGridLayout(self.tabNetworkSettings) - self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) - self.groupBox1 = QtGui.QGroupBox(self.tabNetworkSettings) - self.groupBox1.setObjectName(_fromUtf8("groupBox1")) - self.gridLayout_3 = QtGui.QGridLayout(self.groupBox1) - self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - self.label = QtGui.QLabel(self.groupBox1) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1, QtCore.Qt.AlignRight) - self.lineEditTCPPort = QtGui.QLineEdit(self.groupBox1) - self.lineEditTCPPort.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditTCPPort.setObjectName(_fromUtf8("lineEditTCPPort")) - self.gridLayout_3.addWidget(self.lineEditTCPPort, 0, 1, 1, 1, QtCore.Qt.AlignLeft) - self.labelUPnP = QtGui.QLabel(self.groupBox1) - self.labelUPnP.setObjectName(_fromUtf8("labelUPnP")) - self.gridLayout_3.addWidget(self.labelUPnP, 0, 2, 1, 1, QtCore.Qt.AlignRight) - self.checkBoxUPnP = QtGui.QCheckBox(self.groupBox1) - self.checkBoxUPnP.setObjectName(_fromUtf8("checkBoxUPnP")) - self.gridLayout_3.addWidget(self.checkBoxUPnP, 0, 3, 1, 1, QtCore.Qt.AlignLeft) - self.gridLayout_4.addWidget(self.groupBox1, 0, 0, 1, 1) - self.groupBox_3 = QtGui.QGroupBox(self.tabNetworkSettings) - self.groupBox_3.setObjectName(_fromUtf8("groupBox_3")) - self.gridLayout_9 = QtGui.QGridLayout(self.groupBox_3) - self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) - spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_9.addItem(spacerItem1, 0, 0, 2, 1) - self.label_24 = QtGui.QLabel(self.groupBox_3) - self.label_24.setObjectName(_fromUtf8("label_24")) - self.gridLayout_9.addWidget(self.label_24, 0, 1, 1, 1) - self.lineEditMaxDownloadRate = QtGui.QLineEdit(self.groupBox_3) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxDownloadRate.sizePolicy().hasHeightForWidth()) - self.lineEditMaxDownloadRate.setSizePolicy(sizePolicy) - self.lineEditMaxDownloadRate.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEditMaxDownloadRate.setObjectName(_fromUtf8("lineEditMaxDownloadRate")) - self.gridLayout_9.addWidget(self.lineEditMaxDownloadRate, 0, 2, 1, 1) - self.label_25 = QtGui.QLabel(self.groupBox_3) - self.label_25.setObjectName(_fromUtf8("label_25")) - self.gridLayout_9.addWidget(self.label_25, 1, 1, 1, 1) - self.lineEditMaxUploadRate = QtGui.QLineEdit(self.groupBox_3) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxUploadRate.sizePolicy().hasHeightForWidth()) - self.lineEditMaxUploadRate.setSizePolicy(sizePolicy) - self.lineEditMaxUploadRate.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEditMaxUploadRate.setObjectName(_fromUtf8("lineEditMaxUploadRate")) - self.gridLayout_9.addWidget(self.lineEditMaxUploadRate, 1, 2, 1, 1) - self.label_26 = QtGui.QLabel(self.groupBox_3) - self.label_26.setObjectName(_fromUtf8("label_26")) - self.gridLayout_9.addWidget(self.label_26, 2, 1, 1, 1) - self.lineEditMaxOutboundConnections = QtGui.QLineEdit(self.groupBox_3) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxOutboundConnections.sizePolicy().hasHeightForWidth()) - self.lineEditMaxOutboundConnections.setSizePolicy(sizePolicy) - self.lineEditMaxOutboundConnections.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEditMaxOutboundConnections.setObjectName(_fromUtf8("lineEditMaxOutboundConnections")) self.lineEditMaxOutboundConnections.setValidator( QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) - self.gridLayout_9.addWidget(self.lineEditMaxOutboundConnections, 2, 2, 1, 1) - self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1) - self.groupBox_2 = QtGui.QGroupBox(self.tabNetworkSettings) - self.groupBox_2.setObjectName(_fromUtf8("groupBox_2")) - self.gridLayout_2 = QtGui.QGridLayout(self.groupBox_2) - self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) - self.label_2 = QtGui.QLabel(self.groupBox_2) - self.label_2.setObjectName(_fromUtf8("label_2")) - self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1) - self.label_3 = QtGui.QLabel(self.groupBox_2) - self.label_3.setObjectName(_fromUtf8("label_3")) - self.gridLayout_2.addWidget(self.label_3, 1, 1, 1, 1) - self.lineEditSocksHostname = QtGui.QLineEdit(self.groupBox_2) - self.lineEditSocksHostname.setObjectName(_fromUtf8("lineEditSocksHostname")) - self.lineEditSocksHostname.setPlaceholderText(_fromUtf8("127.0.0.1")) - self.gridLayout_2.addWidget(self.lineEditSocksHostname, 1, 2, 1, 2) - self.label_4 = QtGui.QLabel(self.groupBox_2) - self.label_4.setObjectName(_fromUtf8("label_4")) - self.gridLayout_2.addWidget(self.label_4, 1, 4, 1, 1) - self.lineEditSocksPort = QtGui.QLineEdit(self.groupBox_2) - self.lineEditSocksPort.setObjectName(_fromUtf8("lineEditSocksPort")) - if platform in ['darwin', 'win32', 'win64']: - self.lineEditSocksPort.setPlaceholderText(_fromUtf8("9150")) + + self.adjust_from_config(self.config) + if firstrun: + # switch to "Network Settings" tab if user selected + # "Let me configure special network settings first" on first run + self.tabWidgetSettings.setCurrentIndex( + self.tabWidgetSettings.indexOf(self.tabNetworkSettings) + ) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + def adjust_from_config(self, config): + """Adjust all widgets state according to config settings""" + # pylint: disable=too-many-branches,too-many-statements + self.checkBoxStartOnLogon.setChecked( + config.getboolean('bitmessagesettings', 'startonlogon')) + self.checkBoxMinimizeToTray.setChecked( + config.getboolean('bitmessagesettings', 'minimizetotray')) + self.checkBoxTrayOnClose.setChecked( + config.safeGetBoolean('bitmessagesettings', 'trayonclose')) + self.checkBoxHideTrayConnectionNotifications.setChecked( + config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) + self.checkBoxShowTrayNotifications.setChecked( + config.getboolean('bitmessagesettings', 'showtraynotifications')) + self.checkBoxStartInTray.setChecked( + config.getboolean('bitmessagesettings', 'startintray')) + self.checkBoxWillinglySendToMobile.setChecked( + config.safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) + self.checkBoxUseIdenticons.setChecked( + config.safeGetBoolean('bitmessagesettings', 'useidenticons')) + self.checkBoxReplyBelow.setChecked( + config.safeGetBoolean('bitmessagesettings', 'replybelow')) + + if state.appdata == paths.lookupExeFolder(): + self.checkBoxPortableMode.setChecked(True) else: - self.lineEditSocksPort.setPlaceholderText(_fromUtf8("9050")) - self.gridLayout_2.addWidget(self.lineEditSocksPort, 1, 5, 1, 1) - self.checkBoxAuthentication = QtGui.QCheckBox(self.groupBox_2) - self.checkBoxAuthentication.setObjectName(_fromUtf8("checkBoxAuthentication")) - self.gridLayout_2.addWidget(self.checkBoxAuthentication, 2, 1, 1, 1) - self.label_5 = QtGui.QLabel(self.groupBox_2) - self.label_5.setObjectName(_fromUtf8("label_5")) - self.gridLayout_2.addWidget(self.label_5, 2, 2, 1, 1) - self.lineEditSocksUsername = QtGui.QLineEdit(self.groupBox_2) - self.lineEditSocksUsername.setEnabled(False) - self.lineEditSocksUsername.setObjectName(_fromUtf8("lineEditSocksUsername")) - self.gridLayout_2.addWidget(self.lineEditSocksUsername, 2, 3, 1, 1) - self.label_6 = QtGui.QLabel(self.groupBox_2) - self.label_6.setObjectName(_fromUtf8("label_6")) - self.gridLayout_2.addWidget(self.label_6, 2, 4, 1, 1) - self.lineEditSocksPassword = QtGui.QLineEdit(self.groupBox_2) - self.lineEditSocksPassword.setEnabled(False) - self.lineEditSocksPassword.setInputMethodHints( - QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText) - self.lineEditSocksPassword.setEchoMode(QtGui.QLineEdit.Password) - self.lineEditSocksPassword.setObjectName(_fromUtf8("lineEditSocksPassword")) - self.gridLayout_2.addWidget(self.lineEditSocksPassword, 2, 5, 1, 1) - self.checkBoxSocksListen = QtGui.QCheckBox(self.groupBox_2) - self.checkBoxSocksListen.setObjectName(_fromUtf8("checkBoxSocksListen")) - self.gridLayout_2.addWidget(self.checkBoxSocksListen, 3, 1, 1, 4) - self.comboBoxProxyType = QtGui.QComboBox(self.groupBox_2) - self.comboBoxProxyType.setObjectName(_fromUtf8("comboBoxProxyType")) # pylint: disable=not-callable - self.comboBoxProxyType.addItem(_fromUtf8("")) - self.comboBoxProxyType.addItem(_fromUtf8("")) - self.comboBoxProxyType.addItem(_fromUtf8("")) - self.gridLayout_2.addWidget(self.comboBoxProxyType, 0, 1, 1, 1) - self.gridLayout_4.addWidget(self.groupBox_2, 1, 0, 1, 1) - spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_4.addItem(spacerItem2, 3, 0, 1, 1) - self.tabWidgetSettings.addTab(self.tabNetworkSettings, _fromUtf8("")) - self.tabDemandedDifficulty = QtGui.QWidget() - self.tabDemandedDifficulty.setObjectName(_fromUtf8("tabDemandedDifficulty")) - self.gridLayout_6 = QtGui.QGridLayout(self.tabDemandedDifficulty) - self.gridLayout_6.setObjectName(_fromUtf8("gridLayout_6")) - self.label_9 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_9.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_9.setObjectName(_fromUtf8("label_9")) - self.gridLayout_6.addWidget(self.label_9, 1, 1, 1, 1) - self.label_10 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_10.setWordWrap(True) - self.label_10.setObjectName(_fromUtf8("label_10")) - self.gridLayout_6.addWidget(self.label_10, 2, 0, 1, 3) - self.label_11 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_11.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_11.setObjectName(_fromUtf8("label_11")) - self.gridLayout_6.addWidget(self.label_11, 3, 1, 1, 1) - self.label_8 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_8.setWordWrap(True) - self.label_8.setObjectName(_fromUtf8("label_8")) - self.gridLayout_6.addWidget(self.label_8, 0, 0, 1, 3) - spacerItem3 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_6.addItem(spacerItem3, 1, 0, 1, 1) - self.label_12 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_12.setWordWrap(True) - self.label_12.setObjectName(_fromUtf8("label_12")) - self.gridLayout_6.addWidget(self.label_12, 4, 0, 1, 3) - self.lineEditSmallMessageDifficulty = QtGui.QLineEdit(self.tabDemandedDifficulty) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditSmallMessageDifficulty.sizePolicy().hasHeightForWidth()) - self.lineEditSmallMessageDifficulty.setSizePolicy(sizePolicy) - self.lineEditSmallMessageDifficulty.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditSmallMessageDifficulty.setObjectName(_fromUtf8("lineEditSmallMessageDifficulty")) - self.gridLayout_6.addWidget(self.lineEditSmallMessageDifficulty, 3, 2, 1, 1) - self.lineEditTotalDifficulty = QtGui.QLineEdit(self.tabDemandedDifficulty) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditTotalDifficulty.sizePolicy().hasHeightForWidth()) - self.lineEditTotalDifficulty.setSizePolicy(sizePolicy) - self.lineEditTotalDifficulty.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditTotalDifficulty.setObjectName(_fromUtf8("lineEditTotalDifficulty")) - self.gridLayout_6.addWidget(self.lineEditTotalDifficulty, 1, 2, 1, 1) - spacerItem4 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_6.addItem(spacerItem4, 3, 0, 1, 1) - spacerItem5 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_6.addItem(spacerItem5, 5, 0, 1, 1) - self.tabWidgetSettings.addTab(self.tabDemandedDifficulty, _fromUtf8("")) - self.tabMaxAcceptableDifficulty = QtGui.QWidget() - self.tabMaxAcceptableDifficulty.setObjectName(_fromUtf8("tabMaxAcceptableDifficulty")) - self.gridLayout_7 = QtGui.QGridLayout(self.tabMaxAcceptableDifficulty) - self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7")) - self.label_15 = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.label_15.setWordWrap(True) - self.label_15.setObjectName(_fromUtf8("label_15")) - self.gridLayout_7.addWidget(self.label_15, 0, 0, 1, 3) - spacerItem6 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_7.addItem(spacerItem6, 1, 0, 1, 1) - self.label_13 = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.label_13.setLayoutDirection(QtCore.Qt.LeftToRight) - self.label_13.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_13.setObjectName(_fromUtf8("label_13")) - self.gridLayout_7.addWidget(self.label_13, 1, 1, 1, 1) - self.lineEditMaxAcceptableTotalDifficulty = QtGui.QLineEdit(self.tabMaxAcceptableDifficulty) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxAcceptableTotalDifficulty.sizePolicy().hasHeightForWidth()) - self.lineEditMaxAcceptableTotalDifficulty.setSizePolicy(sizePolicy) - self.lineEditMaxAcceptableTotalDifficulty.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditMaxAcceptableTotalDifficulty.setObjectName(_fromUtf8("lineEditMaxAcceptableTotalDifficulty")) - self.gridLayout_7.addWidget(self.lineEditMaxAcceptableTotalDifficulty, 1, 2, 1, 1) - spacerItem7 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_7.addItem(spacerItem7, 2, 0, 1, 1) - self.label_14 = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.label_14.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_14.setObjectName(_fromUtf8("label_14")) - self.gridLayout_7.addWidget(self.label_14, 2, 1, 1, 1) - self.lineEditMaxAcceptableSmallMessageDifficulty = QtGui.QLineEdit(self.tabMaxAcceptableDifficulty) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxAcceptableSmallMessageDifficulty.sizePolicy().hasHeightForWidth()) - self.lineEditMaxAcceptableSmallMessageDifficulty.setSizePolicy(sizePolicy) - self.lineEditMaxAcceptableSmallMessageDifficulty.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditMaxAcceptableSmallMessageDifficulty.setObjectName( - _fromUtf8("lineEditMaxAcceptableSmallMessageDifficulty")) - self.gridLayout_7.addWidget(self.lineEditMaxAcceptableSmallMessageDifficulty, 2, 2, 1, 1) - spacerItem8 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_7.addItem(spacerItem8, 3, 1, 1, 1) - self.labelOpenCL = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.labelOpenCL.setObjectName(_fromUtf8("labelOpenCL")) - self.gridLayout_7.addWidget(self.labelOpenCL, 4, 0, 1, 1) - self.comboBoxOpenCL = QtGui.QComboBox(self.tabMaxAcceptableDifficulty) - self.comboBoxOpenCL.setObjectName = (_fromUtf8("comboBoxOpenCL")) - self.gridLayout_7.addWidget(self.comboBoxOpenCL, 4, 1, 1, 1) - self.tabWidgetSettings.addTab(self.tabMaxAcceptableDifficulty, _fromUtf8("")) - self.tabNamecoin = QtGui.QWidget() - self.tabNamecoin.setObjectName(_fromUtf8("tabNamecoin")) - self.gridLayout_8 = QtGui.QGridLayout(self.tabNamecoin) - self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) - spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem9, 2, 0, 1, 1) - self.label_16 = QtGui.QLabel(self.tabNamecoin) - self.label_16.setWordWrap(True) - self.label_16.setObjectName(_fromUtf8("label_16")) - self.gridLayout_8.addWidget(self.label_16, 0, 0, 1, 3) - self.label_17 = QtGui.QLabel(self.tabNamecoin) - self.label_17.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_17.setObjectName(_fromUtf8("label_17")) - self.gridLayout_8.addWidget(self.label_17, 2, 1, 1, 1) - self.lineEditNamecoinHost = QtGui.QLineEdit(self.tabNamecoin) - self.lineEditNamecoinHost.setObjectName(_fromUtf8("lineEditNamecoinHost")) - self.gridLayout_8.addWidget(self.lineEditNamecoinHost, 2, 2, 1, 1) - spacerItem10 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem10, 3, 0, 1, 1) - spacerItem11 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem11, 4, 0, 1, 1) - self.label_18 = QtGui.QLabel(self.tabNamecoin) - self.label_18.setEnabled(True) - self.label_18.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_18.setObjectName(_fromUtf8("label_18")) - self.gridLayout_8.addWidget(self.label_18, 3, 1, 1, 1) - self.lineEditNamecoinPort = QtGui.QLineEdit(self.tabNamecoin) - self.lineEditNamecoinPort.setObjectName(_fromUtf8("lineEditNamecoinPort")) - self.gridLayout_8.addWidget(self.lineEditNamecoinPort, 3, 2, 1, 1) - spacerItem12 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_8.addItem(spacerItem12, 8, 1, 1, 1) - self.labelNamecoinUser = QtGui.QLabel(self.tabNamecoin) - self.labelNamecoinUser.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.labelNamecoinUser.setObjectName(_fromUtf8("labelNamecoinUser")) - self.gridLayout_8.addWidget(self.labelNamecoinUser, 4, 1, 1, 1) - self.lineEditNamecoinUser = QtGui.QLineEdit(self.tabNamecoin) - self.lineEditNamecoinUser.setObjectName(_fromUtf8("lineEditNamecoinUser")) - self.gridLayout_8.addWidget(self.lineEditNamecoinUser, 4, 2, 1, 1) - spacerItem13 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem13, 5, 0, 1, 1) - self.labelNamecoinPassword = QtGui.QLabel(self.tabNamecoin) - self.labelNamecoinPassword.setAlignment( - QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.labelNamecoinPassword.setObjectName(_fromUtf8("labelNamecoinPassword")) - self.gridLayout_8.addWidget(self.labelNamecoinPassword, 5, 1, 1, 1) - self.lineEditNamecoinPassword = QtGui.QLineEdit(self.tabNamecoin) - self.lineEditNamecoinPassword.setInputMethodHints( - QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText) - self.lineEditNamecoinPassword.setEchoMode(QtGui.QLineEdit.Password) - self.lineEditNamecoinPassword.setObjectName(_fromUtf8("lineEditNamecoinPassword")) - self.gridLayout_8.addWidget(self.lineEditNamecoinPassword, 5, 2, 1, 1) - self.labelNamecoinTestResult = QtGui.QLabel(self.tabNamecoin) - self.labelNamecoinTestResult.setText(_fromUtf8("")) - self.labelNamecoinTestResult.setObjectName(_fromUtf8("labelNamecoinTestResult")) - self.gridLayout_8.addWidget(self.labelNamecoinTestResult, 7, 0, 1, 2) - self.pushButtonNamecoinTest = QtGui.QPushButton(self.tabNamecoin) - self.pushButtonNamecoinTest.setObjectName(_fromUtf8("pushButtonNamecoinTest")) - self.gridLayout_8.addWidget(self.pushButtonNamecoinTest, 7, 2, 1, 1) - self.horizontalLayout = QtGui.QHBoxLayout() - self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) - self.label_21 = QtGui.QLabel(self.tabNamecoin) - self.label_21.setObjectName(_fromUtf8("label_21")) - self.horizontalLayout.addWidget(self.label_21) - self.radioButtonNamecoinNamecoind = QtGui.QRadioButton(self.tabNamecoin) - self.radioButtonNamecoinNamecoind.setObjectName(_fromUtf8("radioButtonNamecoinNamecoind")) - self.horizontalLayout.addWidget(self.radioButtonNamecoinNamecoind) - self.radioButtonNamecoinNmcontrol = QtGui.QRadioButton(self.tabNamecoin) - self.radioButtonNamecoinNmcontrol.setObjectName(_fromUtf8("radioButtonNamecoinNmcontrol")) - self.horizontalLayout.addWidget(self.radioButtonNamecoinNmcontrol) - self.gridLayout_8.addLayout(self.horizontalLayout, 1, 0, 1, 3) - self.tabWidgetSettings.addTab(self.tabNamecoin, _fromUtf8("")) - self.tabResendsExpire = QtGui.QWidget() - self.tabResendsExpire.setObjectName(_fromUtf8("tabResendsExpire")) - self.gridLayout_5 = QtGui.QGridLayout(self.tabResendsExpire) - self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) - self.label_7 = QtGui.QLabel(self.tabResendsExpire) - self.label_7.setWordWrap(True) - self.label_7.setObjectName(_fromUtf8("label_7")) - self.gridLayout_5.addWidget(self.label_7, 0, 0, 1, 3) - spacerItem14 = QtGui.QSpacerItem(212, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_5.addItem(spacerItem14, 1, 0, 1, 1) - self.widget = QtGui.QWidget(self.tabResendsExpire) - self.widget.setMinimumSize(QtCore.QSize(231, 75)) - self.widget.setObjectName(_fromUtf8("widget")) - self.label_19 = QtGui.QLabel(self.widget) - self.label_19.setGeometry(QtCore.QRect(10, 20, 101, 20)) - self.label_19.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_19.setObjectName(_fromUtf8("label_19")) - self.label_20 = QtGui.QLabel(self.widget) - self.label_20.setGeometry(QtCore.QRect(30, 40, 80, 16)) - self.label_20.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.label_20.setObjectName(_fromUtf8("label_20")) - self.lineEditDays = QtGui.QLineEdit(self.widget) - self.lineEditDays.setGeometry(QtCore.QRect(113, 20, 51, 20)) - self.lineEditDays.setObjectName(_fromUtf8("lineEditDays")) - self.lineEditMonths = QtGui.QLineEdit(self.widget) - self.lineEditMonths.setGeometry(QtCore.QRect(113, 40, 51, 20)) - self.lineEditMonths.setObjectName(_fromUtf8("lineEditMonths")) - self.label_22 = QtGui.QLabel(self.widget) - self.label_22.setGeometry(QtCore.QRect(169, 23, 61, 16)) - self.label_22.setObjectName(_fromUtf8("label_22")) - self.label_23 = QtGui.QLabel(self.widget) - self.label_23.setGeometry(QtCore.QRect(170, 41, 71, 16)) - self.label_23.setObjectName(_fromUtf8("label_23")) - self.gridLayout_5.addWidget(self.widget, 1, 2, 1, 1) - spacerItem15 = QtGui.QSpacerItem(20, 129, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_5.addItem(spacerItem15, 2, 1, 1, 1) - self.tabWidgetSettings.addTab(self.tabResendsExpire, _fromUtf8("")) - self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) + try: + tempfile.NamedTemporaryFile( + dir=paths.lookupExeFolder(), delete=True + ).close() # should autodelete + except: + self.checkBoxPortableMode.setDisabled(True) - self.retranslateUi(settingsDialog) - self.tabWidgetSettings.setCurrentIndex(0) - QtCore.QObject.connect( # pylint: disable=no-member - self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), settingsDialog.accept) - QtCore.QObject.connect( # pylint: disable=no-member - self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), settingsDialog.reject) - QtCore.QObject.connect( # pylint: disable=no-member - self.checkBoxAuthentication, - QtCore.SIGNAL( - _fromUtf8("toggled(bool)")), - self.lineEditSocksUsername.setEnabled) - QtCore.QObject.connect( # pylint: disable=no-member - self.checkBoxAuthentication, - QtCore.SIGNAL( - _fromUtf8("toggled(bool)")), - self.lineEditSocksPassword.setEnabled) - QtCore.QMetaObject.connectSlotsByName(settingsDialog) - settingsDialog.setTabOrder(self.tabWidgetSettings, self.checkBoxStartOnLogon) - settingsDialog.setTabOrder(self.checkBoxStartOnLogon, self.checkBoxStartInTray) - settingsDialog.setTabOrder(self.checkBoxStartInTray, self.checkBoxMinimizeToTray) - settingsDialog.setTabOrder(self.checkBoxMinimizeToTray, self.lineEditTCPPort) - settingsDialog.setTabOrder(self.lineEditTCPPort, self.comboBoxProxyType) - settingsDialog.setTabOrder(self.comboBoxProxyType, self.lineEditSocksHostname) - settingsDialog.setTabOrder(self.lineEditSocksHostname, self.lineEditSocksPort) - settingsDialog.setTabOrder(self.lineEditSocksPort, self.checkBoxAuthentication) - settingsDialog.setTabOrder(self.checkBoxAuthentication, self.lineEditSocksUsername) - settingsDialog.setTabOrder(self.lineEditSocksUsername, self.lineEditSocksPassword) - settingsDialog.setTabOrder(self.lineEditSocksPassword, self.checkBoxSocksListen) - settingsDialog.setTabOrder(self.checkBoxSocksListen, self.buttonBox) + if 'darwin' in sys.platform: + self.checkBoxStartOnLogon.setDisabled(True) + self.checkBoxStartOnLogon.setText(_translate( + "MainWindow", "Start-on-login not yet supported on your OS.")) + self.checkBoxMinimizeToTray.setDisabled(True) + self.checkBoxMinimizeToTray.setText(_translate( + "MainWindow", "Minimize-to-tray not yet supported on your OS.")) + self.checkBoxShowTrayNotifications.setDisabled(True) + self.checkBoxShowTrayNotifications.setText(_translate( + "MainWindow", "Tray notifications not yet supported on your OS.")) + elif 'linux' in sys.platform: + self.checkBoxStartOnLogon.setDisabled(True) + self.checkBoxStartOnLogon.setText(_translate( + "MainWindow", "Start-on-login not yet supported on your OS.")) + # On the Network settings tab: + self.lineEditTCPPort.setText(str( + config.get('bitmessagesettings', 'port'))) + self.checkBoxUPnP.setChecked( + config.safeGetBoolean('bitmessagesettings', 'upnp')) + self.checkBoxAuthentication.setChecked( + config.getboolean('bitmessagesettings', 'socksauthentication')) + self.checkBoxSocksListen.setChecked( + config.getboolean('bitmessagesettings', 'sockslisten')) - def retranslateUi(self, settingsDialog): - """Re-translate the UI into the supported languages""" + proxy_type = config.get('bitmessagesettings', 'socksproxytype') + if proxy_type == 'none': + self.comboBoxProxyType.setCurrentIndex(0) + self.lineEditSocksHostname.setEnabled(False) + self.lineEditSocksPort.setEnabled(False) + self.lineEditSocksUsername.setEnabled(False) + self.lineEditSocksPassword.setEnabled(False) + self.checkBoxAuthentication.setEnabled(False) + self.checkBoxSocksListen.setEnabled(False) + elif proxy_type == 'SOCKS4a': + self.comboBoxProxyType.setCurrentIndex(1) + elif proxy_type == 'SOCKS5': + self.comboBoxProxyType.setCurrentIndex(2) - settingsDialog.setWindowTitle(_translate("settingsDialog", "Settings", None)) - self.checkBoxStartOnLogon.setText(_translate("settingsDialog", "Start Bitmessage on user login", None)) - self.groupBoxTray.setTitle(_translate("settingsDialog", "Tray", None)) - self.checkBoxStartInTray.setText( - _translate( - "settingsDialog", - "Start Bitmessage in the tray (don\'t show main window)", - None)) - self.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", None)) - self.checkBoxTrayOnClose.setText(_translate("settingsDialog", "Close to tray", None)) - self.checkBoxHideTrayConnectionNotifications.setText( - _translate("settingsDialog", "Hide connection notifications", None)) - self.checkBoxShowTrayNotifications.setText( - _translate( - "settingsDialog", - "Show notification when message received", - None)) - self.checkBoxPortableMode.setText(_translate("settingsDialog", "Run in Portable Mode", None)) - self.PortableModeDescription.setText( - _translate( - "settingsDialog", - "In Portable Mode, messages and config files are stored in the same directory as the" - " program rather than the normal application-data folder. This makes it convenient to" - " run Bitmessage from a USB thumb drive.", - None)) - self.checkBoxWillinglySendToMobile.setText( - _translate( - "settingsDialog", - "Willingly include unencrypted destination address when sending to a mobile device", - None)) - self.checkBoxUseIdenticons.setText(_translate("settingsDialog", "Use Identicons", None)) - self.checkBoxReplyBelow.setText(_translate("settingsDialog", "Reply below Quote", None)) - self.groupBox.setTitle(_translate("settingsDialog", "Interface Language", None)) - self.languageComboBox.setItemText(0, _translate("settingsDialog", "System Settings", "system")) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabUserInterface), - _translate( - "settingsDialog", "User Interface", None)) - self.groupBox1.setTitle(_translate("settingsDialog", "Listening port", None)) - self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None)) - self.labelUPnP.setText(_translate("settingsDialog", "UPnP:", None)) - self.groupBox_3.setTitle(_translate("settingsDialog", "Bandwidth limit", None)) - self.label_24.setText(_translate("settingsDialog", "Maximum download rate (kB/s): [0: unlimited]", None)) - self.label_25.setText(_translate("settingsDialog", "Maximum upload rate (kB/s): [0: unlimited]", None)) - self.label_26.setText(_translate("settingsDialog", "Maximum outbound connections: [0: none]", None)) - self.groupBox_2.setTitle(_translate("settingsDialog", "Proxy server / Tor", None)) - self.label_2.setText(_translate("settingsDialog", "Type:", None)) - self.label_3.setText(_translate("settingsDialog", "Server hostname:", None)) - self.label_4.setText(_translate("settingsDialog", "Port:", None)) - self.checkBoxAuthentication.setText(_translate("settingsDialog", "Authentication", None)) - self.label_5.setText(_translate("settingsDialog", "Username:", None)) - self.label_6.setText(_translate("settingsDialog", "Pass:", None)) - self.checkBoxSocksListen.setText( - _translate( - "settingsDialog", - "Listen for incoming connections when using proxy", - None)) - self.comboBoxProxyType.setItemText(0, _translate("settingsDialog", "none", None)) - self.comboBoxProxyType.setItemText(1, _translate("settingsDialog", "SOCKS4a", None)) - self.comboBoxProxyType.setItemText(2, _translate("settingsDialog", "SOCKS5", None)) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabNetworkSettings), - _translate( - "settingsDialog", "Network Settings", None)) - self.label_9.setText(_translate("settingsDialog", "Total difficulty:", None)) - self.label_10.setText( - _translate( - "settingsDialog", - "The \'Total difficulty\' affects the absolute amount of work the sender must complete." - " Doubling this value doubles the amount of work.", - None)) - self.label_11.setText(_translate("settingsDialog", "Small message difficulty:", None)) - self.label_8.setText(_translate( - "settingsDialog", - "When someone sends you a message, their computer must first complete some work. The difficulty of this" - " work, by default, is 1. You may raise this default for new addresses you create by changing the values" - " here. Any new addresses you create will require senders to meet the higher difficulty. There is one" - " exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically" - " notify them when you next send a message that they need only complete the minimum amount of" - " work: difficulty 1. ", - None)) - self.label_12.setText( - _translate( - "settingsDialog", - "The \'Small message difficulty\' mostly only affects the difficulty of sending small messages." - " Doubling this value makes it almost twice as difficult to send a small message but doesn\'t really" - " affect large messages.", - None)) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabDemandedDifficulty), - _translate( - "settingsDialog", "Demanded difficulty", None)) - self.label_15.setText( - _translate( - "settingsDialog", - "Here you may set the maximum amount of work you are willing to do to send a message to another" - " person. Setting these values to 0 means that any value is acceptable.", - None)) - self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) - self.label_14.setText(_translate("settingsDialog", "Maximum acceptable small message difficulty:", None)) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabMaxAcceptableDifficulty), - _translate( - "settingsDialog", "Max acceptable difficulty", None)) - self.labelOpenCL.setText(_translate("settingsDialog", "Hardware GPU acceleration (OpenCL):", None)) - self.label_16.setText(_translate( - "settingsDialog", - "

Bitmessage can utilize a different Bitcoin-based program called Namecoin to make" - " addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage" - " address, you can simply tell him to send a message to test." - "

(Getting your own Bitmessage address into Namecoin is still rather difficult).

" - "

Bitmessage can use either namecoind directly or a running nmcontrol instance.

", - None)) - self.label_17.setText(_translate("settingsDialog", "Host:", None)) - self.label_18.setText(_translate("settingsDialog", "Port:", None)) - self.labelNamecoinUser.setText(_translate("settingsDialog", "Username:", None)) - self.labelNamecoinPassword.setText(_translate("settingsDialog", "Password:", None)) - self.pushButtonNamecoinTest.setText(_translate("settingsDialog", "Test", None)) - self.label_21.setText(_translate("settingsDialog", "Connect to:", None)) - self.radioButtonNamecoinNamecoind.setText(_translate("settingsDialog", "Namecoind", None)) - self.radioButtonNamecoinNmcontrol.setText(_translate("settingsDialog", "NMControl", None)) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabNamecoin), - _translate( - "settingsDialog", "Namecoin integration", None)) - self.label_7.setText(_translate( - "settingsDialog", - "

By default, if you send a message to someone and he is offline for more than two" - " days, Bitmessage will send the message again after an additional two days. This will be continued with" - " exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver" - " acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain" - " number of days or months.

Leave these input fields blank for the default behavior." - "

", - None)) - self.label_19.setText(_translate("settingsDialog", "Give up after", None)) - self.label_20.setText(_translate("settingsDialog", "and", None)) - self.label_22.setText(_translate("settingsDialog", "days", None)) - self.label_23.setText(_translate("settingsDialog", "months.", None)) - self.tabWidgetSettings.setTabText( - self.tabWidgetSettings.indexOf( - self.tabResendsExpire), - _translate( - "settingsDialog", "Resends Expire", None)) + self.lineEditSocksHostname.setText( + config.get('bitmessagesettings', 'sockshostname')) + self.lineEditSocksPort.setText(str( + config.get('bitmessagesettings', 'socksport'))) + self.lineEditSocksUsername.setText( + config.get('bitmessagesettings', 'socksusername')) + self.lineEditSocksPassword.setText( + config.get('bitmessagesettings', 'sockspassword')) + + self.lineEditMaxDownloadRate.setText(str( + config.get('bitmessagesettings', 'maxdownloadrate'))) + self.lineEditMaxUploadRate.setText(str( + config.get('bitmessagesettings', 'maxuploadrate'))) + self.lineEditMaxOutboundConnections.setText(str( + config.get('bitmessagesettings', 'maxoutboundconnections'))) + + # Demanded difficulty tab + self.lineEditTotalDifficulty.setText(str((float( + config.getint( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.lineEditSmallMessageDifficulty.setText(str((float( + config.getint( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + ) / defaults.networkDefaultPayloadLengthExtraBytes))) + + # Max acceptable difficulty tab + self.lineEditMaxAcceptableTotalDifficulty.setText(str((float( + config.getint( + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte') + ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float( + config.getint( + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') + ) / defaults.networkDefaultPayloadLengthExtraBytes))) + + # OpenCL + self.comboBoxOpenCL.setEnabled(openclpow.openclAvailable()) + self.comboBoxOpenCL.clear() + self.comboBoxOpenCL.addItem("None") + self.comboBoxOpenCL.addItems(openclpow.vendors) + self.comboBoxOpenCL.setCurrentIndex(0) + for i in range(self.comboBoxOpenCL.count()): + if self.comboBoxOpenCL.itemText(i) == config.safeGet( + 'bitmessagesettings', 'opencl'): + self.comboBoxOpenCL.setCurrentIndex(i) + break + + # Namecoin integration tab + nmctype = config.get('bitmessagesettings', 'namecoinrpctype') + self.lineEditNamecoinHost.setText( + config.get('bitmessagesettings', 'namecoinrpchost')) + self.lineEditNamecoinPort.setText(str( + config.get('bitmessagesettings', 'namecoinrpcport'))) + self.lineEditNamecoinUser.setText( + config.get('bitmessagesettings', 'namecoinrpcuser')) + self.lineEditNamecoinPassword.setText( + config.get('bitmessagesettings', 'namecoinrpcpassword')) + + if nmctype == "namecoind": + self.radioButtonNamecoinNamecoind.setChecked(True) + elif nmctype == "nmcontrol": + self.radioButtonNamecoinNmcontrol.setChecked(True) + self.lineEditNamecoinUser.setEnabled(False) + self.labelNamecoinUser.setEnabled(False) + self.lineEditNamecoinPassword.setEnabled(False) + self.labelNamecoinPassword.setEnabled(False) + else: + assert False + + # Message Resend tab + self.lineEditDays.setText(str( + config.get('bitmessagesettings', 'stopresendingafterxdays'))) + self.lineEditMonths.setText(str( + config.get('bitmessagesettings', 'stopresendingafterxmonths'))) + + def comboBoxProxyTypeChanged(self, comboBoxIndex): + """A callback for currentIndexChanged event of comboBoxProxyType""" + if comboBoxIndex == 0: + self.lineEditSocksHostname.setEnabled(False) + self.lineEditSocksPort.setEnabled(False) + self.lineEditSocksUsername.setEnabled(False) + self.lineEditSocksPassword.setEnabled(False) + self.checkBoxAuthentication.setEnabled(False) + self.checkBoxSocksListen.setEnabled(False) + elif comboBoxIndex in (1, 2): + self.lineEditSocksHostname.setEnabled(True) + self.lineEditSocksPort.setEnabled(True) + self.checkBoxAuthentication.setEnabled(True) + self.checkBoxSocksListen.setEnabled(True) + if self.checkBoxAuthentication.isChecked(): + self.lineEditSocksUsername.setEnabled(True) + self.lineEditSocksPassword.setEnabled(True) + + def getNamecoinType(self): + """ + Check status of namecoin integration radio buttons + and translate it to a string as in the options. + """ + if self.radioButtonNamecoinNamecoind.isChecked(): + return "namecoind" + if self.radioButtonNamecoinNmcontrol.isChecked(): + return "nmcontrol" + assert False + + # Namecoin connection type was changed. + def namecoinTypeChanged(self, checked): # pylint: disable=unused-argument + """A callback for toggled event of radioButtonNamecoinNamecoind""" + nmctype = self.getNamecoinType() + assert nmctype == "namecoind" or nmctype == "nmcontrol" + + isNamecoind = (nmctype == "namecoind") + self.lineEditNamecoinUser.setEnabled(isNamecoind) + self.labelNamecoinUser.setEnabled(isNamecoind) + self.lineEditNamecoinPassword.setEnabled(isNamecoind) + self.labelNamecoinPassword.setEnabled(isNamecoind) + + if isNamecoind: + self.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) + else: + self.lineEditNamecoinPort.setText("9000") + + def click_pushButtonNamecoinTest(self): + """Test the namecoin settings specified in the settings dialog.""" + self.labelNamecoinTestResult.setText( + _translate("MainWindow", "Testing...")) + nc = namecoin.namecoinConnection({ + 'type': self.getNamecoinType(), + 'host': str(self.lineEditNamecoinHost.text().toUtf8()), + 'port': str(self.lineEditNamecoinPort.text().toUtf8()), + 'user': str(self.lineEditNamecoinUser.text().toUtf8()), + 'password': str(self.lineEditNamecoinPassword.text().toUtf8()) + }) + status, text = nc.test() + self.labelNamecoinTestResult.setText(text) + if status == 'success': + self.parent.namecoin = nc + + def accept(self): + """A callback for accepted event of buttonBox (OK button pressed)""" + # pylint: disable=too-many-branches,too-many-statements + super(SettingsDialog, self).accept() + if self.firstrun: + self.config.remove_option('bitmessagesettings', 'dontconnect') + self.config.set('bitmessagesettings', 'startonlogon', str( + self.checkBoxStartOnLogon.isChecked())) + self.config.set('bitmessagesettings', 'minimizetotray', str( + self.checkBoxMinimizeToTray.isChecked())) + self.config.set('bitmessagesettings', 'trayonclose', str( + self.checkBoxTrayOnClose.isChecked())) + self.config.set( + 'bitmessagesettings', 'hidetrayconnectionnotifications', + str(self.checkBoxHideTrayConnectionNotifications.isChecked())) + self.config.set('bitmessagesettings', 'showtraynotifications', str( + self.checkBoxShowTrayNotifications.isChecked())) + self.config.set('bitmessagesettings', 'startintray', str( + self.checkBoxStartInTray.isChecked())) + self.config.set('bitmessagesettings', 'willinglysendtomobile', str( + self.checkBoxWillinglySendToMobile.isChecked())) + self.config.set('bitmessagesettings', 'useidenticons', str( + self.checkBoxUseIdenticons.isChecked())) + self.config.set('bitmessagesettings', 'replybelow', str( + self.checkBoxReplyBelow.isChecked())) + + lang = str(self.languageComboBox.itemData( + self.languageComboBox.currentIndex()).toString()) + self.config.set('bitmessagesettings', 'userlocale', lang) + self.parent.change_translation() + + if int(self.config.get('bitmessagesettings', 'port')) != int( + self.lineEditTCPPort.text()): + if not self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): + QtGui.QMessageBox.about( + self, _translate("MainWindow", "Restart"), + _translate( + "MainWindow", + "You must restart Bitmessage for the port number" + " change to take effect.") + ) + self.config.set( + 'bitmessagesettings', 'port', str(self.lineEditTCPPort.text())) + if self.checkBoxUPnP.isChecked() != self.config.safeGetBoolean( + 'bitmessagesettings', 'upnp'): + self.config.set( + 'bitmessagesettings', 'upnp', + str(self.checkBoxUPnP.isChecked())) + if self.checkBoxUPnP.isChecked(): + import upnp + upnpThread = upnp.uPnPThread() + upnpThread.start() + + if ( + self.config.get('bitmessagesettings', 'socksproxytype') == + 'none' and + self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' + ): + if shared.statusIconColor != 'red': + QtGui.QMessageBox.about( + self, _translate("MainWindow", "Restart"), + _translate( + "MainWindow", + "Bitmessage will use your proxy from now on but" + " you may want to manually restart Bitmessage now" + " to close existing connections (if any).") + ) + if ( + self.config.get('bitmessagesettings', 'socksproxytype')[0:5] == + 'SOCKS' and self.comboBoxProxyType.currentText()[0:5] != 'SOCKS' + ): + self.parent.statusbar.clearMessage() + # just in case we changed something in the network connectivity + state.resetNetworkProtocolAvailability() + if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS': + self.config.set('bitmessagesettings', 'socksproxytype', str( + self.comboBoxProxyType.currentText())) + else: + self.config.set('bitmessagesettings', 'socksproxytype', 'none') + self.config.set('bitmessagesettings', 'socksauthentication', str( + self.checkBoxAuthentication.isChecked())) + self.config.set('bitmessagesettings', 'sockshostname', str( + self.lineEditSocksHostname.text())) + self.config.set('bitmessagesettings', 'socksport', str( + self.lineEditSocksPort.text())) + self.config.set('bitmessagesettings', 'socksusername', str( + self.lineEditSocksUsername.text())) + self.config.set('bitmessagesettings', 'sockspassword', str( + self.lineEditSocksPassword.text())) + self.config.set('bitmessagesettings', 'sockslisten', str( + self.checkBoxSocksListen.isChecked())) + try: + # Rounding to integers just for aesthetics + self.config.set('bitmessagesettings', 'maxdownloadrate', str( + int(float(self.lineEditMaxDownloadRate.text())))) + self.config.set('bitmessagesettings', 'maxuploadrate', str( + int(float(self.lineEditMaxUploadRate.text())))) + except ValueError: + QtGui.QMessageBox.about( + self, _translate("MainWindow", "Number needed"), + _translate( + "MainWindow", + "Your maximum download and upload rate must be numbers." + " Ignoring what you typed.") + ) + else: + set_rates( + self.config.safeGetInt('bitmessagesettings', 'maxdownloadrate'), + self.config.safeGetInt('bitmessagesettings', 'maxuploadrate')) + + self.config.set('bitmessagesettings', 'maxoutboundconnections', str( + int(float(self.lineEditMaxOutboundConnections.text())))) + + self.config.set( + 'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType()) + self.config.set('bitmessagesettings', 'namecoinrpchost', str( + self.lineEditNamecoinHost.text())) + self.config.set('bitmessagesettings', 'namecoinrpcport', str( + self.lineEditNamecoinPort.text())) + self.config.set('bitmessagesettings', 'namecoinrpcuser', str( + self.lineEditNamecoinUser.text())) + self.config.set('bitmessagesettings', 'namecoinrpcpassword', str( + self.lineEditNamecoinPassword.text())) + self.parent.resetNamecoinConnection() + + # Demanded difficulty tab + if float(self.lineEditTotalDifficulty.text()) >= 1: + self.config.set( + 'bitmessagesettings', 'defaultnoncetrialsperbyte', + str(int( + float(self.lineEditTotalDifficulty.text()) * + defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) + if float(self.lineEditSmallMessageDifficulty.text()) >= 1: + self.config.set( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes', + str(int( + float(self.lineEditSmallMessageDifficulty.text()) * + defaults.networkDefaultPayloadLengthExtraBytes))) + + if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet( + 'bitmessagesettings', 'opencl'): + self.config.set( + 'bitmessagesettings', 'opencl', + str(self.comboBoxOpenCL.currentText())) + queues.workerQueue.put(('resetPoW', '')) + + acceptableDifficultyChanged = False + + if ( + float(self.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or + float(self.lineEditMaxAcceptableTotalDifficulty.text()) == 0 + ): + if self.config.get( + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte' + ) != str(int( + float(self.lineEditMaxAcceptableTotalDifficulty.text()) * + defaults.networkDefaultProofOfWorkNonceTrialsPerByte) + ): + # the user changed the max acceptable total difficulty + acceptableDifficultyChanged = True + self.config.set( + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', + str(int( + float(self.lineEditMaxAcceptableTotalDifficulty.text()) * + defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) + ) + if ( + float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or + float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0 + ): + if self.config.get( + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes' + ) != str(int( + float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) * + defaults.networkDefaultPayloadLengthExtraBytes) + ): + # the user changed the max acceptable small message difficulty + acceptableDifficultyChanged = True + self.config.set( + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', + str(int( + float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) * + defaults.networkDefaultPayloadLengthExtraBytes)) + ) + if acceptableDifficultyChanged: + # It might now be possible to send msgs which were previously + # marked as toodifficult. Let us change them to 'msgqueued'. + # The singleWorker will try to send them and will again mark + # them as toodifficult if the receiver's required difficulty + # is still higher than we are willing to do. + sqlExecute( + "UPDATE sent SET status='msgqueued'" + " WHERE status='toodifficult'") + queues.workerQueue.put(('sendmessage', '')) + + # UI setting to stop trying to send messages after X days/months + # I'm open to changing this UI to something else if someone has a better idea. + if self.lineEditDays.text() == '' and self.lineEditMonths.text() == '': + # We need to handle this special case. Bitmessage has its + # default behavior. The input is blank/blank + self.config.set('bitmessagesettings', 'stopresendingafterxdays', '') + self.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') + shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') + + try: + days = float(self.lineEditDays.text()) + except ValueError: + self.lineEditDays.setText("0") + days = 0.0 + try: + months = float(self.lineEditMonths.text()) + except ValueError: + self.lineEditMonths.setText("0") + months = 0.0 + + if days >= 0 and months >= 0: + shared.maximumLengthOfTimeToBotherResendingMessages = \ + days * 24 * 60 * 60 + months * 60 * 60 * 24 * 365 / 12 + if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: + # If the time period is less than 5 hours, we give + # zero values to all fields. No message will be sent again. + QtGui.QMessageBox.about( + self, + _translate("MainWindow", "Will not resend ever"), + _translate( + "MainWindow", + "Note that the time limit you entered is less" + " than the amount of time Bitmessage waits for" + " the first resend attempt therefore your" + " messages will never be resent.") + ) + self.config.set( + 'bitmessagesettings', 'stopresendingafterxdays', '0') + self.config.set( + 'bitmessagesettings', 'stopresendingafterxmonths', '0') + shared.maximumLengthOfTimeToBotherResendingMessages = 0.0 + else: + self.config.set( + 'bitmessagesettings', 'stopresendingafterxdays', str(days)) + self.config.set( + 'bitmessagesettings', 'stopresendingafterxmonths', + str(months)) + + self.config.save() + + self.parent.updateStartOnLogon() + + if ( + state.appdata != paths.lookupExeFolder() and + self.checkBoxPortableMode.isChecked() + ): + # If we are NOT using portable mode now but the user selected + # that we should... + # Write the keys.dat file to disk in the new location + sqlStoredProcedure('movemessagstoprog') + with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: + self.config.write(configfile) + # Write the knownnodes.dat file to disk in the new location + knownnodes.saveKnownNodes(paths.lookupExeFolder()) + os.remove(state.appdata + 'keys.dat') + os.remove(state.appdata + 'knownnodes.dat') + previousAppdataLocation = state.appdata + state.appdata = paths.lookupExeFolder() + debug.resetLogging() + try: + os.remove(previousAppdataLocation + 'debug.log') + os.remove(previousAppdataLocation + 'debug.log.1') + except: + pass + + if ( + state.appdata == paths.lookupExeFolder() and + not self.checkBoxPortableMode.isChecked() + ): + # If we ARE using portable mode now but the user selected + # that we shouldn't... + state.appdata = paths.lookupAppdataFolder() + if not os.path.exists(state.appdata): + os.makedirs(state.appdata) + sqlStoredProcedure('movemessagstoappdata') + # Write the keys.dat file to disk in the new location + self.config.save() + # Write the knownnodes.dat file to disk in the new location + knownnodes.saveKnownNodes(state.appdata) + os.remove(paths.lookupExeFolder() + 'keys.dat') + os.remove(paths.lookupExeFolder() + 'knownnodes.dat') + debug.resetLogging() + try: + os.remove(paths.lookupExeFolder() + 'debug.log') + os.remove(paths.lookupExeFolder() + 'debug.log.1') + except: + pass diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 4aeba3ce..307c06c2 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -37,6 +37,18 @@ User Interface + + 8 + + + 8 + + + 8 + + + 8 + @@ -44,20 +56,43 @@ - - - - Start Bitmessage in the tray (don't show main window) + + + + Tray + + + + + Start Bitmessage in the tray (don't show main window) + + + + + + + Minimize to tray + + + true + + + + + + + Close to tray + + + + - + - Minimize to tray - - - true + Hide connection notifications @@ -117,90 +152,15 @@ Interface Language - - - + + + 100 0 - - - System Settings - - - - - English - - - - - Esperanto - - - - - Français - - - - - Deutsch - - - - - Español - - - - - русский - - - - - Norsk - - - - - العربية - - - - - 简体中文 - - - - - 日本語 - - - - - Nederlands - - - - - Česky - - - - - Pirate English - - - - - Other (set in keys.dat) - - @@ -213,6 +173,18 @@ Network Settings + + 8 + + + 8 + + + 8 + + + 8 + @@ -220,26 +192,13 @@ - - - Qt::Horizontal - - - - 125 - 20 - - - - - Listen for connections on port: - + @@ -249,6 +208,26 @@ + + + + UPnP + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -466,6 +445,18 @@ Demanded difficulty + + 8 + + + 8 + + + 8 + + + 8 + @@ -594,6 +585,18 @@ Max acceptable difficulty + + 8 + + + 8 + + + 8 + + + 8 + @@ -698,6 +701,33 @@ + + + + + + Hardware GPU acceleration (OpenCL): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -705,6 +735,18 @@ Namecoin integration + + 8 + + + 8 + + + 8 + + + 8 + @@ -888,6 +930,18 @@ Resends Expire + + 8 + + + 8 + + + 8 + + + 8 + @@ -912,91 +966,69 @@ - + 231 75 + + - - - 10 - 20 - 101 - 20 - - Give up after - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + + + - - - 30 - 40 - 80 - 16 - - and - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - 113 - 20 - 51 - 20 - - + + + + + + 55 + 100 + + - - - - 113 - 40 - 51 - 20 - - + + + + + + 55 + 100 + + - - - - 169 - 23 - 61 - 16 - - + + + days - - - - 170 - 41 - 71 - 16 - - + + + months. + + @@ -1017,7 +1049,14 @@ - + + + + LanguageBox + QComboBox +
bitmessageqt.languagebox
+
+
tabWidgetSettings checkBoxStartOnLogon @@ -1101,5 +1140,53 @@ + + comboBoxProxyType + currentIndexChanged(int) + settingsDialog + comboBoxProxyTypeChanged + + + 20 + 20 + + + 20 + 20 + + + + + radioButtonNamecoinNamecoind + toggled(bool) + settingsDialog + namecoinTypeChanged + + + 20 + 20 + + + 20 + 20 + + + + + pushButtonNamecoinTest + clicked() + settingsDialog + click_pushButtonNamecoinTest + + + 20 + 20 + + + 20 + 20 + + + From 18392017c63c538f99fa0cf833c8d494b54bd449 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 20 Nov 2018 16:53:25 +0200 Subject: [PATCH 112/306] Do not propose user to restart Bitmessage if network settings have changed, drop network connections instead --- src/bitmessageqt/settings.py | 61 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index fc96b137..dced52ff 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -1,7 +1,7 @@ import os import sys -from PyQt4 import QtGui +from PyQt4 import QtCore, QtGui import debug import defaults @@ -29,6 +29,8 @@ class SettingsDialog(QtGui.QDialog): self.parent = parent self.firstrun = firstrun self.config = BMConfigParser() + self.net_restart_needed = False + self.timer = QtCore.QTimer() self.lineEditMaxOutboundConnections.setValidator( QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) @@ -98,7 +100,8 @@ class SettingsDialog(QtGui.QDialog): self.checkBoxSocksListen.setChecked( config.getboolean('bitmessagesettings', 'sockslisten')) - proxy_type = config.get('bitmessagesettings', 'socksproxytype') + proxy_type = config.safeGet( + 'bitmessagesettings', 'socksproxytype', 'none') if proxy_type == 'none': self.comboBoxProxyType.setCurrentIndex(0) self.lineEditSocksHostname.setEnabled(False) @@ -283,16 +286,11 @@ class SettingsDialog(QtGui.QDialog): if int(self.config.get('bitmessagesettings', 'port')) != int( self.lineEditTCPPort.text()): - if not self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Restart"), - _translate( - "MainWindow", - "You must restart Bitmessage for the port number" - " change to take effect.") - ) self.config.set( 'bitmessagesettings', 'port', str(self.lineEditTCPPort.text())) + if not self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): + self.net_restart_needed = True + if self.checkBoxUPnP.isChecked() != self.config.safeGetBoolean( 'bitmessagesettings', 'upnp'): self.config.set( @@ -303,32 +301,28 @@ class SettingsDialog(QtGui.QDialog): upnpThread = upnp.uPnPThread() upnpThread.start() + proxy_type = self.config.safeGet( + 'bitmessagesettings', 'socksproxytype', 'none') if ( - self.config.get('bitmessagesettings', 'socksproxytype') == - 'none' and - self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' + proxy_type == 'none' and + self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' and + shared.statusIconColor != 'red' ): - if shared.statusIconColor != 'red': - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Restart"), - _translate( - "MainWindow", - "Bitmessage will use your proxy from now on but" - " you may want to manually restart Bitmessage now" - " to close existing connections (if any).") - ) + self.net_restart_needed = True if ( - self.config.get('bitmessagesettings', 'socksproxytype')[0:5] == - 'SOCKS' and self.comboBoxProxyType.currentText()[0:5] != 'SOCKS' + proxy_type[0:5] == 'SOCKS' and + self.comboBoxProxyType.currentText()[0:5] != 'SOCKS' ): + self.net_restart_needed = True self.parent.statusbar.clearMessage() # just in case we changed something in the network connectivity state.resetNetworkProtocolAvailability() - if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS': - self.config.set('bitmessagesettings', 'socksproxytype', str( - self.comboBoxProxyType.currentText())) - else: - self.config.set('bitmessagesettings', 'socksproxytype', 'none') + self.config.set( + 'bitmessagesettings', 'socksproxytype', + str(self.comboBoxProxyType.currentText()) + if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' + else 'none' + ) self.config.set('bitmessagesettings', 'socksauthentication', str( self.checkBoxAuthentication.isChecked())) self.config.set('bitmessagesettings', 'sockshostname', str( @@ -495,6 +489,15 @@ class SettingsDialog(QtGui.QDialog): self.config.save() + if self.net_restart_needed: + self.net_restart_needed = False + self.config.set('bitmessagesettings', 'dontconnect', 'true') + self.timer.singleShot( + 5000, lambda: + self.config.remove_option( + 'bitmessagesettings', 'dontconnect') + ) + self.parent.updateStartOnLogon() if ( From df66277e2d19e835ef6f9f0adb8a4e3a9d616769 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 30 Jul 2019 11:16:48 +0300 Subject: [PATCH 113/306] state.resetNetworkProtocolAvailability() is obsolete --- src/bitmessageqt/settings.py | 3 +-- src/state.py | 11 ----------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index dced52ff..4273257e 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -315,8 +315,7 @@ class SettingsDialog(QtGui.QDialog): ): self.net_restart_needed = True self.parent.statusbar.clearMessage() - # just in case we changed something in the network connectivity - state.resetNetworkProtocolAvailability() + self.config.set( 'bitmessagesettings', 'socksproxytype', str(self.comboBoxProxyType.currentText()) diff --git a/src/state.py b/src/state.py index 2cbc3a7c..3e051edf 100644 --- a/src/state.py +++ b/src/state.py @@ -9,9 +9,6 @@ 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. @@ -54,14 +51,6 @@ discoveredPeers = {} Peer = collections.namedtuple('Peer', ['host', 'port']) - -def resetNetworkProtocolAvailability(): - global networkProtocolAvailability - networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} - - -resetNetworkProtocolAvailability() - dandelion = 0 testmode = False From 24ae91ad0ad438b07f8000cc18d08f03ccc16509 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 5 Sep 2019 18:31:16 +0300 Subject: [PATCH 114/306] Set dontconnect temporary, completely avoiding saving --- src/bitmessageqt/settings.py | 6 +++--- src/bmconfigparser.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 4273257e..513f285b 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -490,11 +490,11 @@ class SettingsDialog(QtGui.QDialog): if self.net_restart_needed: self.net_restart_needed = False - self.config.set('bitmessagesettings', 'dontconnect', 'true') + self.config.setTemp('bitmessagesettings', 'dontconnect', 'true') self.timer.singleShot( 5000, lambda: - self.config.remove_option( - 'bitmessagesettings', 'dontconnect') + self.config.setTemp( + 'bitmessagesettings', 'dontconnect', 'false') ) self.parent.updateStartOnLogon() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 1ee64e94..726d32eb 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -46,6 +46,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): """Singleton class inherited from ConfigParser.SafeConfigParser with additional methods specific to bitmessage config.""" + _temp = {} + def set(self, section, option, value=None): if self._optcre is self.OPTCRE or value: if not isinstance(value, basestring): @@ -59,6 +61,10 @@ class BMConfigParser(ConfigParser.SafeConfigParser): if section == "bitmessagesettings" and option == "timeformat": return ConfigParser.ConfigParser.get( self, section, option, raw, variables) + try: + return self._temp[section][option] + except KeyError: + pass return ConfigParser.ConfigParser.get( self, section, option, True, variables) except ConfigParser.InterpolationError: @@ -70,6 +76,13 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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): try: return self.getboolean(section, field) From 9e9cc65eafa3db16c3a3ab7a0fd95942b27bebfc Mon Sep 17 00:00:00 2001 From: Navjot Date: Fri, 20 Sep 2019 21:49:28 +0530 Subject: [PATCH 115/306] wokred on updating backend database query or UIfixing issue for android --- src/bitmessagekivy/kivy_helper_search.py | 4 ++- src/bitmessagekivy/main.kv | 2 +- src/bitmessagekivy/mpybit.py | 38 +++++++----------------- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 39d4ab3e..e2e962c0 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -53,5 +53,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if len(sqlStatementParts) > 0: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": - sqlStatementBase += " ORDER BY lastactiontime" + sqlStatementBase += " ORDER BY lastactiontime DESC" + elif folder == "inbox": + sqlStatementBase += " ORDER BY received DESC" return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 4ffab336..1fdb29f0 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -396,7 +396,7 @@ NavigationLayout: id: txt_input size_hint_y: None font_size: '13sp' - height: 50 + height: self.parent.height/2 hint_text: 'type or search recipients address starting with BM-' RV: id: rv diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 5bc27fe7..ae69a133 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -127,7 +127,7 @@ class Inbox(Screen): mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'receivedTime': mail[6]}) for item in data: - meny = ThreeLineAvatarIconListItem( + meny = TwoLineAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', @@ -138,10 +138,7 @@ class Inbox(Screen): meny.bind(on_press=partial( self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -364,10 +361,7 @@ class AddressBook(Screen): meny.bind(on_press=partial( self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 140 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -773,7 +767,7 @@ class Sent(Screen): mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'lastactiontime': mail[6]}) for item in self.data: - meny = ThreeLineAvatarIconListItem( + meny = TwoLineAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', @@ -784,10 +778,7 @@ class Sent(Screen): meny.bind(on_press=partial( self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -907,7 +898,7 @@ class Trash(Screen): src_mng_obj.trash_cnt.badge_text = str(len(trash_data)) state.trash_count = str(len(trash_data)) for item in trash_data: - meny = ThreeLineAvatarIconListItem( + meny = TwoLineAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( item[2]) >= 50 else ( @@ -919,10 +910,7 @@ class Trash(Screen): 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget(source=img_latter)) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -1734,10 +1722,7 @@ class Draft(Screen): meny.bind(on_press=partial( self.draft_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -1907,7 +1892,7 @@ class Allmails(Screen): state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) state.all_count = str(len(all_mails)) for item in all_mails: - meny = ThreeLineAvatarIconListItem( + meny = TwoLineAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( item[2]) >= 50 else ( @@ -1920,10 +1905,7 @@ class Allmails(Screen): meny.bind(on_press=partial( self.mail_detail, item[5], item[4])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 - elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 From 4c7f9487e251a70cd173debdd4a287f71f3be0e2 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 15:12:40 +0530 Subject: [PATCH 116/306] init file fixes for pylint --- src/bitmessagecurses/__init__.py | 800 +++++++++++++++++++------------ 1 file changed, 499 insertions(+), 301 deletions(-) diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index dc6e8a0c..80dc3f14 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -1,40 +1,40 @@ +""" +src/bitmessagecurses/__init__.py +================================ +""" + # Copyright (c) 2014 Luke Montalvo # This file adds a alternative commandline interface, feel free to critique and fork -# +# # This has only been tested on Arch Linux and Linux Mint # Dependencies: # * from python2-pip # * python2-pythondialog # * dialog +import ConfigParser +import curses import os import sys -import StringIO -from textwrap import * - import time -from time import strftime, localtime +from textwrap import fill from threading import Timer -import curses -import dialog -from dialog import Dialog -from helper_sql import * -from helper_ackPayload import genAckPayload - -from addresses import * -import ConfigParser +from addresses import addBMIfNotPresent, decodeAddress from bmconfigparser import BMConfigParser +from dialog import Dialog +from helper_ackPayload import genAckPayload +from helper_sql import sqlExecute, sqlQuery from inventory import Inventory import l10n +import network.stats from pyelliptic.openssl import OpenSSL import queues import shared import shutdown -import network.stats -quit = False +quit = False # pylint: disable=redefined-builtin menutab = 1 menu = ["Inbox", "Send", "Sent", "Your Identities", "Subscriptions", "Address Book", "Blacklist", "Network Status"] naptime = 100 @@ -60,156 +60,189 @@ bwtype = "black" BROADCAST_STR = "[Broadcast subscribers]" -class printLog: + +class printLog: # pylint: disable=no-self-use, no-init, old-style-class + """Printing logs""" + def write(self, output): + # pylint: disable=global-statement global log log += output + def flush(self): pass -class errLog: + + +class errLog: # pylint: disable=no-self-use, no-init, old-style-class + """Error logs""" def write(self, output): + # pylint: disable=global-statement global log - log += "!"+output + log += "!" + output + def flush(self): pass + + printlog = printLog() errlog = errLog() def cpair(a): + """Color pairs""" r = curses.color_pair(a) - if r not in range(1, curses.COLOR_PAIRS-1): + if r not in range(1, curses.COLOR_PAIRS - 1): r = curses.color_pair(0) return r + + def ascii(s): + """ASCII values""" r = "" for c in s: if ord(c) in range(128): r += c return r + def drawmenu(stdscr): + """Creating menu's""" menustr = " " - for i in range(0, len(menu)): - if menutab == i+1: + for i, _ in enumerate(menu): + if menutab == i + 1: menustr = menustr[:-1] menustr += "[" - menustr += str(i+1)+menu[i] - if menutab == i+1: + menustr += str(i + 1) + menu[i] + if menutab == i + 1: menustr += "] " - elif i != len(menu)-1: + elif i != len(menu) - 1: menustr += " " stdscr.addstr(2, 5, menustr, curses.A_UNDERLINE) + def set_background_title(d, title): + """Setting background title""" try: d.set_background_title(title) except: d.add_persistent_args(("--backtitle", title)) + def scrollbox(d, text, height=None, width=None): + """Setting scroll box""" try: - d.scrollbox(text, height, width, exit_label = "Continue") + d.scrollbox(text, height, width, exit_label="Continue") except: - d.msgbox(text, height or 0, width or 0, ok_label = "Continue") + d.msgbox(text, height or 0, width or 0, ok_label="Continue") + def resetlookups(): - global inventorydata + """Reset the Inventory Lookups""" + global inventorydata # pylint: disable=global-statement inventorydata = Inventory().numberOfInventoryLookupsPerformed Inventory().numberOfInventoryLookupsPerformed = 0 Timer(1, resetlookups, ()).start() -def drawtab(stdscr): - if menutab in range(1, len(menu)+1): - if menutab == 1: # Inbox + + +def drawtab(stdscr): # pylint: disable=too-many-branches, too-many-statements + """Method for drawing different tabs""" + if menutab in range(1, len(menu) + 1): + if menutab == 1: # Inbox stdscr.addstr(3, 5, "To", curses.A_BOLD) stdscr.addstr(3, 40, "From", curses.A_BOLD) stdscr.addstr(3, 80, "Subject", curses.A_BOLD) stdscr.addstr(3, 120, "Time Received", curses.A_BOLD) stdscr.hline(4, 5, '-', 121) - for i, item in enumerate(inbox[max(min(len(inbox)-curses.LINES+6, inboxcur-5), 0):]): - if 6+i < curses.LINES: + for i, item in enumerate(inbox[max(min(len(inbox) - curses.LINES + 6, inboxcur - 5), 0):]): + if 6 + i < curses.LINES: a = 0 - if i == inboxcur - max(min(len(inbox)-curses.LINES+6, inboxcur-5), 0): # Highlight current address + if i == inboxcur - max(min(len(inbox) - curses.LINES + 6, inboxcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - if item[7] == False: # If not read, highlight + if item[7] is False: # If not read, highlight a = a | curses.A_BOLD - stdscr.addstr(5+i, 5, item[1][:34], a) - stdscr.addstr(5+i, 40, item[3][:39], a) - stdscr.addstr(5+i, 80, item[5][:39], a) - stdscr.addstr(5+i, 120, item[6][:39], a) - elif menutab == 3: # Sent + stdscr.addstr(5 + i, 5, item[1][:34], a) + stdscr.addstr(5 + i, 40, item[3][:39], a) + stdscr.addstr(5 + i, 80, item[5][:39], a) + stdscr.addstr(5 + i, 120, item[6][:39], a) + elif menutab == 3: # Sent stdscr.addstr(3, 5, "To", curses.A_BOLD) stdscr.addstr(3, 40, "From", curses.A_BOLD) stdscr.addstr(3, 80, "Subject", curses.A_BOLD) stdscr.addstr(3, 120, "Status", curses.A_BOLD) stdscr.hline(4, 5, '-', 121) - for i, item in enumerate(sentbox[max(min(len(sentbox)-curses.LINES+6, sentcur-5), 0):]): - if 6+i < curses.LINES: + for i, item in enumerate(sentbox[max(min(len(sentbox) - curses.LINES + 6, sentcur - 5), 0):]): + if 6 + i < curses.LINES: a = 0 - if i == sentcur - max(min(len(sentbox)-curses.LINES+6, sentcur-5), 0): # Highlight current address + if i == sentcur - max(min(len(sentbox) - curses.LINES + 6, sentcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - stdscr.addstr(5+i, 5, item[0][:34], a) - stdscr.addstr(5+i, 40, item[2][:39], a) - stdscr.addstr(5+i, 80, item[4][:39], a) - stdscr.addstr(5+i, 120, item[5][:39], a) - elif menutab == 2 or menutab == 4: # Send or Identities + stdscr.addstr(5 + i, 5, item[0][:34], a) + stdscr.addstr(5 + i, 40, item[2][:39], a) + stdscr.addstr(5 + i, 80, item[4][:39], a) + stdscr.addstr(5 + i, 120, item[5][:39], a) + elif menutab == 2 or menutab == 4: # Send or Identities stdscr.addstr(3, 5, "Label", curses.A_BOLD) stdscr.addstr(3, 40, "Address", curses.A_BOLD) stdscr.addstr(3, 80, "Stream", curses.A_BOLD) stdscr.hline(4, 5, '-', 81) - for i, item in enumerate(addresses[max(min(len(addresses)-curses.LINES+6, addrcur-5), 0):]): - if 6+i < curses.LINES: + for i, item in enumerate(addresses[max(min(len(addresses) - curses.LINES + 6, addrcur - 5), 0):]): + if 6 + i < curses.LINES: a = 0 - if i == addrcur - max(min(len(addresses)-curses.LINES+6, addrcur-5), 0): # Highlight current address + if i == addrcur - max(min(len(addresses) - curses.LINES + 6, addrcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - if item[1] == True and item[3] not in [8,9]: # Embolden enabled, non-special addresses + if item[1] and item[3] not in [8, 9]: # Embolden enabled, non-special addresses a = a | curses.A_BOLD - stdscr.addstr(5+i, 5, item[0][:34], a) - stdscr.addstr(5+i, 40, item[2][:39], cpair(item[3]) | a) - stdscr.addstr(5+i, 80, str(1)[:39], a) - elif menutab == 5: # Subscriptions + stdscr.addstr(5 + i, 5, item[0][:34], a) + stdscr.addstr(5 + i, 40, item[2][:39], cpair(item[3]) | a) + stdscr.addstr(5 + i, 80, str(1)[:39], a) + elif menutab == 5: # Subscriptions stdscr.addstr(3, 5, "Label", curses.A_BOLD) stdscr.addstr(3, 80, "Address", curses.A_BOLD) stdscr.addstr(3, 120, "Enabled", curses.A_BOLD) stdscr.hline(4, 5, '-', 121) - for i, item in enumerate(subscriptions[max(min(len(subscriptions)-curses.LINES+6, subcur-5), 0):]): - if 6+i < curses.LINES: + for i, item in enumerate(subscriptions[max(min(len(subscriptions) - curses.LINES + 6, subcur - 5), 0):]): + if 6 + i < curses.LINES: a = 0 - if i == subcur - max(min(len(subscriptions)-curses.LINES+6, subcur-5), 0): # Highlight current address + if i == subcur - max(min(len(subscriptions) - curses.LINES + 6, subcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - if item[2] == True: # Embolden enabled subscriptions + if item[2]: # Embolden enabled subscriptions a = a | curses.A_BOLD - stdscr.addstr(5+i, 5, item[0][:74], a) - stdscr.addstr(5+i, 80, item[1][:39], a) - stdscr.addstr(5+i, 120, str(item[2]), a) - elif menutab == 6: # Address book + stdscr.addstr(5 + i, 5, item[0][:74], a) + stdscr.addstr(5 + i, 80, item[1][:39], a) + stdscr.addstr(5 + i, 120, str(item[2]), a) + elif menutab == 6: # Address book stdscr.addstr(3, 5, "Label", curses.A_BOLD) stdscr.addstr(3, 40, "Address", curses.A_BOLD) stdscr.hline(4, 5, '-', 41) - for i, item in enumerate(addrbook[max(min(len(addrbook)-curses.LINES+6, abookcur-5), 0):]): - if 6+i < curses.LINES: + for i, item in enumerate(addrbook[max(min(len(addrbook) - curses.LINES + 6, abookcur - 5), 0):]): + if 6 + i < curses.LINES: a = 0 - if i == abookcur - max(min(len(addrbook)-curses.LINES+6, abookcur-5), 0): # Highlight current address + if i == abookcur - max(min(len(addrbook) - curses.LINES + 6, abookcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - stdscr.addstr(5+i, 5, item[0][:34], a) - stdscr.addstr(5+i, 40, item[1][:39], a) - elif menutab == 7: # Blacklist - stdscr.addstr(3, 5, "Type: "+bwtype) + stdscr.addstr(5 + i, 5, item[0][:34], a) + stdscr.addstr(5 + i, 40, item[1][:39], a) + elif menutab == 7: # Blacklist + stdscr.addstr(3, 5, "Type: " + bwtype) stdscr.addstr(4, 5, "Label", curses.A_BOLD) stdscr.addstr(4, 80, "Address", curses.A_BOLD) stdscr.addstr(4, 120, "Enabled", curses.A_BOLD) stdscr.hline(5, 5, '-', 121) - for i, item in enumerate(blacklist[max(min(len(blacklist)-curses.LINES+6, blackcur-5), 0):]): - if 7+i < curses.LINES: + for i, item in enumerate(blacklist[max(min(len(blacklist) - curses.LINES + 6, blackcur - 5), 0):]): + if 7 + i < curses.LINES: a = 0 - if i == blackcur - max(min(len(blacklist)-curses.LINES+6, blackcur-5), 0): # Highlight current address + if i == blackcur - max(min(len(blacklist) - curses.LINES + 6, blackcur - 5), 0): + # Highlight current address a = a | curses.A_REVERSE - if item[2] == True: # Embolden enabled subscriptions + if item[2]: # Embolden enabled subscriptions a = a | curses.A_BOLD - stdscr.addstr(6+i, 5, item[0][:74], a) - stdscr.addstr(6+i, 80, item[1][:39], a) - stdscr.addstr(6+i, 120, str(item[2]), a) - elif menutab == 8: # Network status + stdscr.addstr(6 + i, 5, item[0][:74], a) + stdscr.addstr(6 + i, 80, item[1][:39], a) + stdscr.addstr(6 + i, 120, str(item[2]), a) + elif menutab == 8: # Network status # Connection data connected_hosts = network.stats.connectedHostsList() stdscr.addstr( @@ -228,51 +261,63 @@ def drawtab(stdscr): for i, item in enumerate(streamcount): if i < 4: if i == 0: - stdscr.addstr(8+i, 6, "?") + stdscr.addstr(8 + i, 6, "?") else: - stdscr.addstr(8+i, 6, str(i)) - stdscr.addstr(8+i, 18, str(item).ljust(2)) - + stdscr.addstr(8 + i, 6, str(i)) + stdscr.addstr(8 + i, 18, str(item).ljust(2)) + # Uptime and processing data - stdscr.addstr(6, 35, "Since startup on "+l10n.formatTimestamp(startuptime, False)) - stdscr.addstr(7, 40, "Processed "+str(shared.numberOfMessagesProcessed).ljust(4)+" person-to-person messages.") - stdscr.addstr(8, 40, "Processed "+str(shared.numberOfBroadcastsProcessed).ljust(4)+" broadcast messages.") - stdscr.addstr(9, 40, "Processed "+str(shared.numberOfPubkeysProcessed).ljust(4)+" public keys.") - + stdscr.addstr(6, 35, "Since startup on " + l10n.formatTimestamp(startuptime, False)) + stdscr.addstr(7, 40, "Processed " + str( + shared.numberOfMessagesProcessed).ljust(4) + " person-to-person messages.") + stdscr.addstr(8, 40, "Processed " + str( + shared.numberOfBroadcastsProcessed).ljust(4) + " broadcast messages.") + stdscr.addstr(9, 40, "Processed " + str( + shared.numberOfPubkeysProcessed).ljust(4) + " public keys.") + # Inventory data - stdscr.addstr(11, 35, "Inventory lookups per second: "+str(inventorydata).ljust(3)) - + stdscr.addstr(11, 35, "Inventory lookups per second: " + str(inventorydata).ljust(3)) + # Log stdscr.addstr(13, 6, "Log", curses.A_BOLD) n = log.count('\n') if n > 0: l = log.split('\n') if n > 512: - del l[:(n-256)] + del l[:(n - 256)] logpad.erase() n = len(l) for i, item in enumerate(l): a = 0 - if len(item) > 0 and item[0] == '!': + if item and item[0] == '!': a = curses.color_pair(1) item = item[1:] logpad.addstr(i, 0, item, a) - logpad.refresh(n-curses.LINES+2, 0, 14, 6, curses.LINES-2, curses.COLS-7) + logpad.refresh(n - curses.LINES + 2, 0, 14, 6, curses.LINES - 2, curses.COLS - 7) stdscr.refresh() + def redraw(stdscr): + """Redraw menu""" stdscr.erase() stdscr.border() drawmenu(stdscr) stdscr.refresh() + + def dialogreset(stdscr): + """Resetting dialogue""" stdscr.clear() stdscr.keypad(1) curses.curs_set(0) + + +# pylint: disable=too-many-branches, too-many-statements def handlech(c, stdscr): + # pylint: disable=redefined-outer-name, too-many-nested-blocks, too-many-locals, global-statement if c != curses.ERR: global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur - if c in range(256): + if c in range(256): if chr(c) in '12345678': global menutab menutab = int(chr(c)) @@ -284,17 +329,27 @@ def handlech(c, stdscr): d = Dialog(dialog="dialog") if menutab == 1: set_background_title(d, "Inbox Message Dialog Box") - r, t = d.menu("Do what with \""+inbox[inboxcur][5]+"\" from \""+inbox[inboxcur][3]+"\"?", - choices=[("1", "View message"), + r, t = d.menu( + "Do what with \"" + inbox[inboxcur][5] + "\" from \"" + inbox[inboxcur][3] + "\"?", + choices=[ + ("1", "View message"), ("2", "Mark message as unread"), ("3", "Reply"), ("4", "Add sender to Address Book"), ("5", "Save message as text file"), ("6", "Move to trash")]) if r == d.DIALOG_OK: - if t == "1": # View - set_background_title(d, "\""+inbox[inboxcur][5]+"\" from \""+inbox[inboxcur][3]+"\" to \""+inbox[inboxcur][1]+"\"") - data = "" + if t == "1": # View + set_background_title( + d, + "\"" + + inbox[inboxcur][5] + + "\" from \"" + + inbox[inboxcur][3] + + "\" to \"" + + inbox[inboxcur][1] + + "\"") + data = "" # pyint: disable=redefined-outer-name ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0]) if ret != []: for row in ret: @@ -302,16 +357,16 @@ def handlech(c, stdscr): data = shared.fixPotentiallyInvalidUTF8Data(data) msg = "" for i, item in enumerate(data.split("\n")): - msg += fill(item, replace_whitespace=False)+"\n" + msg += fill(item, replace_whitespace=False) + "\n" scrollbox(d, unicode(ascii(msg)), 30, 80) sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", inbox[inboxcur][0]) inbox[inboxcur][7] = 1 else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "2": # Mark unread + elif t == "2": # Mark unread sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", inbox[inboxcur][0]) inbox[inboxcur][7] = 0 - elif t == "3": # Reply + elif t == "3": # Reply curses.curs_set(1) m = inbox[inboxcur] fromaddr = m[4] @@ -320,29 +375,31 @@ def handlech(c, stdscr): if fromaddr == item[2] and item[3] != 0: ischan = True break - if not addresses[i][1]: - scrollbox(d, unicode("Sending address disabled, please either enable it or choose a different address.")) + if not addresses[i][1]: # pylint: disable=undefined-loop-variable + scrollbox(d, unicode( + "Sending address disabled, please either enable it" + "or choose a different address.")) return toaddr = m[2] if ischan: toaddr = fromaddr - + subject = m[5] if not m[5][:4] == "Re: ": - subject = "Re: "+m[5] + subject = "Re: " + m[5] body = "" ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", m[0]) if ret != []: body = "\n\n------------------------------------------------------\n" for row in ret: body, = row - + sendMessage(fromaddr, toaddr, ischan, subject, body, True) dialogreset(stdscr) - elif t == "4": # Add to Address Book + elif t == "4": # Add to Address Book addr = inbox[inboxcur][4] - if addr not in [item[1] for i,item in enumerate(addrbook)]: - r, t = d.inputbox("Label for address \""+addr+"\"") + if addr not in [item[1] for i, item in enumerate(addrbook)]: + r, t = d.inputbox("Label for address \"" + addr + "\"") if r == d.DIALOG_OK: label = t sqlExecute("INSERT INTO addressbook VALUES (?,?)", label, addr) @@ -352,61 +409,85 @@ def handlech(c, stdscr): addrbook.reverse() else: scrollbox(d, unicode("The selected address is already in the Address Book.")) - elif t == "5": # Save message - set_background_title(d, "Save \""+inbox[inboxcur][5]+"\" as text file") - r, t = d.inputbox("Filename", init=inbox[inboxcur][5]+".txt") + elif t == "5": # Save message + set_background_title(d, "Save \"" + inbox[inboxcur][5] + "\" as text file") + r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt") if r == d.DIALOG_OK: msg = "" ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0]) if ret != []: for row in ret: msg, = row - fh = open(t, "a") # Open in append mode just in case + fh = open(t, "a") # Open in append mode just in case fh.write(msg) fh.close() else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "6": # Move to trash + elif t == "6": # Move to trash sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", inbox[inboxcur][0]) del inbox[inboxcur] - scrollbox(d, unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it.")) + scrollbox(d, unicode( + "Message moved to trash. There is no interface to view your trash," + " \nbut the message is still on disk if you are desperate to recover it.")) elif menutab == 2: a = "" - if addresses[addrcur][3] != 0: # if current address is a chan + if addresses[addrcur][3] != 0: # if current address is a chan a = addresses[addrcur][2] sendMessage(addresses[addrcur][2], a) elif menutab == 3: set_background_title(d, "Sent Messages Dialog Box") - r, t = d.menu("Do what with \""+sentbox[sentcur][4]+"\" to \""+sentbox[sentcur][0]+"\"?", - choices=[("1", "View message"), + r, t = d.menu( + "Do what with \"" + sentbox[sentcur][4] + "\" to \"" + sentbox[sentcur][0] + "\"?", + choices=[ + ("1", "View message"), ("2", "Move to trash")]) if r == d.DIALOG_OK: - if t == "1": # View - set_background_title(d, "\""+sentbox[sentcur][4]+"\" from \""+sentbox[sentcur][3]+"\" to \""+sentbox[sentcur][1]+"\"") + if t == "1": # View + set_background_title( + d, + "\"" + + sentbox[sentcur][4] + + "\" from \"" + + sentbox[sentcur][3] + + "\" to \"" + + sentbox[sentcur][1] + + "\"") data = "" - ret = sqlQuery("SELECT message FROM sent WHERE subject=? AND ackdata=?", sentbox[sentcur][4], sentbox[sentcur][6]) + ret = sqlQuery( + "SELECT message FROM sent WHERE subject=? AND ackdata=?", + sentbox[sentcur][4], + sentbox[sentcur][6]) if ret != []: for row in ret: data, = row data = shared.fixPotentiallyInvalidUTF8Data(data) msg = "" for i, item in enumerate(data.split("\n")): - msg += fill(item, replace_whitespace=False)+"\n" + msg += fill(item, replace_whitespace=False) + "\n" scrollbox(d, unicode(ascii(msg)), 30, 80) else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "2": # Move to trash - sqlExecute("UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?", sentbox[sentcur][4], sentbox[sentcur][6]) + elif t == "2": # Move to trash + sqlExecute( + "UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?", + sentbox[sentcur][4], + sentbox[sentcur][6]) del sentbox[sentcur] - scrollbox(d, unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it.")) + scrollbox(d, unicode( + "Message moved to trash. There is no interface to view your trash" + " \nbut the message is still on disk if you are desperate to recover it.")) elif menutab == 4: set_background_title(d, "Your Identities Dialog Box") if len(addresses) <= addrcur: - r, t = d.menu("Do what with addresses?", - choices=[("1", "Create new address")]) + r, t = d.menu( + "Do what with addresses?", + choices=[ + ("1", "Create new address")]) else: - r, t = d.menu("Do what with \""+addresses[addrcur][0]+"\" : \""+addresses[addrcur][2]+"\"?", - choices=[("1", "Create new address"), + r, t = d.menu( + "Do what with \"" + addresses[addrcur][0] + "\" : \"" + addresses[addrcur][2] + "\"?", + choices=[ + ("1", "Create new address"), ("2", "Send a message from this address"), ("3", "Rename"), ("4", "Enable"), @@ -414,31 +495,41 @@ def handlech(c, stdscr): ("6", "Delete"), ("7", "Special address behavior")]) if r == d.DIALOG_OK: - if t == "1": # Create new address + if t == "1": # Create new address set_background_title(d, "Create new address") - scrollbox(d, unicode("Here you may generate as many addresses as you like.\n" - "Indeed, creating and abandoning addresses is encouraged.\n" - "Deterministic addresses have several pros and cons:\n" - "\nPros:\n" - " * You can recreate your addresses on any computer from memory\n" - " * You need not worry about backing up your keys.dat file as long as you \n can remember your passphrase\n" - "Cons:\n" - " * You must remember (or write down) your passphrase in order to recreate \n your keys if they are lost\n" - " * You must also remember the address version and stream numbers\n" - " * If you choose a weak passphrase someone may be able to brute-force it \n and then send and receive messages as you")) - r, t = d.menu("Choose an address generation technique", - choices=[("1", "Use a random number generator"), + scrollbox( + d, unicode( + "Here you may generate as many addresses as you like.\n" + "Indeed, creating and abandoning addresses is encouraged.\n" + "Deterministic addresses have several pros and cons:\n" + "\nPros:\n" + " * You can recreate your addresses on any computer from memory\n" + " * You need not worry about backing up your keys.dat file as long as you" + " \n can remember your passphrase\n" + "Cons:\n" + " * You must remember (or write down) your passphrase in order to recreate" + " \n your keys if they are lost\n" + " * You must also remember the address version and stream numbers\n" + " * If you choose a weak passphrase someone may be able to brute-force it" + " \n and then send and receive messages as you")) + r, t = d.menu( + "Choose an address generation technique", + choices=[ + ("1", "Use a random number generator"), ("2", "Use a passphrase")]) if r == d.DIALOG_OK: if t == "1": set_background_title(d, "Randomly generate address") r, t = d.inputbox("Label (not shown to anyone except you)") label = "" - if r == d.DIALOG_OK and len(t) > 0: + if r == d.DIALOG_OK and t: label = t - r, t = d.menu("Choose a stream", - choices=[("1", "Use the most available stream"),("", "(Best if this is the first of many addresses you will create)"), - ("2", "Use the same stream as an existing address"),("", "(Saves you some bandwidth and processing power)")]) + r, t = d.menu( + "Choose a stream", + choices=[("1", "Use the most available stream"), + ("", "(Best if this is the first of many addresses you will create)"), + ("2", "Use the same stream as an existing address"), + ("", "(Saves you some bandwidth and processing power)")]) if r == d.DIALOG_OK: if t == "1": stream = 1 @@ -450,42 +541,69 @@ def handlech(c, stdscr): if r == d.DIALOG_OK: stream = decodeAddress(addrs[int(t)][1])[2] shorten = False - r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", 1 if shorten else 0)]) + r, t = d.checklist( + "Miscellaneous options", + choices=[( + "1", + "Spend time shortening the address", + 1 if shorten else 0)]) if r == d.DIALOG_OK and "1" in t: shorten = True - queues.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) + queues.addressGeneratorQueue.put(( + "createRandomAddress", + 4, + stream, + label, + 1, + "", + shorten)) elif t == "2": set_background_title(d, "Make deterministic addresses") - r, t = d.passwordform("Enter passphrase", - [("Passphrase", 1, 1, "", 2, 1, 64, 128), - ("Confirm passphrase", 3, 1, "", 4, 1, 64, 128)], + r, t = d.passwordform( + "Enter passphrase", + [ + ("Passphrase", 1, 1, "", 2, 1, 64, 128), + ("Confirm passphrase", 3, 1, "", 4, 1, 64, 128)], form_height=4, insecure=True) if r == d.DIALOG_OK: if t[0] == t[1]: passphrase = t[0] - r, t = d.rangebox("Number of addresses to generate", - width=48, min=1, max=99, init=8) + r, t = d.rangebox( + "Number of addresses to generate", + width=48, + min=1, + max=99, + init=8) if r == d.DIALOG_OK: number = t stream = 1 shorten = False - r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", 1 if shorten else 0)]) + r, t = d.checklist( + "Miscellaneous options", + choices=[( + "1", + "Spend time shortening the address", + 1 if shorten else 0)]) if r == d.DIALOG_OK and "1" in t: shorten = True - scrollbox(d, unicode("In addition to your passphrase, be sure to remember the following numbers:\n" - "\n * Address version number: "+str(4)+"\n" - " * Stream number: "+str(stream))) - queues.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) + scrollbox( + d, unicode( + "In addition to your passphrase, be sure to remember the" + " following numbers:\n" + "\n * Address version number: " + str(4) + "\n" + " * Stream number: " + str(stream))) + queues.addressGeneratorQueue.put( + ('createDeterministicAddresses', 4, stream, + "unused deterministic address", number, + str(passphrase), shorten)) else: scrollbox(d, unicode("Passphrases do not match")) - elif t == "2": # Send a message + elif t == "2": # Send a message a = "" - if addresses[addrcur][3] != 0: # if current address is a chan + if addresses[addrcur][3] != 0: # if current address is a chan a = addresses[addrcur][2] sendMessage(addresses[addrcur][2], a) - elif t == "3": # Rename address label + elif t == "3": # Rename address label a = addresses[addrcur][2] label = addresses[addrcur][0] r, t = d.inputbox("New address label", init=label) @@ -495,72 +613,79 @@ def handlech(c, stdscr): # Write config BMConfigParser().save() addresses[addrcur][0] = label - elif t == "4": # Enable address + elif t == "4": # Enable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "true") # Set config + BMConfigParser().set(a, "enabled", "true") # Set config # Write config BMConfigParser().save() # Change color if BMConfigParser().safeGetBoolean(a, 'chan'): - addresses[addrcur][3] = 9 # orange + addresses[addrcur][3] = 9 # orange elif BMConfigParser().safeGetBoolean(a, 'mailinglist'): - addresses[addrcur][3] = 5 # magenta + addresses[addrcur][3] = 5 # magenta else: - addresses[addrcur][3] = 0 # black + addresses[addrcur][3] = 0 # black addresses[addrcur][1] = True - shared.reloadMyAddressHashes() # Reload address hashes - elif t == "5": # Disable address + shared.reloadMyAddressHashes() # Reload address hashes + elif t == "5": # Disable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "false") # Set config - addresses[addrcur][3] = 8 # Set color to gray + BMConfigParser().set(a, "enabled", "false") # Set config + addresses[addrcur][3] = 8 # Set color to gray # Write config BMConfigParser().save() addresses[addrcur][1] = False - shared.reloadMyAddressHashes() # Reload address hashes - elif t == "6": # Delete address + shared.reloadMyAddressHashes() # Reload address hashes + elif t == "6": # Delete address r, t = d.inputbox("Type in \"I want to delete this address\"", width=50) if r == d.DIALOG_OK and t == "I want to delete this address": - BMConfigParser().remove_section(addresses[addrcur][2]) - BMConfigParser().save() - del addresses[addrcur] - elif t == "7": # Special address behavior + BMConfigParser().remove_section(addresses[addrcur][2]) + BMConfigParser().save() + del addresses[addrcur] + elif t == "7": # Special address behavior a = addresses[addrcur][2] set_background_title(d, "Special address behavior") if BMConfigParser().safeGetBoolean(a, "chan"): - scrollbox(d, unicode("This is a chan address. You cannot use it as a pseudo-mailing list.")) + scrollbox(d, unicode( + "This is a chan address. You cannot use it as a pseudo-mailing list.")) else: m = BMConfigParser().safeGetBoolean(a, "mailinglist") - r, t = d.radiolist("Select address behavior", - choices=[("1", "Behave as a normal address", not m), + r, t = d.radiolist( + "Select address behavior", + choices=[ + ("1", "Behave as a normal address", not m), ("2", "Behave as a pseudo-mailing-list address", m)]) if r == d.DIALOG_OK: - if t == "1" and m == True: + if t == "1" and m: BMConfigParser().set(a, "mailinglist", "false") if addresses[addrcur][1]: - addresses[addrcur][3] = 0 # Set color to black + addresses[addrcur][3] = 0 # Set color to black else: - addresses[addrcur][3] = 8 # Set color to gray - elif t == "2" and m == False: + addresses[addrcur][3] = 8 # Set color to gray + elif t == "2" and m is False: try: mn = BMConfigParser().get(a, "mailinglistname") except ConfigParser.NoOptionError: - mn = "" + mn = "" r, t = d.inputbox("Mailing list name", init=mn) if r == d.DIALOG_OK: mn = t BMConfigParser().set(a, "mailinglist", "true") BMConfigParser().set(a, "mailinglistname", mn) - addresses[addrcur][3] = 6 # Set color to magenta + addresses[addrcur][3] = 6 # Set color to magenta # Write config BMConfigParser().save() elif menutab == 5: set_background_title(d, "Subscriptions Dialog Box") if len(subscriptions) <= subcur: - r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", - choices=[("1", "Add new subscription")]) + r, t = d.menu( + "Do what with subscription to \"" + subscriptions[subcur][0] + "\"?", + choices=[ + ("1", "Add new subscription")]) else: - r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", - choices=[("1", "Add new subscription"), + r, t = d.menu( + "Do what with subscription to \"" + subscriptions[subcur][0] + "\"?", + choices=[ + ("1", "Add new subscription"), ("2", "Delete this subscription"), ("3", "Enable"), ("4", "Disable")]) @@ -581,27 +706,39 @@ def handlech(c, stdscr): sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True) shared.reloadBroadcastSendersForWhichImWatching() elif t == "2": - r, t = d.inpuxbox("Type in \"I want to delete this subscription\"") + r, t = d.inputbox("Type in \"I want to delete this subscription\"") if r == d.DIALOG_OK and t == "I want to delete this subscription": - sqlExecute("DELETE FROM subscriptions WHERE label=? AND address=?", subscriptions[subcur][0], subscriptions[subcur][1]) - shared.reloadBroadcastSendersForWhichImWatching() - del subscriptions[subcur] + sqlExecute( + "DELETE FROM subscriptions WHERE label=? AND address=?", + subscriptions[subcur][0], + subscriptions[subcur][1]) + shared.reloadBroadcastSendersForWhichImWatching() + del subscriptions[subcur] elif t == "3": - sqlExecute("UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?", subscriptions[subcur][0], subscriptions[subcur][1]) + sqlExecute( + "UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?", + subscriptions[subcur][0], + subscriptions[subcur][1]) shared.reloadBroadcastSendersForWhichImWatching() subscriptions[subcur][2] = True elif t == "4": - sqlExecute("UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?", subscriptions[subcur][0], subscriptions[subcur][1]) + sqlExecute( + "UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?", + subscriptions[subcur][0], + subscriptions[subcur][1]) shared.reloadBroadcastSendersForWhichImWatching() subscriptions[subcur][2] = False elif menutab == 6: set_background_title(d, "Address Book Dialog Box") if len(addrbook) <= abookcur: - r, t = d.menu("Do what with addressbook?", + r, t = d.menu( + "Do what with addressbook?", choices=[("3", "Add new address to Address Book")]) else: - r, t = d.menu("Do what with \""+addrbook[abookcur][0]+"\" : \""+addrbook[abookcur][1]+"\"", - choices=[("1", "Send a message to this address"), + r, t = d.menu( + "Do what with \"" + addrbook[abookcur][0] + "\" : \"" + addrbook[abookcur][1] + "\"", + choices=[ + ("1", "Send a message to this address"), ("2", "Subscribe to this address"), ("3", "Add new address to Address Book"), ("4", "Delete this address")]) @@ -623,8 +760,8 @@ def handlech(c, stdscr): r, t = d.inputbox("Input new address") if r == d.DIALOG_OK: addr = t - if addr not in [item[1] for i,item in enumerate(addrbook)]: - r, t = d.inputbox("Label for address \""+addr+"\"") + if addr not in [item[1] for i, item in enumerate(addrbook)]: + r, t = d.inputbox("Label for address \"" + addr + "\"") if r == d.DIALOG_OK: sqlExecute("INSERT INTO addressbook VALUES (?,?)", t, addr) # Prepend entry @@ -636,25 +773,39 @@ def handlech(c, stdscr): elif t == "4": r, t = d.inputbox("Type in \"I want to delete this Address Book entry\"") if r == d.DIALOG_OK and t == "I want to delete this Address Book entry": - sqlExecute("DELETE FROM addressbook WHERE label=? AND address=?", addrbook[abookcur][0], addrbook[abookcur][1]) + sqlExecute( + "DELETE FROM addressbook WHERE label=? AND address=?", + addrbook[abookcur][0], + addrbook[abookcur][1]) del addrbook[abookcur] elif menutab == 7: set_background_title(d, "Blacklist Dialog Box") - r, t = d.menu("Do what with \""+blacklist[blackcur][0]+"\" : \""+blacklist[blackcur][1]+"\"?", - choices=[("1", "Delete"), + r, t = d.menu( + "Do what with \"" + blacklist[blackcur][0] + "\" : \"" + blacklist[blackcur][1] + "\"?", + choices=[ + ("1", "Delete"), ("2", "Enable"), ("3", "Disable")]) if r == d.DIALOG_OK: if t == "1": r, t = d.inputbox("Type in \"I want to delete this Blacklist entry\"") if r == d.DIALOG_OK and t == "I want to delete this Blacklist entry": - sqlExecute("DELETE FROM blacklist WHERE label=? AND address=?", blacklist[blackcur][0], blacklist[blackcur][1]) + sqlExecute( + "DELETE FROM blacklist WHERE label=? AND address=?", + blacklist[blackcur][0], + blacklist[blackcur][1]) del blacklist[blackcur] elif t == "2": - sqlExecute("UPDATE blacklist SET enabled=1 WHERE label=? AND address=?", blacklist[blackcur][0], blacklist[blackcur][1]) + sqlExecute( + "UPDATE blacklist SET enabled=1 WHERE label=? AND address=?", + blacklist[blackcur][0], + blacklist[blackcur][1]) blacklist[blackcur][2] = True - elif t== "3": - sqlExecute("UPDATE blacklist SET enabled=0 WHERE label=? AND address=?", blacklist[blackcur][0], blacklist[blackcur][1]) + elif t == "3": + sqlExecute( + "UPDATE blacklist SET enabled=0 WHERE label=? AND address=?", + blacklist[blackcur][0], + blacklist[blackcur][1]) blacklist[blackcur][2] = False dialogreset(stdscr) else: @@ -672,17 +823,17 @@ def handlech(c, stdscr): if menutab == 7 and blackcur > 0: blackcur -= 1 elif c == curses.KEY_DOWN: - if menutab == 1 and inboxcur < len(inbox)-1: + if menutab == 1 and inboxcur < len(inbox) - 1: inboxcur += 1 - if (menutab == 2 or menutab == 4) and addrcur < len(addresses)-1: + if (menutab == 2 or menutab == 4) and addrcur < len(addresses) - 1: addrcur += 1 - if menutab == 3 and sentcur < len(sentbox)-1: + if menutab == 3 and sentcur < len(sentbox) - 1: sentcur += 1 - if menutab == 5 and subcur < len(subscriptions)-1: + if menutab == 5 and subcur < len(subscriptions) - 1: subcur += 1 - if menutab == 6 and abookcur < len(addrbook)-1: + if menutab == 6 and abookcur < len(addrbook) - 1: abookcur += 1 - if menutab == 7 and blackcur < len(blacklist)-1: + if menutab == 7 and blackcur < len(blacklist) - 1: blackcur += 1 elif c == curses.KEY_HOME: if menutab == 1: @@ -699,38 +850,47 @@ def handlech(c, stdscr): blackcur = 0 elif c == curses.KEY_END: if menutab == 1: - inboxcur = len(inbox)-1 + inboxcur = len(inbox) - 1 if menutab == 2 or menutab == 4: - addrcur = len(addresses)-1 + addrcur = len(addresses) - 1 if menutab == 3: - sentcur = len(sentbox)-1 + sentcur = len(sentbox) - 1 if menutab == 5: - subcur = len(subscriptions)-1 + subcur = len(subscriptions) - 1 if menutab == 6: - abookcur = len(addrbook)-1 + abookcur = len(addrbook) - 1 if menutab == 7: - blackcur = len(blackcur)-1 + blackcur = len(blackcur) - 1 redraw(stdscr) + + +# pylint: disable=too-many-locals, too-many-arguments def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=False): + """Method for message sending""" if sender == "": return d = Dialog(dialog="dialog") set_background_title(d, "Send a message") if recv == "": - r, t = d.inputbox("Recipient address (Cancel to load from the Address Book or leave blank to broadcast)", 10, 60) + r, t = d.inputbox( + "Recipient address (Cancel to load from the Address Book or leave blank to broadcast)", + 10, + 60) if r != d.DIALOG_OK: - global menutab + global menutab # pylint: disable=global-statement menutab = 6 return recv = t - if broadcast == None and sender != recv: - r, t = d.radiolist("How to send the message?", - choices=[("1", "Send to one or more specific people", 1), + if broadcast is None and sender != recv: + r, t = d.radiolist( + "How to send the message?", + choices=[ + ("1", "Send to one or more specific people", 1), ("2", "Broadcast to everyone who is subscribed to your address", 0)]) if r != d.DIALOG_OK: return broadcast = False - if t == "2": # Broadcast + if t == "2": # Broadcast broadcast = True if subject == "" or reply: r, t = d.inputbox("Message subject", width=60, init=subject) @@ -748,9 +908,10 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F recvlist = [] for i, item in enumerate(recv.replace(",", ";").split(";")): recvlist.append(item.strip()) - list(set(recvlist)) # Remove exact duplicates + list(set(recvlist)) # Remove exact duplicates for addr in recvlist: if addr != "": + # pylint: disable=redefined-outer-name status, version, stream, ripe = decodeAddress(addr) if status != "success": set_background_title(d, "Recipient address error") @@ -762,13 +923,17 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F elif status == "invalidcharacters": err += "The address contains invalid characters." elif status == "versiontoohigh": - err += "The address version is too high. Either you need to upgrade your Bitmessage software or your acquaintance is doing something clever." + err += ("The address version is too high. Either you need to upgrade your Bitmessage software" + " or your acquaintance is doing something clever.") elif status == "ripetooshort": - err += "Some data encoded in the address is too short. There might be something wrong with the software of your acquaintance." + err += ("Some data encoded in the address is too short. There might be something wrong with" + " the software of your acquaintance.") elif status == "ripetoolong": - err += "Some data encoded in the address is too long. There might be something wrong with the software of your acquaintance." + err += ("Some data encoded in the address is too long. There might be something wrong with" + " the software of your acquaintance.") elif status == "varintmalformed": - err += "Some data encoded in the address is malformed. There might be something wrong with the software of your acquaintance." + err += ("Some data encoded in the address is malformed. There might be something wrong with" + " the software of your acquaintance.") else: err += "It is unknown what is wrong with the address." scrollbox(d, unicode(err)) @@ -776,17 +941,24 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F addr = addBMIfNotPresent(addr) if version > 4 or version <= 1: set_background_title(d, "Recipient address error") - scrollbox(d, unicode("Could not understand version number " + version + "of address" + addr + ".")) + scrollbox(d, unicode( + "Could not understand version number " + + version + + "of address" + + addr + + ".")) continue if stream > 1 or stream == 0: set_background_title(d, "Recipient address error") - scrollbox(d, unicode("Bitmessage currently only supports stream numbers of 1, unlike as requested for address " + addr + ".")) + scrollbox(d, unicode( + "Bitmessage currently only supports stream numbers of 1," + "unlike as requested for address " + addr + ".")) continue if not network.stats.connectedHostsList(): set_background_title(d, "Not connected warning") scrollbox(d, unicode("Because you are not currently connected to the network, ")) stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) + ackdata = genAckPayload(decodeAddress(addr)[2], stealthLevel) sqlExecute( "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", @@ -796,22 +968,22 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "msgqueued", - 0, # retryNumber + 0, # retryNumber "sent", - 2, # encodingType + 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) queues.workerQueue.put(("sendmessage", addr)) - else: # Broadcast + else: # Broadcast if recv == "": set_background_title(d, "Empty sender error") scrollbox(d, unicode("You must specify an address to send the message from.")) else: # dummy ackdata, no need for stealth - ackdata = genAckPayload(streamNumber, 0) + ackdata = genAckPayload(decodeAddress(addr)[2], 0) recv = BROADCAST_STR ripe = "" sqlExecute( @@ -823,21 +995,24 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "broadcastqueued", - 0, # retryNumber - "sent", # folder - 2, # encodingType + 0, # retryNumber + "sent", # folder + 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) queues.workerQueue.put(('sendbroadcast', '')) + +# pylint: disable=redefined-outer-name, too-many-locals def loadInbox(): + """Load the list of messages""" sys.stdout = sys.__stdout__ - print("Loading inbox messages...") + print "Loading inbox messages..." sys.stdout = printlog - + where = "toaddress || fromaddress || subject || message" what = "%%" ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read @@ -847,7 +1022,7 @@ def loadInbox(): for row in ret: msgid, toaddr, fromaddr, subject, received, read = row subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject)) - + # Set label for to address try: if toaddr == BROADCAST_STR: @@ -859,17 +1034,17 @@ def loadInbox(): if tolabel == "": tolabel = toaddr tolabel = shared.fixPotentiallyInvalidUTF8Data(tolabel) - + # Set label for from address fromlabel = "" if BMConfigParser().has_section(fromaddr): fromlabel = BMConfigParser().get(fromaddr, "label") - if fromlabel == "": # Check Address Book + if fromlabel == "": # Check Address Book qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) if qr != []: for r in qr: fromlabel, = r - if fromlabel == "": # Check Subscriptions + if fromlabel == "": # Check Subscriptions qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", fromaddr) if qr != []: for r in qr: @@ -877,16 +1052,19 @@ def loadInbox(): if fromlabel == "": fromlabel = fromaddr fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel) - + # Load into array - inbox.append([msgid, tolabel, toaddr, fromlabel, fromaddr, subject, - l10n.formatTimestamp(received, False), read]) + inbox.append([msgid, tolabel, toaddr, fromlabel, fromaddr, subject, l10n.formatTimestamp( + received, False), read]) inbox.reverse() + + def loadSent(): + """Load the messages that sent""" sys.stdout = sys.__stdout__ - print("Loading sent messages...") + print "Loading sent messages..." sys.stdout = printlog - + where = "toaddress || fromaddress || subject || message" what = "%%" ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime @@ -896,7 +1074,7 @@ def loadSent(): for row in ret: toaddr, fromaddr, subject, status, ackdata, lastactiontime = row subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject)) - + # Set label for to address tolabel = "" qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", toaddr) @@ -913,14 +1091,14 @@ def loadSent(): tolabel = BMConfigParser().get(toaddr, "label") if tolabel == "": tolabel = toaddr - + # Set label for from address fromlabel = "" if BMConfigParser().has_section(fromaddr): fromlabel = BMConfigParser().get(fromaddr, "label") if fromlabel == "": fromlabel = fromaddr - + # Set status string if status == "awaitingpubkey": statstr = "Waiting for their public key. Will request it again soon" @@ -930,20 +1108,20 @@ def loadSent(): statstr = "Message queued" elif status == "msgsent": t = l10n.formatTimestamp(lastactiontime, False) - statstr = "Message sent at "+t+".Waiting for acknowledgement." + statstr = "Message sent at " + t + ".Waiting for acknowledgement." elif status == "msgsentnoackexpected": t = l10n.formatTimestamp(lastactiontime, False) - statstr = "Message sent at "+t+"." + statstr = "Message sent at " + t + "." elif status == "doingmsgpow": statstr = "The proof of work required to send the message has been queued." elif status == "ackreceived": t = l10n.formatTimestamp(lastactiontime, False) - statstr = "Acknowledgment of the message received at "+t+"." + statstr = "Acknowledgment of the message received at " + t + "." elif status == "broadcastqueued": statstr = "Broadcast queued." elif status == "broadcastsent": t = l10n.formatTimestamp(lastactiontime, False) - statstr = "Broadcast sent at "+t+"." + statstr = "Broadcast sent at " + t + "." elif status == "forcepow": statstr = "Forced difficulty override. Message will start sending soon." elif status == "badkey": @@ -952,31 +1130,47 @@ def loadSent(): statstr = "Error: The work demanded by the recipient is more difficult than you are willing to do." else: t = l10n.formatTimestamp(lastactiontime, False) - statstr = "Unknown status "+status+" at "+t+"." - + statstr = "Unknown status " + status + " at " + t + "." + # Load into array - sentbox.append([tolabel, toaddr, fromlabel, fromaddr, subject, statstr, ackdata, + sentbox.append([ + tolabel, + toaddr, + fromlabel, + fromaddr, + subject, + statstr, + ackdata, l10n.formatTimestamp(lastactiontime, False)]) sentbox.reverse() + + def loadAddrBook(): + """Load address book""" sys.stdout = sys.__stdout__ - print("Loading address book...") + print "Loading address book..." sys.stdout = printlog - + ret = sqlQuery("SELECT label, address FROM addressbook") for row in ret: label, addr = row label = shared.fixPotentiallyInvalidUTF8Data(label) addrbook.append([label, addr]) addrbook.reverse() + + def loadSubscriptions(): + """Load subscription functionality""" ret = sqlQuery("SELECT label, address, enabled FROM subscriptions") for row in ret: label, address, enabled = row subscriptions.append([label, address, enabled]) subscriptions.reverse() + + def loadBlackWhiteList(): - global bwtype + """load black/white list""" + global bwtype # pylint: disable=global-statement bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist") if bwtype == "black": ret = sqlQuery("SELECT label, address, enabled FROM blacklist") @@ -987,51 +1181,53 @@ def loadBlackWhiteList(): blacklist.append([label, address, enabled]) blacklist.reverse() + def runwrapper(): sys.stdout = printlog - #sys.stderr = errlog - + # sys.stderr = errlog + # Load messages from database loadInbox() loadSent() loadAddrBook() loadSubscriptions() loadBlackWhiteList() - + stdscr = curses.initscr() - - global logpad + + global logpad # pylint: disable=global-statement logpad = curses.newpad(1024, curses.COLS) - + stdscr.nodelay(0) curses.curs_set(0) stdscr.timeout(1000) - + curses.wrapper(run) doShutdown() + def run(stdscr): # Schedule inventory lookup data resetlookups() - + # Init color pairs if curses.has_colors(): - curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) # red - curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) # green - curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) # yellow - curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK) # blue - curses.init_pair(5, curses.COLOR_MAGENTA, curses.COLOR_BLACK) # magenta - curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) # cyan - curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK) # white + curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) # red + curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) # green + curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) # yellow + curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK) # blue + curses.init_pair(5, curses.COLOR_MAGENTA, curses.COLOR_BLACK) # magenta + curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) # cyan + curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK) # white if curses.can_change_color(): - curses.init_color(8, 500, 500, 500) # gray + curses.init_color(8, 500, 500, 500) # gray curses.init_pair(8, 8, 0) - curses.init_color(9, 844, 465, 0) # orange + curses.init_color(9, 844, 465, 0) # orange curses.init_pair(9, 9, 0) else: - curses.init_pair(8, curses.COLOR_WHITE, curses.COLOR_BLACK) # grayish - curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish - + curses.init_pair(8, curses.COLOR_WHITE, curses.COLOR_BLACK) # grayish + curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish + # Init list of address in 'Your Identities' tab configSections = BMConfigParser().addresses() for addressInKeysFile in configSections: @@ -1039,27 +1235,29 @@ def run(stdscr): addresses.append([BMConfigParser().get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) # Set address color if not isEnabled: - addresses[len(addresses)-1].append(8) # gray + addresses[len(addresses) - 1].append(8) # gray elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'): - addresses[len(addresses)-1].append(9) # orange + addresses[len(addresses) - 1].append(9) # orange elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'): - addresses[len(addresses)-1].append(5) # magenta + addresses[len(addresses) - 1].append(5) # magenta else: - addresses[len(addresses)-1].append(0) # black + addresses[len(addresses) - 1].append(0) # black addresses.reverse() - + stdscr.clear() redraw(stdscr) - while quit == False: + while quit is False: drawtab(stdscr) handlech(stdscr.getch(), stdscr) + def doShutdown(): + """Shutting the app down""" sys.stdout = sys.__stdout__ - print("Shutting down...") + print "Shutting down..." sys.stdout = printlog shutdown.doCleanShutdown() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ - - os._exit(0) + + os._exit(0) # pylint: disable=protected-access From 7d0e23e31ae7bcac700e7b3d78f58c3cd8f4b353 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 23 Sep 2019 17:53:59 +0300 Subject: [PATCH 117/306] Delete from addressbook only by address (Fixes: #1484) --- src/bitmessageqt/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 94c00e38..00b0f4e5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3191,8 +3191,7 @@ class MyForm(settingsmixin.SMainWindow): 0].row() item = self.ui.tableWidgetAddressBook.item(currentRow, 0) sqlExecute( - 'DELETE FROM addressbook WHERE label=? AND address=?', - item.label, item.address) + 'DELETE FROM addressbook WHERE address=?', item.address) self.ui.tableWidgetAddressBook.removeRow(currentRow) self.rerenderMessagelistFromLabels() self.rerenderMessagelistToLabels() From 42a89ad3672678985f6fd14d531ffd6c84283717 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 23 Sep 2019 18:15:31 +0300 Subject: [PATCH 118/306] Delete from addressbook by pressing DEL --- src/bitmessageqt/__init__.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 00b0f4e5..440d36b2 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -781,6 +781,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.treeWidgetSubscriptions.keyPressEvent = self.treeWidgetKeyPressEvent self.ui.treeWidgetChans.keyPressEvent = self.treeWidgetKeyPressEvent + # Key press in addressbook + self.ui.tableWidgetAddressBook.keyPressEvent = self.addressbookKeyPressEvent + # Key press in messagelist self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetKeyPressEvent self.ui.tableWidgetInboxSubscriptions.keyPressEvent = self.tableWidgetKeyPressEvent @@ -1450,6 +1453,15 @@ class MyForm(settingsmixin.SMainWindow): def treeWidgetKeyPressEvent(self, event): return self.handleKeyPress(event, self.getCurrentTreeWidget()) + # addressbook + def addressbookKeyPressEvent(self, event): + """Handle keypress event in addressbook widget""" + if event.key() == QtCore.Qt.Key_Delete: + self.on_action_AddressBookDelete() + else: + return QtGui.QTableWidget.keyPressEvent( + self.ui.tableWidgetAddressBook, event) + # inbox / sent def tableWidgetKeyPressEvent(self, event): return self.handleKeyPress(event, self.getCurrentMessagelist()) @@ -1458,11 +1470,12 @@ class MyForm(settingsmixin.SMainWindow): def textEditKeyPressEvent(self, event): return self.handleKeyPress(event, self.getCurrentMessageTextedit()) - def handleKeyPress(self, event, focus = None): + def handleKeyPress(self, event, focus=None): + """This method handles keypress events for all widgets on MyForm""" messagelist = self.getCurrentMessagelist() folder = self.getCurrentFolder() if event.key() == QtCore.Qt.Key_Delete: - if isinstance (focus, MessageView) or isinstance(focus, QtGui.QTableWidget): + if isinstance(focus, MessageView) or isinstance(focus, QtGui.QTableWidget): if folder == "sent": self.on_action_SentTrash() else: @@ -1498,17 +1511,17 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setFocus() event.ignore() elif event.key() == QtCore.Qt.Key_F: - searchline = self.getCurrentSearchLine(retObj = True) + searchline = self.getCurrentSearchLine(retObj=True) if searchline: searchline.setFocus() event.ignore() if not event.isAccepted(): return - if isinstance (focus, MessageView): + if isinstance(focus, MessageView): return MessageView.keyPressEvent(focus, event) - elif isinstance (focus, QtGui.QTableWidget): + elif isinstance(focus, QtGui.QTableWidget): return QtGui.QTableWidget.keyPressEvent(focus, event) - elif isinstance (focus, QtGui.QTreeWidget): + elif isinstance(focus, QtGui.QTreeWidget): return QtGui.QTreeWidget.keyPressEvent(focus, event) # menu button 'manage keys' From ace05e151ceb20e9a4b95563782e70096af029f5 Mon Sep 17 00:00:00 2001 From: Navjot Date: Tue, 24 Sep 2019 20:51:34 +0530 Subject: [PATCH 119/306] worked on android application popup responsive functionality --- src/bitmessagekivy/main.kv | 23 +++++--- src/bitmessagekivy/mpybit.py | 51 +++--------------- .../BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png | Bin 461 -> 0 bytes .../BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png | Bin 475 -> 0 bytes 4 files changed, 23 insertions(+), 51 deletions(-) delete mode 100644 src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png delete mode 100644 src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1fdb29f0..920ca2ef 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -72,9 +72,9 @@ on_text:app.getCurrentAccountData(self.text) Image: source: app.get_default_image() - x: self.width/4-2 - y: self.parent.y + self.parent.height/2 - self.height + 14 - size: 28, 28 + x: self.width/6 + y: self.parent.y + self.parent.height/4 + size: self.parent.height/2, self.parent.height/2 ArrowImg: NavigationDrawerIconButton: id: inbox_cnt @@ -821,11 +821,13 @@ NavigationLayout: : id: popup + size_hint : (None,None) + height: 2*(label.height + address.height) + 10 + width :app.window_size[0] - app.window_size[0]/10 title: 'add contact\'s' background: './images/popup.jpeg' title_size: sp(20) title_color: 0.4, 0.3765, 0.3451, 1 - size_hint: 1, 1 auto_dismiss: False separator_color: 0.3529, 0.3922, 0.102, 0.7 BoxLayout: @@ -1050,19 +1052,23 @@ NavigationLayout: : id: myadd_popup + size_hint : (None,None) + height: 4.5*(myaddr_label.height+ my_add_btn.children[0].height) + width :app.window_size[0] - app.window_size[0]/10 background: './images/popup.jpeg' - separator_height: 0 auto_dismiss: False + separator_height: 0 BoxLayout: + id: myadd_popup_box size_hint_y: None spacing:dp(70) - id: myadd_popup_box orientation: 'vertical' BoxLayout: size_hint_y: None orientation: 'vertical' spacing:dp(25) MDLabel: + id: myaddr_label font_style: 'Title' theme_text_color: 'Primary' text: "Label" @@ -1087,6 +1093,7 @@ NavigationLayout: font_size: '15sp' halign: 'left' BoxLayout: + id: my_add_btn spacing:5 orientation: 'horizontal' MDRaisedButton: @@ -1125,6 +1132,9 @@ NavigationLayout: : id: addbook_popup + size_hint : (None,None) + height: 4*(add_label.height) + width :app.window_size[0] - app.window_size[0]/10 background: './images/popup.jpeg' separator_height: 0 auto_dismiss: False @@ -1165,6 +1175,7 @@ NavigationLayout: font_size: '15sp' halign: 'left' BoxLayout: + id: addbook_btn spacing:5 orientation: 'horizontal' MDRaisedButton: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ae69a133..0eb2c1e3 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1036,14 +1036,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods state.association = text self.root.ids.sc1.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) - # self.root.ids.sc4.clear_widgets() - # self.root.ids.sc5.clear_widgets() - # self.root.ids.sc16.clear_widgets() - # self.root.ids.sc17.clear_widgets() - # self.root.ids.sc4.add_widget(Sent()) - # self.root.ids.sc5.add_widget(Trash()) - # self.root.ids.sc16.add_widget(Draft()) - # self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = \ @@ -1091,7 +1083,12 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods if BMConfigParser().addresses(): img = identiconGeneration.generate(BMConfigParser().addresses()[0]) self.createFolder('./images/default_identicon/') - img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) + if platform == 'android': + # android_path = os.path.expanduser("~/user/0/org.test.bitapp/files/app/") + android_path = os.path.join(os.environ['ANDROID_PRIVATE'] + '/app/') + img.texture.save('{1}/images/default_identicon/{0}.png'.format(BMConfigParser().addresses()[0], android_path)) + else: + img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' @@ -1125,8 +1122,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.current = 'sent'\ if state.detailPageType == 'sent' else 'inbox' \ if state.detailPageType == 'inbox' else 'draft' - # if state.detailPageType in ['sent', 'inbox']: - # self.add_search_bar() self.back_press() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root @@ -1309,13 +1304,6 @@ class GrashofPopup(Popup): def __init__(self, **kwargs): """Grash of pop screen settings.""" super(GrashofPopup, self).__init__(**kwargs) - print("sssssssssssssssssssiiiiiiiiiiiiiiizzzzzzzzzzeeeeee...............", state.screen_density) - if state.screen_density[0] <= 720: - self.size_hint_y = 0.4 - self.size_hint_x = 0.9 - else: - self.size_hint_y = 0.42 - self.size_hint_x = 0.7 def savecontact(self): """Method is used for Saving Contacts.""" @@ -1497,9 +1485,6 @@ class MailDetail(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ received = {};".format(state.sentMailTime)) - # msg_count_objs.inbox_cnt.badge_text = str( - # int(state.inbox_count) - 1) - # state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].clear_widgets() self.parent.screens[0].add_widget(Inbox()) elif state.detailPageType == 'draft': @@ -1574,12 +1559,6 @@ class MyaddDetailPopup(Popup): def __init__(self, **kwargs): """My Address Details screen setting.""" super(MyaddDetailPopup, self).__init__(**kwargs) - if state.screen_density[0] <= 720: - self.size_hint_y = 0.32 - self.size_hint_x = 0.9 - else: - self.size_hint_y = 0.32 - self.size_hint_x = 0.7 def set_address(self, address, label): """Getting address for displaying details on popup.""" @@ -1612,12 +1591,6 @@ class AddbookDetailPopup(Popup): def __init__(self, **kwargs): """Method used set screen of address detail page.""" super(AddbookDetailPopup, self).__init__(**kwargs) - if state.screen_density[0] <= 720: - self.size_hint_y = 0.35 - self.size_hint_x = 0.95 - else: - self.size_hint_y = 0.35 - self.size_hint_x = 0.7 def set_addbook_data(self, address, label): """Getting address book data for detial dipaly.""" @@ -1694,10 +1667,6 @@ class Draft(Screen): xAddress, account, "draft", where, what, False) if state.msg_counter_objs: state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) - # state.all_count = str(int(state.all_count) + 1) - # state.msg_counter_objs.allmail_cnt.badge_text = state.all_count - # state.msg_counter_objs = None - if queryreturn: src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.draft_cnt.badge_text = str(len(queryreturn)) @@ -1772,13 +1741,7 @@ class Draft(Screen): if int(state.draft_count) > 0: msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) - # msg_count_objs.allmail_cnt.badge_text = str( - # int(state.all_count) - 1) - # msg_count_objs.trash_cnt.badge_text = str( - # int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) - # state.all_count = str(int(state.all_count) - 1) - # state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') @@ -1840,8 +1803,6 @@ class CustomSpinner(Spinner): def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) - # max_value = 2.8 - # self.dropdown_cls.max_height = self.height / 2 * max_value + max_value * 4 self.dropdown_cls.max_height = Window.size[1] / 3 diff --git a/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png b/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png deleted file mode 100644 index 22def0cd17aa71234a0ab0ad8237d8795055e7e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV4ULV;uumf=k1-1yiATf3Z%_+g}Yo_3`3Vh(#~4LV0gIt_b?d2K{=@9ASpvIdCKIWUk%% zP43a<{r?Wk{I$^JBpV@*Ky^y*7BuFk|yI+#2Mtc{jm*(GOW^ fqJoW6;T`WBd$}JI#g{z=MiYaltDnm{r-UW|*9?{7 diff --git a/src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png b/src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png deleted file mode 100644 index c886f8fc069f541c653bb2c07092ae61037b5a95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrU|i(s;uuoF`1aODUseYmR>xTj za)r3sg!BqOyq!B$uYQvHp7r)ifBy=$VtB+Tz~4~8aD-Vwj^QIi2fKp}r9#UY|J42O z*>jqa;lN#n3U&sDa^?rJ3=DU88_F3N3d|Yq;gfj&HM4y;4`)MbwHkB6!+9qeB6g%3 zF^IjJ$wQIQXVsjS50^19H0);lz{kMwj_rUo1H%q!hW88%5AqoHFyoeBm`c5nK?>zP Z^(S8Q{r0V21PmDl22WQ%mvv4FO#s!zm}&q3 From 8f09140513a6fb86ee12165e36bf1353dce3ac21 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 20 Sep 2019 16:49:04 +0530 Subject: [PATCH 120/306] Code fixes 3 regarding PR#11 --- .../recipes/kivymd/__init__.py | 19 ++++--- src/bitmessagekivy/identiconGeneration.py | 4 +- src/bitmessagekivy/kivy_helper_search.py | 16 ++++-- src/bitmessagekivy/mpybit.py | 12 +++-- src/class_singleCleaner.py | 18 ++++--- src/class_singleWorker.py | 9 ++-- src/messagetypes/__init__.py | 13 ++++- src/messagetypes/message.py | 13 ++++- src/messagetypes/vote.py | 13 ++++- src/paths.py | 47 ++++++++++++----- src/pyelliptic/openssl.py | 4 +- src/state.py | 28 +++++----- src/tr.py | 51 +++++++++++++------ 13 files changed, 171 insertions(+), 76 deletions(-) diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py index d7e91a90..5a29bba7 100644 --- a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py @@ -1,24 +1,28 @@ -from os import environ -from os.path import exists, join +""" +src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py +================================= +""" +# pylint: disable=import-error +from os.path import join -import sh -from pythonforandroid.logger import shprint, info_main, info from pythonforandroid.recipe import PythonRecipe # from pythonforandroid.util import ensure_dir class KivyMDRecipe(PythonRecipe): - # This recipe installs KivyMD into the android dist from source + """This recipe installs KivyMD into the android dist from source""" version = 'master' url = 'https://github.com/surbhicis/kivymd/archive/master.zip' depends = ['kivy'] site_packages_name = 'kivymd' call_hostpython_via_targetpython = False - def should_build(self, arch): + def should_build(self, arch): # pylint: disable=no-self-use, unused-argument + """Method helps to build the application""" return True def get_recipe_env(self, arch): + """Method is used for getting all the env paths""" env = super(KivyMDRecipe, self).get_recipe_env(arch) env['PYTHON_ROOT'] = self.ctx.get_python_install_dir() env['CFLAGS'] += ' -I' + env['PYTHON_ROOT'] + '/include/python2.7' @@ -30,8 +34,7 @@ class KivyMDRecipe(PythonRecipe): join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'), join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'), join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'), - join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'), - ]) + join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'), ]) return env diff --git a/src/bitmessagekivy/identiconGeneration.py b/src/bitmessagekivy/identiconGeneration.py index 43e0dbc5..a5dcf3d0 100644 --- a/src/bitmessagekivy/identiconGeneration.py +++ b/src/bitmessagekivy/identiconGeneration.py @@ -2,11 +2,13 @@ src/identiconGeneration.py ================================= """ +# pylint: disable=import-error import hashlib +from io import BytesIO + from PIL import Image from kivy.core.image import Image as CoreImage from kivy.uix.image import Image as kiImage -from io import BytesIO """ Core classes for loading images and converting them to a Texture. The raw image data can be keep in memory for further access """ diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index e2e962c0..a1fe4a99 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -1,7 +1,13 @@ -from helper_sql import * +""" +src/bitmessagekivy/kivy_helper_search.py +================================= +""" +from helper_sql import sqlQuery def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False): + """Method helping for searching mails""" + # pylint: disable=too-many-arguments, too-many-branches if what is not None and what != "": what = "%" + what + "%" else: @@ -9,7 +15,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if folder == "sent" or folder == "draft": sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime + SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' elif folder == "addressbook": sqlStatementBase = '''SELECT label, address From addressbook ''' @@ -27,7 +33,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w else: sqlStatementParts.append(xAddress + " = ? ") sqlArguments.append(account) - if folder is not "addressbook": + if folder != "addressbook": if folder is not None: if folder == "new": folder = "inbox" @@ -50,10 +56,10 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementParts.append(filter_col) if unreadOnly: sqlStatementParts.append("read = 0") - if len(sqlStatementParts) > 0: + if sqlStatementParts: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime DESC" elif folder == "inbox": sqlStatementBase += " ORDER BY received DESC" - return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file + return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 0eb2c1e3..cb4c4fda 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -2,6 +2,7 @@ src/bitmessagekivy/mpybit.py ================================= """ +# pylint: disable=relative-import, unused-variable, import-error, no-name-in-module, too-many-lines import os import time from functools import partial @@ -55,11 +56,8 @@ import queues from semaphores import kivyuisignaler import state from uikivysignaler import UIkivySignaler -# pylint: disable=unused-argument, too-few-public-methods, import-error -import identiconGeneration -import os -from kivy.core.clipboard import Clipboard +import identiconGeneration # pylint: disable=unused-argument, too-few-public-methods @@ -1485,6 +1483,9 @@ class MailDetail(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ received = {};".format(state.sentMailTime)) + # msg_count_objs.inbox_cnt.badge_text = str( + # int(state.inbox_count) - 1) + # state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].clear_widgets() self.parent.screens[0].add_widget(Inbox()) elif state.detailPageType == 'draft': @@ -1987,7 +1988,8 @@ class Archieve(Screen): pass + class Spam(Screen): """Spam Screen show widgets of page.""" - pass \ No newline at end of file + pass diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index eb67fcef..9a2916c7 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -17,11 +17,11 @@ resends getpubkey messages in 5 days (then 10 days, then 20 days, etc...) resends msg messages in 5 days (then 10 days, then 20 days, etc...) """ - +# pylint: disable=relative-import, protected-access import gc import os -import shared import time +import shared import tr from bmconfigparser import BMConfigParser @@ -36,11 +36,12 @@ import state class singleCleaner(StoppableThread): + """Base method that Cleanup knownnodes and handle possible severe exception""" name = "singleCleaner" cycleLength = 300 expireDiscoveredPeers = 300 - def run(self): + def run(self): # pylint: disable=too-many-branches gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 try: @@ -73,7 +74,7 @@ class singleCleaner(StoppableThread): # If we are running as a daemon then we are going to fill up the UI # queue which will never be handled by a UI. We should clear it to # save memory. - # FIXME redundant? + # ..FIXME redundant? if shared.thisapp.daemon or not state.enableGUI: queues.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < \ @@ -128,9 +129,10 @@ class singleCleaner(StoppableThread): "MainWindow", 'Alert: Your disk or data storage volume' ' is full. Bitmessage will now exit.'), - True) + True) )) - # FIXME redundant? + # ..FIXME redundant? + # pylint: disable=no-member if shared.daemon or not state.enableGUI: os._exit(1) @@ -153,7 +155,7 @@ class singleCleaner(StoppableThread): del state.discoveredPeers[k] except KeyError: pass - # TODO: cleanup pending upload / download + # ..TODO: cleanup pending upload / download gc.collect() @@ -162,6 +164,7 @@ class singleCleaner(StoppableThread): def resendPubkeyRequest(address): + """After a long time, method send getpubkey request""" logger.debug( 'It has been a long time and we haven\'t heard a response to our' ' getpubkey request. Sending again.' @@ -186,6 +189,7 @@ def resendPubkeyRequest(address): def resendMsg(ackdata): + """After a long time, method send acknowledgement msg""" logger.debug( 'It has been a long time and we haven\'t heard an acknowledgement' ' to our msg. Sending again.' diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index ca8c0b95..74343459 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -2,8 +2,8 @@ src/class_singleWorker.py ========================= """ -# pylint: disable=protected-access,too-many-branches,too-many-statements,no-self-use,too-many-lines,too-many-locals - +# pylint: disable=protected-access,too-many-branches,too-many-statements +# pylint: disable=no-self-use,too-many-lines,too-many-locals,relative-import from __future__ import division import hashlib @@ -34,6 +34,7 @@ from inventory import Inventory # This thread, of which there is only one, does the heavy lifting: # calculating POWs. + def sizeof_fmt(num, suffix='h/s'): """Format hashes per seconds nicely (SI prefix)""" @@ -469,7 +470,7 @@ class singleWorker(StoppableThread): def sendOnionPeerObj(self, peer=None): """Send onionpeer object representing peer""" if not peer: # find own onionhostname - for peer in state.ownAddresses: + for peer in state.ownAddresses: # pylint: disable=redefined-argument-from-local if peer.host.endswith('.onion'): break else: @@ -478,7 +479,7 @@ class singleWorker(StoppableThread): embeddedTime = int(time.time() + TTL) streamNumber = 1 # Don't know yet what should be here objectType = protocol.OBJECT_ONIONPEER - # FIXME: ideally the objectPayload should be signed + # ..FIXME: ideally the objectPayload should be signed objectPayload = encodeVarint(peer.port) + protocol.encodeHost(peer.host) tag = calculateInventoryHash(objectPayload) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index ad1aee9c..95eee595 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,3 +1,8 @@ +""" +src/messagetypes/__init__.py +============================ +""" +# pylint: disable=import-error from importlib import import_module from os import path, listdir from string import lower @@ -9,12 +14,15 @@ from debug import logger import messagetypes import paths -class MsgBase(object): - def encode(self): + +class MsgBase(object): # pylint: disable=too-few-public-methods + """Base class for message types""" + def __init__(self): self.data = {"": lower(type(self).__name__)} def constructObject(data): + """Construct an object""" whitelist = ["message"] if data[""] not in whitelist: return None @@ -35,6 +43,7 @@ def constructObject(data): else: return returnObj + if paths.frozen is not None or platform == "android": import messagetypes.message import messagetypes.vote diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index f52c6b35..263a2e4a 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -1,13 +1,21 @@ +""" +src/messagetypes/message.py +================================= +""" from debug import logger from messagetypes import MsgBase +# pylint: disable=attribute-defined-outside-init class Message(MsgBase): - def __init__(self): + """Base method, helps to decode, encode and process the message""" + def __init__(self): # pylint: disable=super-init-not-called return def decode(self, data): + """Method used for decoding the message""" # UTF-8 and variable type validator + # pylint: disable=unidiomatic-typecheck if type(data["subject"]) is str: self.subject = unicode(data["subject"], 'utf-8', 'replace') else: @@ -18,6 +26,8 @@ class Message(MsgBase): self.body = unicode(str(data["body"]), 'utf-8', 'replace') def encode(self, data): + """Method used for encoding the message""" + # pylint: disable=no-member super(Message, self).encode() try: self.data["subject"] = data["subject"] @@ -27,5 +37,6 @@ class Message(MsgBase): return self.data def process(self): + """Method used for process the message""" logger.debug("Subject: %i bytes", len(self.subject)) logger.debug("Body: %i bytes", len(self.body)) diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index df8d267f..a77e1cc7 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -1,15 +1,25 @@ +""" +src/messagetypes/vote.py +================================= +""" from debug import logger from messagetypes import MsgBase +# pylint: disable=attribute-defined-outside-init + class Vote(MsgBase): - def __init__(self): + """Base method, helps to decode, encode and process the message""" + def __init__(self): # pylint: disable=super-init-not-called return def decode(self, data): + """Method used for decoding the message""" self.msgid = data["msgid"] self.vote = data["vote"] def encode(self, data): + """Method used for encoding the message""" + # pylint: disable=no-member super(Vote, self).encode() try: self.data["msgid"] = data["msgid"] @@ -19,5 +29,6 @@ class Vote(MsgBase): return self.data def process(self): + """Method used for process the message""" logger.debug("msgid: %s", self.msgid) logger.debug("vote: %s", self.vote) diff --git a/src/paths.py b/src/paths.py index c4c62950..78ae2804 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,3 +1,8 @@ +""" +src/paths.py +============ +""" +# pylint: disable=import-error from os import environ, path import sys import re @@ -7,9 +12,14 @@ from kivy.utils import platform # When using py2exe or py2app, the variable frozen is added to the sys # namespace. This can be used to setup a different code path for # binary distributions vs source distributions. -frozen = getattr(sys,'frozen', None) +frozen = getattr(sys, 'frozen', None) + def lookupExeFolder(): + """ + Folder with PyBitmessage binary (.exe, .app, ...). If it is run from source, it returns the source root + directory + """ if frozen: if frozen == "macosx_app": # targetdir/Bitmessage.app/Contents/MacOS/Bitmessage @@ -22,10 +32,12 @@ def lookupExeFolder(): exeFolder = '' return exeFolder -def lookupAppdataFolder(): +def lookupAppdataFolder(): # pylint: disable=too-many-branches + """Folder with runtime data (like configuration, database, ...)""" + # flake8: noqa=F821 import traceback - print(traceback.print_tb) + print traceback.print_tb APPNAME = "PyBitmessage" if "BITMESSAGE_HOME" in environ: dataFolder = environ["BITMESSAGE_HOME"] @@ -35,9 +47,11 @@ def lookupAppdataFolder(): if "HOME" in environ: dataFolder = path.join(environ["HOME"], "Library/Application Support/", APPNAME) + '/' else: - stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.' + stringToLog = ( + 'Could not find home folder, please report this message' + ' and your OS X version to the BitMessage Github.') if 'logger' in globals(): - logger.critical(stringToLog) + logger.critical(stringToLog) # pylint: disable=undefined-variable else: print stringToLog sys.exit() @@ -58,7 +72,7 @@ def lookupAppdataFolder(): move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder) stringToLog = "Moving data folder to %s" % (dataFolder) if 'logger' in globals(): - logger.info(stringToLog) + logger.info(stringToLog) # pylint: disable=undefined-variable else: print stringToLog except IOError: @@ -67,16 +81,21 @@ def lookupAppdataFolder(): dataFolder = dataFolder + '/' return dataFolder + def codePath(): + """Return the code path of the running instance""" + # pylint: disable=redefined-outer-name if frozen == "macosx_app": codePath = environ.get("RESOURCEPATH") - elif frozen: # windows - codePath = sys._MEIPASS + elif frozen: # windows + codePath = sys._MEIPASS # pylint: disable=no-member,protected-access else: codePath = path.dirname(__file__) return codePath + def tail(f, lines=20): + """Read last lines of a file. Like tail(1)""" total_lines_wanted = lines BLOCK_SIZE = 1024 @@ -84,12 +103,13 @@ def tail(f, lines=20): block_end_byte = f.tell() lines_to_go = total_lines_wanted block_number = -1 - blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting - # from the end of the file + blocks = [] + # blocks of size BLOCK_SIZE, in reverse order starting + # from the end of the file while lines_to_go > 0 and block_end_byte > 0: - if (block_end_byte - BLOCK_SIZE > 0): + if block_end_byte - BLOCK_SIZE > 0: # read the last block we haven't yet read - f.seek(block_number*BLOCK_SIZE, 2) + f.seek(block_number * BLOCK_SIZE, 2) blocks.append(f.read(BLOCK_SIZE)) else: # file too small, start from begining @@ -105,6 +125,7 @@ def tail(f, lines=20): def lastCommit(): + """Git commitish of the currently checked out repository""" githeadfile = path.join(codePath(), '..', '.git', 'logs', 'HEAD') result = {} if path.isfile(githeadfile): @@ -117,4 +138,4 @@ def lastCommit(): ) except (IOError, AttributeError, TypeError): pass - return result \ No newline at end of file + return result diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 0fc445e6..2d5ea04a 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -2,6 +2,7 @@ src/pyelliptic/openssl.py ================================= """ +# pylint: disable=import-error import sys import ctypes from kivy.utils import platform @@ -646,7 +647,8 @@ class _OpenSSL: # pylint: disable=too-many-instance-attributes, old-style-cl def loadOpenSSL(): """Method find and load the OpenSSL library""" - # pylint: disable=global-statement, protected-access, too-many-branches + # pylint: disable=global-statement, protected-access, too-many-branches, no-member + global OpenSSL from os import path, environ from ctypes.util import find_library diff --git a/src/state.py b/src/state.py index 63fa82e4..07cb687a 100644 --- a/src/state.py +++ b/src/state.py @@ -1,20 +1,21 @@ +""" +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 @@ -23,18 +24,13 @@ 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 - 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 @@ -46,11 +42,19 @@ ownAddresses = {} # 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 diff --git a/src/tr.py b/src/tr.py index af42145e..5ce623cd 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,25 +1,43 @@ +""" +src/tr.py +================================= +""" +# pylint: disable=relative-import import os import state -# This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions. -class translateClass: +"""This is used so that the translateText function can be used """ +"""when we are in daemon mode and not using any QT functions.""" + + +class translateClass: # pylint: disable=old-style-class, too-few-public-methods + """ + This is used so that the translateText function can be used when we are + in daemon mode and not using any QT functions. + """ def __init__(self, context, text): self.context = context self.text = text - def arg(self,argument): - if '%' in self.text: - return translateClass(self.context, self.text.replace('%','',1)) # This doesn't actually do anything with the arguments because we don't have a UI in which to display this information anyway. - else: - return self.text -def _translate(context, text, disambiguation = None, encoding = None, n = None): + def arg(self, argument): # pylint: disable=unused-argument + """Replace argument placeholders""" + if '%' in self.text: + return translateClass(self.context, self.text.replace('%', '', 1)) + # This doesn't actually do anything with the arguments + # because we don't have a UI in which to display this information anyway. + return self.text + + +def _translate(context, text, disambiguation=None, encoding=None, n=None): # pylint: disable=unused-argument return translateText(context, text, n) # def _translate(context, text, disambiguation = None, encoding = None, n = None): # return translateClass(context, text.replace('%','',1)) -def translateText(context, text, n = None): + +def translateText(context, text, n=None): + """Translate text in context""" try: enableGUI = state.enableGUI except AttributeError: # inside the plugin @@ -28,15 +46,16 @@ def translateText(context, text, n = None): try: from PyQt4 import QtCore, QtGui except Exception as err: - print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API\ + .You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download\ + or by searching Google for \'PyQt Download\'.\ + If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' print 'Error message:', err - os._exit(0) + os._exit(0) # pylint: disable=protected-access if n is None: return QtGui.QApplication.translate(context, text) - else: - return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) + return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) else: if '%' in text: - return translateClass(context, text.replace('%','',1)) - else: - return text + return translateClass(context, text.replace('%', '', 1)) + return text From 5a6611219cc2343f9fc8c9e55a2e8c059659cdb1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 25 Sep 2019 17:15:45 +0530 Subject: [PATCH 121/306] mpybit fixes --- src/bitmessagekivy/mpybit.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index cb4c4fda..1b4db996 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -43,7 +43,6 @@ from kivymd.list import ( ILeftBody, ILeftBodyTouch, IRightBodyTouch, - ThreeLineAvatarIconListItem, TwoLineAvatarIconListItem, TwoLineListItem) from kivymd.navigationdrawer import ( @@ -1084,7 +1083,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods if platform == 'android': # android_path = os.path.expanduser("~/user/0/org.test.bitapp/files/app/") android_path = os.path.join(os.environ['ANDROID_PRIVATE'] + '/app/') - img.texture.save('{1}/images/default_identicon/{0}.png'.format(BMConfigParser().addresses()[0], android_path)) + img.texture.save('{1}/images/default_identicon/{0}.png'.format( + BMConfigParser().addresses()[0], android_path)) else: img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] @@ -1299,7 +1299,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" - def __init__(self, **kwargs): + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """Grash of pop screen settings.""" super(GrashofPopup, self).__init__(**kwargs) @@ -1557,7 +1557,7 @@ class MyaddDetailPopup(Popup): address_label = StringProperty() address = StringProperty() - def __init__(self, **kwargs): + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """My Address Details screen setting.""" super(MyaddDetailPopup, self).__init__(**kwargs) @@ -1589,7 +1589,7 @@ class AddbookDetailPopup(Popup): address_label = StringProperty() address = StringProperty() - def __init__(self, **kwargs): + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """Method used set screen of address detail page.""" super(AddbookDetailPopup, self).__init__(**kwargs) From 0a065670715605e8f676f8a6008b51d6f16f42a0 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 12 Jul 2019 18:19:06 +0300 Subject: [PATCH 122/306] Connect to bootstrap nodes by name --- src/knownnodes.py | 10 +++++++++- src/network/connectionchooser.py | 3 ++- src/network/connectionpool.py | 3 +-- src/network/socks5.py | 10 ++++------ src/network/tcp.py | 13 ++++++++----- src/protocol.py | 5 ++++- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/knownnodes.py b/src/knownnodes.py index f4e00b90..6d4629a2 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -11,7 +11,6 @@ import time import state from bmconfigparser import BMConfigParser from debug import logger -from helper_bootstrap import dns knownNodesLock = threading.Lock() knownNodes = {stream: {} for stream in range(1, 4)} @@ -123,6 +122,8 @@ def readKnownNodes(): logger.debug( 'Failed to read nodes from knownnodes.dat', exc_info=True) createDefaultKnownNodes() + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + createDefaultKnownNodes(onion=True) config = BMConfigParser() @@ -177,6 +178,13 @@ def trimKnownNodes(recAddrStream=1): del knownNodes[recAddrStream][oldest] +def dns(): + """Add DNS names to knownnodes""" + for port in [8080, 8444]: + addKnownNode( + 1, state.Peer('bootstrap%s.bitmessage.org' % port, port)) + + def cleanupKnownNodes(): """ Cleanup knownnodes: remove old nodes and nodes with low rating diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index e116ec53..4b1565a2 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -46,7 +46,8 @@ def chooseConnection(stream): # onion addresses have a higher priority when SOCKS if peer.host.endswith('.onion') and rating > 0: rating = 1 - else: + # TODO: need better check + elif not peer.host.startswith('bootstrap'): encodedAddr = protocol.encodeHost(peer.host) # don't connect to local IPs when using SOCKS if not protocol.checkIPAddress(encodedAddr, False): diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 461c2b77..05358c28 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -8,7 +8,6 @@ import socket import time import asyncore_pollchoose as asyncore -import helper_bootstrap import helper_random import knownnodes import protocol @@ -185,7 +184,7 @@ class BMConnectionPool(object): # pylint: disable=too-many-nested-blocks if spawnConnections: if not knownnodes.knownNodesActual: - helper_bootstrap.dns() + knownnodes.dns() if not self.bootstrapped: self.bootstrapped = True Proxy.proxy = ( diff --git a/src/network/socks5.py b/src/network/socks5.py index 86616f30..e0cb7202 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -8,6 +8,7 @@ src/network/socks5.py import socket import struct +import state from proxy import GeneralProxyError, Proxy, ProxyError @@ -160,9 +161,6 @@ class Socks5(Proxy): class Socks5Connection(Socks5): """Child socks5 class used for making outbound connections.""" - def __init__(self, address): - Socks5.__init__(self, address=address) - def state_auth_done(self): """Request connection to be made""" # Now we can request the actual connection @@ -172,9 +170,9 @@ class Socks5Connection(Socks5): try: self.ipaddr = socket.inet_aton(self.destination[0]) self.append_write_buf(chr(0x01).encode() + self.ipaddr) - except socket.error: + except socket.error: # may be IPv6! # Well it's not an IP number, so it's probably a DNS name. - if Proxy._remote_dns: # pylint: disable=protected-access + if self._remote_dns: # Resolve remotely self.ipaddr = None self.append_write_buf(chr(0x03).encode() + chr( @@ -202,7 +200,7 @@ class Socks5Resolver(Socks5): def __init__(self, host): self.host = host self.port = 8444 - Socks5.__init__(self, address=(self.host, self.port)) + Socks5.__init__(self, address=state.Peer(self.host, self.port)) def state_auth_done(self): """Perform resolving""" diff --git a/src/network/tcp.py b/src/network/tcp.py index 5ebd6a21..9b92cb52 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -73,11 +73,14 @@ class TCPConnection(BMProto, TLSDispatcher): logger.debug( 'Connecting to %s:%i', self.destination.host, self.destination.port) - encodedAddr = protocol.encodeHost(self.destination.host) - self.local = all([ - protocol.checkIPAddress(encodedAddr, True), - not protocol.checkSocksIP(self.destination.host) - ]) + try: + self.local = ( + protocol.checkIPAddress( + protocol.encodeHost(self.destination.host), True) and + not protocol.checkSocksIP(self.destination.host) + ) + except socket.error: + pass # it's probably a hostname ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called self.bm_proto_reset() self.set_state("bm_header", expectBytes=protocol.Header.size) diff --git a/src/protocol.py b/src/protocol.py index ab81e5e5..1031b950 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -264,7 +264,10 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server= else: # use first 16 bytes if host data is longer # for example in case of onion v3 service - payload += encodeHost(remoteHost)[:16] + try: + payload += encodeHost(remoteHost)[:16] + except socket.error: + payload += encodeHost('127.0.0.1') payload += pack('>H', remotePort) # remote IPv6 and port # bitflags of the services I offer. From 4825c5a136450656932f8157677d221c55953d2e Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 20 Jul 2019 11:41:49 +0300 Subject: [PATCH 123/306] Universal bootstrap procedure for any connection type --- src/network/connectionpool.py | 29 ++++++++++++++++++++++++++--- src/network/tcp.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 05358c28..1554a585 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -18,7 +18,8 @@ from debug import logger from proxy import Proxy from singleton import Singleton from tcp import ( - TCPServer, Socks5BMConnection, Socks4aBMConnection, TCPConnection) + bootstrap, Socks4aBMConnection, Socks5BMConnection, + TCPConnection, TCPServer) from udp import UDPSocket @@ -159,7 +160,28 @@ class BMConnectionPool(object): udpSocket = UDPSocket(host=bind, announcing=True) self.udpSockets[udpSocket.listening.host] = udpSocket - def loop(self): # pylint: disable=too-many-branches, too-many-statements + def startBootstrappers(self): + """Run the process of resolving bootstrap hostnames""" + proxy_type = BMConfigParser().safeGet( + 'bitmessagesettings', 'socksproxytype') + # A plugins may be added here + if not proxy_type or proxy_type == 'none': + connection_base = TCPConnection + elif proxy_type == 'SOCKS5': + connection_base = Socks5BMConnection + elif proxy_type == 'SOCKS4a': + connection_base = Socks4aBMConnection # FIXME: I cannot test + else: + # This should never happen because socksproxytype setting + # is handled in bitmessagemain before starting the connectionpool + return + + bootstrapper = bootstrap(connection_base) + port = helper_random.randomchoice([8080, 8444]) + hostname = 'bootstrap%s.bitmessage.org' % port + self.addConnection(bootstrapper(hostname, port)) + + def loop(self): # pylint: disable=too-many-branches,too-many-statements """Main Connectionpool's loop""" # defaults to empty loop if outbound connections are maxed spawnConnections = False @@ -184,7 +206,8 @@ class BMConnectionPool(object): # pylint: disable=too-many-nested-blocks if spawnConnections: if not knownnodes.knownNodesActual: - knownnodes.dns() + self.startBootstrappers() + knownnodes.knownNodesActual = True if not self.bootstrapped: self.bootstrapped = True Proxy.proxy = ( diff --git a/src/network/tcp.py b/src/network/tcp.py index 9b92cb52..da02df2f 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -325,6 +325,39 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection): return True +def bootstrap(connection_class): + """Make bootstrapper class for connection type (connection_class)""" + class Bootstrapper(connection_class): + """Base class for bootstrappers""" + _connection_base = connection_class + + def __init__(self, host, port): + self._connection_base.__init__(self, state.Peer(host, port)) + self.close_reason = self._succeed = False + + def bm_command_addr(self): + """ + Got addr message - the bootstrap succeed. + Let BMProto process the addr message and switch state to 'close' + """ + BMProto.bm_command_addr(self) + self._succeed = True + # pylint: disable=attribute-defined-outside-init + self.close_reason = "Thanks for bootstrapping!" + self.set_state("close") + + def handle_close(self): + """ + After closing the connection switch knownnodes.knownNodesActual + back to False if the bootstrapper failed. + """ + self._connection_base.handle_close(self) + if not self._succeed: + knownnodes.knownNodesActual = False + + return Bootstrapper + + class TCPServer(AdvancedDispatcher): """TCP connection server for Bitmessage protocol""" From 7215003c6f2ad50ec785392cbf598f5be778d5fa Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 21 Jul 2019 16:50:49 +0300 Subject: [PATCH 124/306] No DNS resolving in knownnodes --- src/knownnodes.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/knownnodes.py b/src/knownnodes.py index 6d4629a2..2735edbf 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -191,33 +191,24 @@ def cleanupKnownNodes(): """ now = int(time.time()) needToWriteKnownNodesToDisk = False - dns_done = False - spawnConnections = not BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'dontconnect' - ) and BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'sendoutgoingconnections') with knownNodesLock: for stream in knownNodes: if stream not in state.streamsInWhichIAmParticipating: continue keys = knownNodes[stream].keys() - if len(keys) <= 1: # leave at least one node - if not dns_done and spawnConnections: - dns() - dns_done = True - continue for node in keys: + if len(knownNodes[stream]) <= 1: # leave at least one node + break try: - # scrap old nodes - if (now - knownNodes[stream][node]["lastseen"] > - 2419200): # 28 days + age = now - knownNodes[stream][node]["lastseen"] + # scrap old nodes (age > 28 days) + if age > 2419200: needToWriteKnownNodesToDisk = True del knownNodes[stream][node] continue - # scrap old nodes with low rating - if (now - knownNodes[stream][node]["lastseen"] > 10800 and - knownNodes[stream][node]["rating"] <= + # scrap old nodes (age > 3 hours) with low rating + if (age > 10800 and knownNodes[stream][node]["rating"] <= knownNodesForgetRating): needToWriteKnownNodesToDisk = True del knownNodes[stream][node] From bdb09c2d00d2bdbb7ad6ec6076a92f99c246abda Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 29 Jul 2019 14:37:56 +0300 Subject: [PATCH 125/306] Ignore self node in connectionchooser.chooseConnection() --- src/network/connectionchooser.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 4b1565a2..53ce30b7 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -1,3 +1,4 @@ +# pylint: disable=too-many-branches import random # nosec import knownnodes @@ -38,7 +39,10 @@ def chooseConnection(stream): for _ in range(50): peer = random.choice(knownnodes.knownNodes[stream].keys()) try: - rating = knownnodes.knownNodes[stream][peer]['rating'] + peer_info = knownnodes.knownNodes[stream][peer] + if peer_info.get('self'): + continue + rating = peer_info["rating"] except TypeError: logger.warning('Error in %s', peer) rating = 0 From bcb29facaac12b47df7adfadeddacde08c9ebfaf Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 29 Jul 2019 14:19:18 +0300 Subject: [PATCH 126/306] A test for bootstrapping, have problem with test_tcpconnection ): --- src/tests/core.py | 48 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/tests/core.py b/src/tests/core.py index a323be83..a9df05fc 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -13,9 +13,11 @@ import unittest import knownnodes import state +from bmconfigparser import BMConfigParser from helper_msgcoding import MsgEncode, MsgDecode from network import asyncore_pollchoose as asyncore -from network.tcp import TCPConnection +from network.connectionpool import BMConnectionPool +from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection from queues import excQueue knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat') @@ -80,8 +82,10 @@ class TestCore(unittest.TestCase): ' with no subject!' % e ) + @unittest.skip('Bad environment for asyncore.loop') def test_tcpconnection(self): """initial fill script from network.tcp""" + BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') try: for peer in (state.Peer("127.0.0.1", 8448),): direct = TCPConnection(peer) @@ -91,10 +95,18 @@ class TestCore(unittest.TestCase): except: self.fail('Exception in test loop') - def _wipe_knownnodes(self): + @staticmethod + def _wipe_knownnodes(): with knownnodes.knownNodesLock: knownnodes.knownNodes = {stream: {} for stream in range(1, 4)} + @staticmethod + def _outdate_knownnodes(): + with knownnodes.knownNodesLock: + for nodes in knownnodes.knownNodes.itervalues(): + for node in nodes.itervalues(): + node['lastseen'] -= 2419205 # older than 28 days + def test_knownnodes_pickle(self): """ensure that 3 nodes was imported for each stream""" pickle_knownnodes() @@ -117,9 +129,7 @@ class TestCore(unittest.TestCase): def test_0_cleaner(self): """test knownnodes starvation leading to IndexError in Asyncore""" - for nodes in knownnodes.knownNodes.itervalues(): - for node in nodes.itervalues(): - node['lastseen'] -= 2419205 # older than 28 days + self._outdate_knownnodes() # time.sleep(303) # singleCleaner wakes up every 5 min knownnodes.cleanupKnownNodes() while True: @@ -130,6 +140,34 @@ class TestCore(unittest.TestCase): if thread == 'Asyncore' and isinstance(exc, IndexError): self.fail("IndexError because of empty knownNodes!") + def test_bootstrap(self): + """test bootstrapping""" + BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') + self._outdate_knownnodes() + knownnodes.cleanupKnownNodes() + # it's weird, knownnodes appear empty + knownnodes.addKnownNode(1, state.Peer('127.0.0.1', 8444), is_self=True) + time.sleep(0.25) + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + proxy_type = BMConfigParser().safeGet( + 'bitmessagesettings', 'socksproxytype') + if proxy_type == 'SOCKS5': + connection_base = Socks5BMConnection + elif proxy_type == 'SOCKS4a': + connection_base = Socks4aBMConnection + else: + connection_base = TCPConnection + _started = time.time() + for _ in range(180): + time.sleep(1) + for peer, con in BMConnectionPool().outboundConnections.iteritems(): + if not peer.host.startswith('bootstrap'): + self.assertIsInstance(con, connection_base) + return + else: # pylint: disable=useless-else-on-loop + self.fail( + 'Failed to connect during %s sec' % (time.time() - _started)) + def run(): """Starts all tests defined in this module""" From 6a0c3ae075d787d40e3fb4507393eb46fafe64c8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 1 Aug 2019 15:28:32 +0300 Subject: [PATCH 127/306] Remove obsolete helper_bootstrap and bundled SocksiPy --- setup.py | 1 - src/helper_bootstrap.py | 84 ------- src/socks/BUGS | 25 --- src/socks/LICENSE | 22 -- src/socks/README | 201 ----------------- src/socks/__init__.py | 476 ---------------------------------------- 6 files changed, 809 deletions(-) delete mode 100644 src/helper_bootstrap.py delete mode 100644 src/socks/BUGS delete mode 100644 src/socks/LICENSE delete mode 100644 src/socks/README delete mode 100644 src/socks/__init__.py diff --git a/setup.py b/setup.py index 3a9c7a3c..61afa91e 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,6 @@ if __name__ == "__main__": 'pybitmessage.network', 'pybitmessage.plugins', 'pybitmessage.pyelliptic', - 'pybitmessage.socks', 'pybitmessage.storage' ] diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py deleted file mode 100644 index 1710b09c..00000000 --- a/src/helper_bootstrap.py +++ /dev/null @@ -1,84 +0,0 @@ -import socket - -import knownnodes -import socks -import state -from bmconfigparser import BMConfigParser -from debug import logger - - -def dns(): - """ - DNS bootstrap. This could be programmed to use the SOCKS proxy to do the - DNS lookup some day but for now we will just rely on the entries in - defaultKnownNodes.py. Hopefully either they are up to date or the user - has run Bitmessage recently without SOCKS turned on and received good - bootstrap nodes using that method. - """ - - def try_add_known_node(stream, addr, port, method=''): - try: - socket.inet_aton(addr) - except (TypeError, socket.error): - return - logger.info( - 'Adding %s to knownNodes based on %s DNS bootstrap method', - addr, method) - knownnodes.addKnownNode(stream, state.Peer(addr, port)) - - proxy_type = BMConfigParser().get('bitmessagesettings', 'socksproxytype') - - if proxy_type == 'none': - for port in [8080, 8444]: - try: - for item in socket.getaddrinfo( - 'bootstrap%s.bitmessage.org' % port, 80): - try_add_known_node(1, item[4][0], port) - except: - logger.error( - 'bootstrap%s.bitmessage.org DNS bootstrapping failed.', - port, exc_info=True - ) - elif proxy_type == 'SOCKS5': - knownnodes.createDefaultKnownNodes(onion=True) - logger.debug('Adding default onion knownNodes.') - for port in [8080, 8444]: - logger.debug("Resolving %i through SOCKS...", port) - address_family = socket.AF_INET - sock = socks.socksocket(address_family, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.settimeout(20) - proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = BMConfigParser().get( - 'bitmessagesettings', 'sockshostname') - socksport = BMConfigParser().getint( - 'bitmessagesettings', 'socksport') - # Do domain name lookups through the proxy; - # though this setting doesn't really matter since we won't - # be doing any domain name lookups anyway. - rdns = True - if BMConfigParser().getboolean( - 'bitmessagesettings', 'socksauthentication'): - socksusername = BMConfigParser().get( - 'bitmessagesettings', 'socksusername') - sockspassword = BMConfigParser().get( - 'bitmessagesettings', 'sockspassword') - sock.setproxy( - proxytype, sockshostname, socksport, rdns, - socksusername, sockspassword) - else: - sock.setproxy( - proxytype, sockshostname, socksport, rdns) - try: - ip = sock.resolve("bootstrap" + str(port) + ".bitmessage.org") - sock.shutdown(socket.SHUT_RDWR) - sock.close() - except: - logger.error("SOCKS DNS resolving failed", exc_info=True) - else: - try_add_known_node(1, ip, port, 'SOCKS') - else: - logger.info( - 'DNS bootstrap skipped because the proxy type does not support' - ' DNS resolution.' - ) diff --git a/src/socks/BUGS b/src/socks/BUGS deleted file mode 100644 index fa8ccfad..00000000 --- a/src/socks/BUGS +++ /dev/null @@ -1,25 +0,0 @@ -SocksiPy version 1.00 -A Python SOCKS module. -(C) 2006 Dan-Haim. All rights reserved. -See LICENSE file for details. - - -KNOWN BUGS AND ISSUES ----------------------- - -There are no currently known bugs in this module. -There are some limits though: - -1) Only outgoing connections are supported - This module currently only supports -outgoing TCP connections, though some servers may support incoming connections -as well. UDP is not supported either. - -2) GSSAPI Socks5 authenticaion is not supported. - - -If you find any new bugs, please contact the author at: - -negativeiq@users.sourceforge.net - - -Thank you! diff --git a/src/socks/LICENSE b/src/socks/LICENSE deleted file mode 100644 index 04b6b1f3..00000000 --- a/src/socks/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright 2006 Dan-Haim. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -3. Neither the name of Dan Haim nor the names of his contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. diff --git a/src/socks/README b/src/socks/README deleted file mode 100644 index a52f55f3..00000000 --- a/src/socks/README +++ /dev/null @@ -1,201 +0,0 @@ -SocksiPy version 1.00 -A Python SOCKS module. -(C) 2006 Dan-Haim. All rights reserved. -See LICENSE file for details. - - -WHAT IS A SOCKS PROXY? -A SOCKS proxy is a proxy server at the TCP level. In other words, it acts as -a tunnel, relaying all traffic going through it without modifying it. -SOCKS proxies can be used to relay traffic using any network protocol that -uses TCP. - -WHAT IS SOCKSIPY? -This Python module allows you to create TCP connections through a SOCKS -proxy without any special effort. - -PROXY COMPATIBILITY -SocksiPy is compatible with three different types of proxies: -1. SOCKS Version 4 (Socks4), including the Socks4a extension. -2. SOCKS Version 5 (Socks5). -3. HTTP Proxies which support tunneling using the CONNECT method. - -SYSTEM REQUIREMENTS -Being written in Python, SocksiPy can run on any platform that has a Python -interpreter and TCP/IP support. -This module has been tested with Python 2.3 and should work with greater versions -just as well. - - -INSTALLATION -------------- - -Simply copy the file "socks.py" to your Python's lib/site-packages directory, -and you're ready to go. - - -USAGE ------- - -First load the socks module with the command: - ->>> import socks ->>> - -The socks module provides a class called "socksocket", which is the base to -all of the module's functionality. -The socksocket object has the same initialization parameters as the normal socket -object to ensure maximal compatibility, however it should be noted that socksocket -will only function with family being AF_INET and type being SOCK_STREAM. -Generally, it is best to initialize the socksocket object with no parameters - ->>> s = socks.socksocket() ->>> - -The socksocket object has an interface which is very similiar to socket's (in fact -the socksocket class is derived from socket) with a few extra methods. -To select the proxy server you would like to use, use the setproxy method, whose -syntax is: - -setproxy(proxytype, addr[, port[, rdns[, username[, password]]]]) - -Explaination of the parameters: - -proxytype - The type of the proxy server. This can be one of three possible -choices: PROXY_TYPE_SOCKS4, PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP for Socks4, -Socks5 and HTTP servers respectively. - -addr - The IP address or DNS name of the proxy server. - -port - The port of the proxy server. Defaults to 1080 for socks and 8080 for http. - -rdns - This is a boolean flag than modifies the behavior regarding DNS resolving. -If it is set to True, DNS resolving will be preformed remotely, on the server. -If it is set to False, DNS resolving will be preformed locally. Please note that -setting this to True with Socks4 servers actually use an extension to the protocol, -called Socks4a, which may not be supported on all servers (Socks5 and http servers -always support DNS). The default is True. - -username - For Socks5 servers, this allows simple username / password authentication -with the server. For Socks4 servers, this parameter will be sent as the userid. -This parameter is ignored if an HTTP server is being used. If it is not provided, -authentication will not be used (servers may accept unauthentication requests). - -password - This parameter is valid only for Socks5 servers and specifies the -respective password for the username provided. - -Example of usage: - ->>> s.setproxy(socks.PROXY_TYPE_SOCKS5,"socks.example.com") ->>> - -After the setproxy method has been called, simply call the connect method with the -traditional parameters to establish a connection through the proxy: - ->>> s.connect(("www.sourceforge.net",80)) ->>> - -Connection will take a bit longer to allow negotiation with the proxy server. -Please note that calling connect without calling setproxy earlier will connect -without a proxy (just like a regular socket). - -Errors: Any errors in the connection process will trigger exceptions. The exception -may either be generated by the underlying socket layer or may be custom module -exceptions, whose details follow: - -class ProxyError - This is a base exception class. It is not raised directly but -rather all other exception classes raised by this module are derived from it. -This allows an easy way to catch all proxy-related errors. - -class GeneralProxyError - When thrown, it indicates a problem which does not fall -into another category. The parameter is a tuple containing an error code and a -description of the error, from the following list: -1 - invalid data - This error means that unexpected data has been received from -the server. The most common reason is that the server specified as the proxy is -not really a Socks4/Socks5/HTTP proxy, or maybe the proxy type specified is wrong. -4 - bad proxy type - This will be raised if the type of the proxy supplied to the -setproxy function was not PROXY_TYPE_SOCKS4/PROXY_TYPE_SOCKS5/PROXY_TYPE_HTTP. -5 - bad input - This will be raised if the connect method is called with bad input -parameters. - -class Socks5AuthError - This indicates that the connection through a Socks5 server -failed due to an authentication problem. The parameter is a tuple containing a -code and a description message according to the following list: - -1 - authentication is required - This will happen if you use a Socks5 server which -requires authentication without providing a username / password at all. -2 - all offered authentication methods were rejected - This will happen if the proxy -requires a special authentication method which is not supported by this module. -3 - unknown username or invalid password - Self descriptive. - -class Socks5Error - This will be raised for Socks5 errors which are not related to -authentication. The parameter is a tuple containing a code and a description of the -error, as given by the server. The possible errors, according to the RFC are: - -1 - General SOCKS server failure - If for any reason the proxy server is unable to -fulfill your request (internal server error). -2 - connection not allowed by ruleset - If the address you're trying to connect to -is blacklisted on the server or requires authentication. -3 - Network unreachable - The target could not be contacted. A router on the network -had replied with a destination net unreachable error. -4 - Host unreachable - The target could not be contacted. A router on the network -had replied with a destination host unreachable error. -5 - Connection refused - The target server has actively refused the connection -(the requested port is closed). -6 - TTL expired - The TTL value of the SYN packet from the proxy to the target server -has expired. This usually means that there are network problems causing the packet -to be caught in a router-to-router "ping-pong". -7 - Command not supported - The client has issued an invalid command. When using this -module, this error should not occur. -8 - Address type not supported - The client has provided an invalid address type. -When using this module, this error should not occur. - -class Socks4Error - This will be raised for Socks4 errors. The parameter is a tuple -containing a code and a description of the error, as given by the server. The -possible error, according to the specification are: - -1 - Request rejected or failed - Will be raised in the event of an failure for any -reason other then the two mentioned next. -2 - request rejected because SOCKS server cannot connect to identd on the client - -The Socks server had tried an ident lookup on your computer and has failed. In this -case you should run an identd server and/or configure your firewall to allow incoming -connections to local port 113 from the remote server. -3 - request rejected because the client program and identd report different user-ids - -The Socks server had performed an ident lookup on your computer and has received a -different userid than the one you have provided. Change your userid (through the -username parameter of the setproxy method) to match and try again. - -class HTTPError - This will be raised for HTTP errors. The parameter is a tuple -containing the HTTP status code and the description of the server. - - -After establishing the connection, the object behaves like a standard socket. -Call the close method to close the connection. - -In addition to the socksocket class, an additional function worth mentioning is the -setdefaultproxy function. The parameters are the same as the setproxy method. -This function will set default proxy settings for newly created socksocket objects, -in which the proxy settings haven't been changed via the setproxy method. -This is quite useful if you wish to force 3rd party modules to use a socks proxy, -by overriding the socket object. -For example: - ->>> socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5,"socks.example.com") ->>> socket.socket = socks.socksocket ->>> urllib.urlopen("http://www.sourceforge.net/") - - -PROBLEMS ---------- - -If you have any problems using this module, please first refer to the BUGS file -(containing current bugs and issues). If your problem is not mentioned you may -contact the author at the following E-Mail address: - -negativeiq@users.sourceforge.net - -Please allow some time for your question to be received and handled. - - -Dan-Haim, -Author. diff --git a/src/socks/__init__.py b/src/socks/__init__.py deleted file mode 100644 index 7fd2cba3..00000000 --- a/src/socks/__init__.py +++ /dev/null @@ -1,476 +0,0 @@ -"""SocksiPy - Python SOCKS module. -Version 1.00 - -Copyright 2006 Dan-Haim. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - 3. Neither the name of Dan Haim nor the names of his contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. - - -This module provides a standard socket-like interface for Python -for tunneling connections through SOCKS proxies. - -""" - -""" - -Minor modifications made by Christopher Gilbert (http://motomastyle.com/) -for use in PyLoris (http://pyloris.sourceforge.net/) - -Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/) -mainly to merge bug fixes found in Sourceforge - -""" - -import socket -import struct -import sys - -PROXY_TYPE_SOCKS4 = 1 -PROXY_TYPE_SOCKS5 = 2 -PROXY_TYPE_HTTP = 3 - -_defaultproxy = None -_orgsocket = socket.socket - -class ProxyError(Exception): pass -class GeneralProxyError(ProxyError): pass -class Socks5AuthError(ProxyError): pass -class Socks5Error(ProxyError): pass -class Socks4Error(ProxyError): pass -class HTTPError(ProxyError): pass - -_generalerrors = ("success", - "invalid data", - "not connected", - "not available", - "bad proxy type", - "bad input", - "timed out", - "network unreachable", - "connection refused", - "host unreachable") - -_socks5errors = ("succeeded", - "general SOCKS server failure", - "connection not allowed by ruleset", - "Network unreachable", - "Host unreachable", - "Connection refused", - "TTL expired", - "Command not supported", - "Address type not supported", - "Unknown error") - -_socks5autherrors = ("succeeded", - "authentication is required", - "all offered authentication methods were rejected", - "unknown username or invalid password", - "unknown error") - -_socks4errors = ("request granted", - "request rejected or failed", - "request rejected because SOCKS server cannot connect to identd on the client", - "request rejected because the client program and identd report different user-ids", - "unknown error") - -def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None): - """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]]) - Sets a default proxy which all further socksocket objects will use, - unless explicitly changed. - """ - global _defaultproxy - _defaultproxy = (proxytype, addr, port, rdns, username, password) - -def wrapmodule(module): - """wrapmodule(module) - Attempts to replace a module's socket library with a SOCKS socket. Must set - a default proxy using setdefaultproxy(...) first. - This will only work on modules that import socket directly into the namespace; - most of the Python Standard Library falls into this category. - """ - if _defaultproxy != None: - module.socket.socket = socksocket - else: - raise GeneralProxyError((4, "no proxy specified")) - -class socksocket(socket.socket): - """socksocket([family[, type[, proto]]]) -> socket object - Open a SOCKS enabled socket. The parameters are the same as - those of the standard socket init. In order for SOCKS to work, - you must specify family=AF_INET, type=SOCK_STREAM and proto=0. - """ - - def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None): - _orgsocket.__init__(self, family, type, proto, _sock) - if _defaultproxy != None: - self.__proxy = _defaultproxy - else: - self.__proxy = (None, None, None, None, None, None) - self.__proxysockname = None - self.__proxypeername = None - - def __recvall(self, count): - """__recvall(count) -> data - Receive EXACTLY the number of bytes requested from the socket. - Blocks until the required number of bytes have been received. - """ - try: - data = self.recv(count) - except socket.timeout: - raise GeneralProxyError((6, "timed out")) - while len(data) < count: - d = self.recv(count-len(data)) - if not d: raise GeneralProxyError((0, "connection closed unexpectedly")) - data = data + d - return data - - def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None): - """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]]) - Sets the proxy to be used. - - proxytype - The type of the proxy to be used. Three types - are supported: PROXY_TYPE_SOCKS4 (including socks4a), - PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP - - addr - The address of the server (IP or DNS). - - port - The port of the server. Defaults to 1080 for SOCKS - servers and 8080 for HTTP proxy servers. - - rdns - Should DNS queries be preformed on the remote side - (rather than the local side). The default is True. - Note: This has no effect with SOCKS4 servers. - - username - Username to authenticate with to the server. - The default is no authentication. - - password - Password to authenticate with to the server. - Only relevant when username is also provided. - - """ - self.__proxy = (proxytype, addr, port, rdns, username, password) - - def __negotiatesocks5(self): - """__negotiatesocks5(self,destaddr,destport) - Negotiates a connection through a SOCKS5 server. - """ - # First we'll send the authentication packages we support. - if (self.__proxy[4]!=None) and (self.__proxy[5]!=None): - # The username/password details were supplied to the - # setproxy method so we support the USERNAME/PASSWORD - # authentication (in addition to the standard none). - self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) - else: - # No username/password were entered, therefore we - # only support connections with no authentication. - self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00)) - # We'll receive the server's response to determine which - # method was selected - chosenauth = self.__recvall(2) - if chosenauth[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - # Check the chosen authentication method - if chosenauth[1:2] == chr(0x00).encode(): - # No authentication is required - pass - elif chosenauth[1:2] == chr(0x02).encode(): - # Okay, we need to perform a basic username/password - # authentication. - self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5]) - authstat = self.__recvall(2) - if authstat[0:1] != chr(0x01).encode(): - # Bad response - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - if authstat[1:2] != chr(0x00).encode(): - # Authentication failed - self.close() - raise Socks5AuthError((3, _socks5autherrors[3])) - # Authentication succeeded - else: - # Reaching here is always bad - self.close() - if chosenauth[1] == chr(0xFF).encode(): - raise Socks5AuthError((2, _socks5autherrors[2])) - else: - raise GeneralProxyError((1, _generalerrors[1])) - - def __connectsocks5(self, destaddr, destport): - # Now we can request the actual connection - req = struct.pack('BBB', 0x05, 0x01, 0x00) - # If the given destination address is an IP address, we'll - # use the IPv4 address request even if remote resolving was specified. - try: - ipaddr = socket.inet_aton(destaddr) - req = req + chr(0x01).encode() + ipaddr - except socket.error: - # Well it's not an IP number, so it's probably a DNS name. - if self.__proxy[3]: - # Resolve remotely - ipaddr = None - req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr - else: - # Resolve locally - ipaddr = socket.inet_aton(socket.gethostbyname(destaddr)) - req = req + chr(0x01).encode() + ipaddr - req = req + struct.pack(">H", destport) - self.sendall(req) - # Get the response - resp = self.__recvall(4) - if resp[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - elif resp[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(resp[1:2])<=8: - raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) - else: - raise Socks5Error((9, _socks5errors[9])) - # Get the bound address/port - elif resp[3:4] == chr(0x01).encode(): - boundaddr = self.__recvall(4) - elif resp[3:4] == chr(0x03).encode(): - resp = resp + self.recv(1) - boundaddr = self.__recvall(ord(resp[4:5])) - else: - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - boundport = struct.unpack(">H", self.__recvall(2))[0] - self.__proxysockname = (boundaddr, boundport) - if ipaddr != None: - self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) - else: - self.__proxypeername = (destaddr, destport) - - def __resolvesocks5(self, host): - # Now we can request the actual connection - req = struct.pack('BBB', 0x05, 0xF0, 0x00) - req += chr(0x03).encode() + chr(len(host)).encode() + host - req = req + struct.pack(">H", 8444) - self.sendall(req) - # Get the response - ip = "" - resp = self.__recvall(4) - if resp[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - elif resp[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(resp[1:2])<=8: - raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) - else: - raise Socks5Error((9, _socks5errors[9])) - # Get the bound address/port - elif resp[3:4] == chr(0x01).encode(): - ip = socket.inet_ntoa(self.__recvall(4)) - elif resp[3:4] == chr(0x03).encode(): - resp = resp + self.recv(1) - ip = self.__recvall(ord(resp[4:5])) - else: - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - boundport = struct.unpack(">H", self.__recvall(2))[0] - return ip - - def getproxysockname(self): - """getsockname() -> address info - Returns the bound IP address and port number at the proxy. - """ - return self.__proxysockname - - def getproxypeername(self): - """getproxypeername() -> address info - Returns the IP and port number of the proxy. - """ - return _orgsocket.getpeername(self) - - def getpeername(self): - """getpeername() -> address info - Returns the IP address and port number of the destination - machine (note: getproxypeername returns the proxy) - """ - return self.__proxypeername - - def getproxytype(self): - return self.__proxy[0] - - def __negotiatesocks4(self,destaddr,destport): - """__negotiatesocks4(self,destaddr,destport) - Negotiates a connection through a SOCKS4 server. - """ - # Check if the destination address provided is an IP address - rmtrslv = False - try: - ipaddr = socket.inet_aton(destaddr) - except socket.error: - # It's a DNS name. Check where it should be resolved. - if self.__proxy[3]: - ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01) - rmtrslv = True - else: - ipaddr = socket.inet_aton(socket.gethostbyname(destaddr)) - # Construct the request packet - req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr - # The username parameter is considered userid for SOCKS4 - if self.__proxy[4] != None: - req = req + self.__proxy[4] - req = req + chr(0x00).encode() - # DNS name if remote resolving is required - # NOTE: This is actually an extension to the SOCKS4 protocol - # called SOCKS4A and may not be supported in all cases. - if rmtrslv: - req = req + destaddr + chr(0x00).encode() - self.sendall(req) - # Get the response from the server - resp = self.__recvall(8) - if resp[0:1] != chr(0x00).encode(): - # Bad data - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - if resp[1:2] != chr(0x5A).encode(): - # Server returned an error - self.close() - if ord(resp[1:2]) in (91, 92, 93): - self.close() - raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90])) - else: - raise Socks4Error((94, _socks4errors[4])) - # Get the bound address/port - self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0]) - if rmtrslv != None: - self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) - else: - self.__proxypeername = (destaddr, destport) - - def __negotiatehttp(self, destaddr, destport): - """__negotiatehttp(self,destaddr,destport) - Negotiates a connection through an HTTP server. - """ - # If we need to resolve locally, we do this now - if not self.__proxy[3]: - addr = socket.gethostbyname(destaddr) - else: - addr = destaddr - self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode()) - # We read the response until we get the string "\r\n\r\n" - resp = self.recv(1) - while resp.find("\r\n\r\n".encode()) == -1: - resp = resp + self.recv(1) - # We just need the first line to check if the connection - # was successful - statusline = resp.splitlines()[0].split(" ".encode(), 2) - if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - try: - statuscode = int(statusline[1]) - except ValueError: - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - if statuscode != 200: - self.close() - raise HTTPError((statuscode, statusline[2])) - self.__proxysockname = ("0.0.0.0", 0) - self.__proxypeername = (addr, destport) - - def connect(self, destpair): - """connect(self, despair) - Connects to the specified destination through a proxy. - destpar - A tuple of the IP/DNS address and the port number. - (identical to socket's connect). - To select the proxy server use setproxy(). - """ - # Do a minimal input check first - if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int): - raise GeneralProxyError((5, _generalerrors[5])) - if self.__proxy[0] == PROXY_TYPE_SOCKS5: - if self.__proxy[2] != None: - portnum = self.__proxy[2] - else: - portnum = 1080 - try: - _orgsocket.connect(self, (self.__proxy[1], portnum)) - except socket.error as e: - # ENETUNREACH, WSAENETUNREACH - if e[0] in [101, 10051]: - raise GeneralProxyError((7, _generalerrors[7])) - # ECONNREFUSED, WSAECONNREFUSED - if e[0] in [111, 10061]: - raise GeneralProxyError((8, _generalerrors[8])) - # EHOSTUNREACH, WSAEHOSTUNREACH - if e[0] in [113, 10065]: - raise GeneralProxyError((9, _generalerrors[9])) - raise - self.__negotiatesocks5() - self.__connectsocks5(destpair[0], destpair[1]) - elif self.__proxy[0] == PROXY_TYPE_SOCKS4: - if self.__proxy[2] != None: - portnum = self.__proxy[2] - else: - portnum = 1080 - _orgsocket.connect(self,(self.__proxy[1], portnum)) - self.__negotiatesocks4(destpair[0], destpair[1]) - elif self.__proxy[0] == PROXY_TYPE_HTTP: - if self.__proxy[2] != None: - portnum = self.__proxy[2] - else: - portnum = 8080 - try: - _orgsocket.connect(self,(self.__proxy[1], portnum)) - except socket.error as e: - # ENETUNREACH, WSAENETUNREACH - if e[0] in [101, 10051]: - raise GeneralProxyError((7, _generalerrors[7])) - # ECONNREFUSED, WSAECONNREFUSED - if e[0] in [111, 10061]: - raise GeneralProxyError((8, _generalerrors[8])) - # EHOSTUNREACH, WSAEHOSTUNREACH - if e[0] in [113, 10065]: - raise GeneralProxyError((9, _generalerrors[9])) - raise - self.__negotiatehttp(destpair[0], destpair[1]) - elif self.__proxy[0] == None: - _orgsocket.connect(self, (destpair[0], destpair[1])) - else: - raise GeneralProxyError((4, _generalerrors[4])) - - def resolve(self, host): - if self.__proxy[0] == PROXY_TYPE_SOCKS5: - if self.__proxy[2] != None: - portnum = self.__proxy[2] - else: - portnum = 1080 - _orgsocket.connect(self, (self.__proxy[1], portnum)) - self.__negotiatesocks5() - return self.__resolvesocks5(host) - else: - return None From a7cfe5ba326b950d882619f88ae17b3cd2d18ba3 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 9 Aug 2019 17:15:00 +0300 Subject: [PATCH 128/306] Try to test with tor --- .travis.yml | 1 + requirements.txt | 1 + src/bitmessagemain.py | 5 +++-- src/plugins/proxyconfig_stem.py | 13 +++++++++++-- src/tests/core.py | 28 +++++++++++++++++++++------- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1edba418..d7141188 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ addons: packages: - build-essential - libcap-dev + - tor install: - pip install -r requirements.txt - ln -s src pybitmessage # tests environment diff --git a/requirements.txt b/requirements.txt index c55e5cf1..be429a9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ python_prctl psutil pycrypto +stem diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 5dcfea6c..1dd2f271 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -193,7 +193,8 @@ class Main: from plugins.plugin import get_plugin try: proxyconfig_start = time.time() - get_plugin('proxyconfig', name=proxy_type)(config) + if not get_plugin('proxyconfig', name=proxy_type)(config): + raise TypeError except TypeError: logger.error( 'Failed to run proxy config plugin %s', @@ -424,7 +425,7 @@ class Main: self.stop() elif not state.enableGUI: from tests import core as test_core # pylint: disable=relative-import - test_core_result = test_core.run() + test_core_result = test_core.run(self) state.enableGUI = True self.stop() test_core.cleanup() diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index 75605c07..e8b5417e 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -8,6 +8,7 @@ import tempfile import stem import stem.control import stem.process +import stem.version class DebugLogger(object): @@ -31,7 +32,7 @@ class DebugLogger(object): self._logger.log(self._levels.get(level, 10), '(tor)' + line) -def connect_plugin(config): +def connect_plugin(config): # pylint: disable=too-many-branches """Run stem proxy configurator""" logwrite = DebugLogger() if config.safeGet('bitmessagesettings', 'sockshostname') not in ( @@ -60,8 +61,14 @@ def connect_plugin(config): # So if there is a system wide tor, use it for outbound connections. try: stem.process.launch_tor_with_config( - tor_config, take_ownership=True, init_msg_handler=logwrite) + tor_config, take_ownership=True, timeout=20, + init_msg_handler=logwrite) except OSError: + if not attempt: + try: + stem.version.get_system_tor_version() + except IOError: + return continue else: logwrite('Started tor on port %s' % port) @@ -108,3 +115,5 @@ def connect_plugin(config): onionhostname, 'keytype', response.private_key_type) config.save() config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5') + + return True diff --git a/src/tests/core.py b/src/tests/core.py index a9df05fc..005900d0 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -21,6 +21,7 @@ from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection from queues import excQueue knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat') +program = None def pickle_knownnodes(): @@ -132,6 +133,7 @@ class TestCore(unittest.TestCase): self._outdate_knownnodes() # time.sleep(303) # singleCleaner wakes up every 5 min knownnodes.cleanupKnownNodes() + self.assertTrue(knownnodes.knownNodes[1]) while True: try: thread, exc = excQueue.get(block=False) @@ -140,14 +142,15 @@ class TestCore(unittest.TestCase): if thread == 'Asyncore' and isinstance(exc, IndexError): self.fail("IndexError because of empty knownNodes!") - def test_bootstrap(self): - """test bootstrapping""" + def _initiate_bootstrap(self): BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') self._outdate_knownnodes() - knownnodes.cleanupKnownNodes() - # it's weird, knownnodes appear empty knownnodes.addKnownNode(1, state.Peer('127.0.0.1', 8444), is_self=True) - time.sleep(0.25) + knownnodes.cleanupKnownNodes() + time.sleep(2) + + def _check_bootstrap(self): + _started = time.time() BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') proxy_type = BMConfigParser().safeGet( 'bitmessagesettings', 'socksproxytype') @@ -157,20 +160,31 @@ class TestCore(unittest.TestCase): connection_base = Socks4aBMConnection else: connection_base = TCPConnection - _started = time.time() for _ in range(180): time.sleep(1) for peer, con in BMConnectionPool().outboundConnections.iteritems(): if not peer.host.startswith('bootstrap'): self.assertIsInstance(con, connection_base) + self.assertNotEqual(peer.host, '127.0.0.1') return else: # pylint: disable=useless-else-on-loop self.fail( 'Failed to connect during %s sec' % (time.time() - _started)) + def test_bootstrap(self): + """test bootstrapping""" + self._initiate_bootstrap() + self._check_bootstrap() + self._initiate_bootstrap() + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem') + program.start_proxyconfig(BMConfigParser()) + self._check_bootstrap() -def run(): + +def run(prog): """Starts all tests defined in this module""" + global program # pylint: disable=global-statement + program = prog loader = unittest.TestLoader() loader.sortTestMethodsUsing = None suite = loader.loadTestsFromTestCase(TestCore) From 88f2c51595470bc83f1f10740b01a7eab4dc5e62 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 2 Sep 2019 14:19:45 +0300 Subject: [PATCH 129/306] quzwelsuziwqgpt2.onion:8444 is also a bootstrap server --- src/knownnodes.py | 13 +++---------- src/network/connectionpool.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/knownnodes.py b/src/knownnodes.py index 2735edbf..ba21bac7 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -34,10 +34,6 @@ DEFAULT_NODES = ( state.Peer('178.11.46.221', 8444) ) -DEFAULT_NODES_ONION = ( - state.Peer('quzwelsuziwqgpt2.onion', 8444), -) - def json_serialize_knownnodes(output): """ @@ -66,8 +62,7 @@ def json_deserialize_knownnodes(source): if ( not (knownNodesActual or info.get('self')) and - peer not in DEFAULT_NODES and - peer not in DEFAULT_NODES_ONION + peer not in DEFAULT_NODES ): knownNodesActual = True @@ -102,9 +97,9 @@ def addKnownNode(stream, peer, lastseen=None, is_self=False): } -def createDefaultKnownNodes(onion=False): +def createDefaultKnownNodes(): past = time.time() - 2418600 # 28 days - 10 min - for peer in DEFAULT_NODES_ONION if onion else DEFAULT_NODES: + for peer in DEFAULT_NODES: addKnownNode(1, peer, past) saveKnownNodes() @@ -122,8 +117,6 @@ def readKnownNodes(): logger.debug( 'Failed to read nodes from knownnodes.dat', exc_info=True) createDefaultKnownNodes() - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': - createDefaultKnownNodes(onion=True) config = BMConfigParser() diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1554a585..4d16df49 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -165,10 +165,14 @@ class BMConnectionPool(object): proxy_type = BMConfigParser().safeGet( 'bitmessagesettings', 'socksproxytype') # A plugins may be added here + hostname = None if not proxy_type or proxy_type == 'none': connection_base = TCPConnection elif proxy_type == 'SOCKS5': connection_base = Socks5BMConnection + hostname = helper_random.randomchoice([ + 'quzwelsuziwqgpt2.onion', None + ]) elif proxy_type == 'SOCKS4a': connection_base = Socks4aBMConnection # FIXME: I cannot test else: @@ -177,8 +181,11 @@ class BMConnectionPool(object): return bootstrapper = bootstrap(connection_base) - port = helper_random.randomchoice([8080, 8444]) - hostname = 'bootstrap%s.bitmessage.org' % port + if not hostname: + port = helper_random.randomchoice([8080, 8444]) + hostname = 'bootstrap%s.bitmessage.org' % port + else: + port = 8444 self.addConnection(bootstrapper(hostname, port)) def loop(self): # pylint: disable=too-many-branches,too-many-statements From 8ed1d48799e8176c0dbe6b2f234dd4948f0d54db Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 26 Sep 2019 16:54:59 +0530 Subject: [PATCH 130/306] core pylint fixes --- src/tests/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/core.py b/src/tests/core.py index 005900d0..b01c6b69 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -25,6 +25,7 @@ program = None def pickle_knownnodes(): + """Generate old style pickled knownnodes.dat""" now = time.time() with open(knownnodes_file, 'wb') as dst: pickle.dump({ @@ -40,6 +41,7 @@ def pickle_knownnodes(): def cleanup(): + """Cleanup application files""" os.remove(knownnodes_file) From 7839f83f20a2e887a9b68bd4da099ba966b02972 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 26 Sep 2019 16:56:55 +0530 Subject: [PATCH 131/306] test_api pylint fixes --- src/tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/test_api.py b/src/tests/test_api.py index dfe1b273..44505ffe 100644 --- a/src/tests/test_api.py +++ b/src/tests/test_api.py @@ -31,7 +31,7 @@ class TestAPIShutdown(TestAPIProto, TestProcessShutdown): """Separate test case for API command 'shutdown'""" def test_shutdown(self): """Shutdown the pybitmessage""" - self.assertEquals(self.api.shutdown(), 'done') + self.assertEqual(self.api.shutdown(), 'done') for _ in range(5): if not self.process.is_running(): break From 944c30f9b41fc3b557821edc5a0990bb4e22f008 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 26 Sep 2019 16:57:17 +0530 Subject: [PATCH 132/306] test_config pylint fixes --- src/tests/test_config.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/test_config.py b/src/tests/test_config.py index a0a727e5..35ddd3fa 100644 --- a/src/tests/test_config.py +++ b/src/tests/test_config.py @@ -26,6 +26,7 @@ class TestConfig(unittest.TestCase): False ) # no arg for default + # pylint: disable=too-many-function-args with self.assertRaises(TypeError): BMConfigParser().safeGetBoolean( 'nonexistent', 'nonexistent', True) @@ -47,9 +48,9 @@ class TestProcessConfig(TestProcessProto): config = BMConfigParser() config.read(os.path.join(self.home, 'keys.dat')) - self.assertEquals(config.safeGetInt( + self.assertEqual(config.safeGetInt( 'bitmessagesettings', 'settingsversion'), 10) - self.assertEquals(config.safeGetInt( + self.assertEqual(config.safeGetInt( 'bitmessagesettings', 'port'), 8444) # don't connect self.assertTrue(config.safeGetBoolean( @@ -59,7 +60,7 @@ class TestProcessConfig(TestProcessProto): 'bitmessagesettings', 'apienabled')) # extralowdifficulty is false - self.assertEquals(config.safeGetInt( + self.assertEqual(config.safeGetInt( 'bitmessagesettings', 'defaultnoncetrialsperbyte'), 1000) - self.assertEquals(config.safeGetInt( + self.assertEqual(config.safeGetInt( 'bitmessagesettings', 'defaultpayloadlengthextrabytes'), 1000) From fa65b17fc98a5689197beae21f3aa8be4be7f31f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 14:51:54 +0530 Subject: [PATCH 133/306] __init__ pylint fixes --- src/pyelliptic/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pyelliptic/__init__.py b/src/pyelliptic/__init__.py index 1d6a928f..7aa666e0 100644 --- a/src/pyelliptic/__init__.py +++ b/src/pyelliptic/__init__.py @@ -1,3 +1,7 @@ +""" +src/pyelliptic/__init__.py +===================================== +""" # Copyright (C) 2010 # Author: Yann GUIBET # Contact: From e0d81bb7e8e23c4d8612b0f8a382df3eddfd87f8 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 17:51:58 +0530 Subject: [PATCH 134/306] cipher pylint fixes --- src/pyelliptic/cipher.py | 16 +++++++++++++--- src/pyelliptic/hash.py | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index bc1af6b0..d02b743a 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -1,5 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +src/pyelliptic/cipher.py +======================== +""" # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. @@ -7,7 +11,8 @@ from openssl import OpenSSL -class Cipher: +# pylint: disable=redefined-builtin +class Cipher(object): """ Symmetric encryption @@ -44,30 +49,34 @@ class Cipher: @staticmethod def get_blocksize(ciphername): + """This Method returns cipher blocksize""" cipher = OpenSSL.get_cipher(ciphername) return cipher.get_blocksize() @staticmethod def gen_IV(ciphername): + """Generate random initialization vector""" cipher = OpenSSL.get_cipher(ciphername) return OpenSSL.rand(cipher.get_blocksize()) def update(self, input): + """Update result with more data""" i = OpenSSL.c_int(0) buffer = OpenSSL.malloc(b"", len(input) + self.cipher.get_blocksize()) inp = OpenSSL.malloc(input, len(input)) if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer), OpenSSL.byref(i), inp, len(input)) == 0: raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...") - return buffer.raw[0:i.value] + return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index def final(self): + """Returning the final value""" i = OpenSSL.c_int(0) buffer = OpenSSL.malloc(b"", self.cipher.get_blocksize()) if (OpenSSL.EVP_CipherFinal_ex(self.ctx, OpenSSL.byref(buffer), OpenSSL.byref(i))) == 0: raise Exception("[OpenSSL] EVP_CipherFinal_ex FAIL ...") - return buffer.raw[0:i.value] + return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index def ciphering(self, input): """ @@ -77,6 +86,7 @@ class Cipher: return buff + self.final() def __del__(self): + # pylint: disable=protected-access if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_CIPHER_CTX_reset(self.ctx) else: diff --git a/src/pyelliptic/hash.py b/src/pyelliptic/hash.py index f2240500..2d7064f8 100644 --- a/src/pyelliptic/hash.py +++ b/src/pyelliptic/hash.py @@ -27,6 +27,7 @@ def _equals_str(a, b): def equals(a, b): + """Compare two strings or bytearrays""" if isinstance(a, str): return _equals_str(a, b) else: @@ -58,6 +59,7 @@ def hmac_sha512(k, m): def pbkdf2(password, salt=None, i=10000, keylen=64): + """Compute the salt, key and the message with pbkdf2""" if salt is None: salt = OpenSSL.rand(8) p_password = OpenSSL.malloc(password, len(password)) From 4448e6ee7ba040c2582618a291e9cb28af57e511 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 17:52:56 +0530 Subject: [PATCH 135/306] hash pylint fixes --- src/pyelliptic/hash.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pyelliptic/hash.py b/src/pyelliptic/hash.py index 2d7064f8..c21dd6a4 100644 --- a/src/pyelliptic/hash.py +++ b/src/pyelliptic/hash.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- - +""" +src/pyelliptic/hash.py +===================== +""" # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. @@ -30,8 +33,7 @@ def equals(a, b): """Compare two strings or bytearrays""" if isinstance(a, str): return _equals_str(a, b) - else: - return _equals_bytes(a, b) + return _equals_bytes(a, b) def hmac_sha256(k, m): @@ -59,7 +61,7 @@ def hmac_sha512(k, m): def pbkdf2(password, salt=None, i=10000, keylen=64): - """Compute the salt, key and the message with pbkdf2""" + """Key derivation function using SHA256""" if salt is None: salt = OpenSSL.rand(8) p_password = OpenSSL.malloc(password, len(password)) From a6f951d37fe05a3b6518585cfdd6b11be6bc5f68 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 24 Sep 2019 13:05:42 +0530 Subject: [PATCH 136/306] openssl pylint fixes --- src/pyelliptic/openssl.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index ab2990e6..fcde01ec 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -1,10 +1,14 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- - +""" +src/pyelliptic/openssl.py +===================== +""" # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. # # Software slightly changed by Jonathan Warren +# pylint: disable=protected-access import sys import ctypes @@ -13,6 +17,9 @@ OpenSSL = None class CipherName: + """Class returns cipher name, pointer and blocksize""" + + # pylint: disable=old-style-class def __init__(self, name, pointer, blocksize): self._name = name self._pointer = pointer @@ -24,16 +31,20 @@ class CipherName: " | Function pointer : " + str(self._pointer) def get_pointer(self): + """This method returns cipher pointer""" return self._pointer() def get_name(self): + """This method returns cipher name""" return self._name def get_blocksize(self): + """This method returns cipher blocksize""" return self._blocksize def get_version(library): + """This function return version, hexversion and cflages""" version = None hexversion = None cflags = None @@ -68,6 +79,7 @@ class _OpenSSL: """ Wrapper for OpenSSL using ctypes """ + # pylint: disable=too-many-statements, too-many-instance-attributes, old-style-class def __init__(self, library): """ Build the wrapper @@ -594,6 +606,7 @@ class _OpenSSL: """ returns the name of a elliptic curve with his id """ + # pylint: disable=redefined-builtin res = None for i in self.curves: if self.curves[i] == id: @@ -607,6 +620,7 @@ class _OpenSSL: """ OpenSSL random function """ + # pylint: disable=redefined-builtin buffer = self.malloc(0, size) # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is # evidently possible that it returned an error and not-actually-random data. However, in @@ -623,6 +637,7 @@ class _OpenSSL: """ returns a create_string_buffer (ctypes) """ + # pylint: disable=redefined-builtin buffer = None if data != 0: if sys.version_info.major == 3 and isinstance(data, type('')): @@ -634,6 +649,8 @@ class _OpenSSL: def loadOpenSSL(): + """This function finds and load the OpenSSL library""" + # pylint: disable=global-statement global OpenSSL from os import path, environ from ctypes.util import find_library From 36775ae88b87cb6a126f9f0091b1a8dd41e8e0be Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:07:04 +0530 Subject: [PATCH 137/306] indicator_libmessaging pylint fixes --- src/plugins/indicator_libmessaging.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/indicator_libmessaging.py b/src/plugins/indicator_libmessaging.py index 36178663..ab2e833e 100644 --- a/src/plugins/indicator_libmessaging.py +++ b/src/plugins/indicator_libmessaging.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +src/plugins/indicator_libmessaging.py +===================================== +""" import gi gi.require_version('MessagingMenu', '1.0') # noqa:E402 @@ -9,6 +13,7 @@ from pybitmessage.tr import _translate class IndicatorLibmessaging(object): + """Plugin for libmessage indicator""" def __init__(self, form): try: self.app = MessagingMenu.App(desktop_id='pybitmessage.desktop') @@ -32,15 +37,18 @@ class IndicatorLibmessaging(object): if self.app: self.app.unregister() - def activate(self, app, source): + def activate(self, app, source): # pylint: disable=unused-argument + """Activate the libmessaging indicator plugin""" self.form.appIndicatorInbox( self.new_message_item if source == 'messages' else self.new_broadcast_item ) - # show the number of unread messages and subscriptions - # on the messaging menu def show_unread(self, draw_attention=False): + """ + show the number of unread messages and subscriptions + on the messaging menu + """ for source, count in zip( ('messages', 'subscriptions'), self.form.getUnread() From 4c1568a3eb4c6748c2e26c56d50a60e1c17271b7 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:07:23 +0530 Subject: [PATCH 138/306] menu_qrcode pylint fixes --- src/plugins/menu_qrcode.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py index 7f21c6b8..2e65bd88 100644 --- a/src/plugins/menu_qrcode.py +++ b/src/plugins/menu_qrcode.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- """ +src/plugins/menu_qrcode.py +========================== + A menu plugin showing QR-Code for bitmessage address in modal dialog. """ @@ -12,9 +15,10 @@ from pybitmessage.tr import _translate # http://stackoverflow.com/questions/20452486 -class Image(qrcode.image.base.BaseImage): +class Image(qrcode.image.base.BaseImage): # pylint: disable=abstract-method """Image output class for qrcode using QPainter""" - def __init__(self, border, width, box_size): + + def __init__(self, border, width, box_size): # pylint: disable=super-init-not-called self.border = border self.width = width self.box_size = box_size From 7aa9b94c111106ea739ea3890b351a5c953d6a43 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:08:00 +0530 Subject: [PATCH 139/306] notification_notify2 pylint fixes --- src/plugins/notification_notify2.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py index 3fd935c4..b4cd045d 100644 --- a/src/plugins/notification_notify2.py +++ b/src/plugins/notification_notify2.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +src/plugins/notification_notify2.py +=================================== +""" import gi gi.require_version('Notify', '0.7') @@ -6,10 +10,13 @@ from gi.repository import Notify Notify.init('pybitmessage') + def connect_plugin(title, subtitle, category, label, icon): + """Plugin for notify2""" if not icon: icon = 'mail-message-new' if category == 2 else 'pybitmessage' connect_plugin.notification.update(title, subtitle, icon) connect_plugin.notification.show() + connect_plugin.notification = Notify.Notification.new("Init", "Init") From e50f99419fba105a56b100c89958b281ff21cc14 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:08:18 +0530 Subject: [PATCH 140/306] plugin pylint fixes --- src/plugins/plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index 6601adaf..e671a73f 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- - +""" +src/plugins/plugin.py +=================================== +""" import pkg_resources From df1994d6f3f02b833bbd690102ad8dfbbe3aa9c0 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:08:34 +0530 Subject: [PATCH 141/306] proxyconfig_stem pylint fixes --- src/plugins/proxyconfig_stem.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index e8b5417e..5bb9a726 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- - +""" +src/plugins/proxyconfig_stem.py +=================================== +""" import os import logging import random # noseq @@ -29,14 +32,14 @@ class DebugLogger(object): # Plugin's debug or unexpected log line from tor self._logger.debug(line) else: - self._logger.log(self._levels.get(level, 10), '(tor)' + line) + self._logger.log(self._levels.get(level, 10), '(tor) %s', line) def connect_plugin(config): # pylint: disable=too-many-branches """Run stem proxy configurator""" logwrite = DebugLogger() if config.safeGet('bitmessagesettings', 'sockshostname') not in ( - 'localhost', '127.0.0.1', '' + 'localhost', '127.0.0.1', '' ): # remote proxy is choosen for outbound connections, # nothing to do here, but need to set socksproxytype to SOCKS5! From a86c5188c44411d173bd2a15b24b7801b8bddf8b Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:08:56 +0530 Subject: [PATCH 142/306] sound_canberra pylint fixes --- src/plugins/sound_canberra.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/sound_canberra.py b/src/plugins/sound_canberra.py index 094901ed..dbb4baed 100644 --- a/src/plugins/sound_canberra.py +++ b/src/plugins/sound_canberra.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +src/plugins/proxyconfig_stem.py +=================================== +""" from pybitmessage.bitmessageqt import sound @@ -14,7 +18,8 @@ _theme = { } -def connect_plugin(category, label=None): +def connect_plugin(category, label=None): # pylint: disable=unused-argument + """This function implements the entry point.""" try: _canberra.play(0, pycanberra.CA_PROP_EVENT_ID, _theme[category], None) except (KeyError, pycanberra.CanberraException): From a86e43c108c4117472868f2bcecdb0f4d20df31e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:09:19 +0530 Subject: [PATCH 143/306] sound_gstreamer pylint fixes --- src/plugins/sound_gstreamer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/sound_gstreamer.py b/src/plugins/sound_gstreamer.py index 062da3f9..32a0aa65 100644 --- a/src/plugins/sound_gstreamer.py +++ b/src/plugins/sound_gstreamer.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- - +""" +src/plugins/sound_gstreamer.py +=================================== +""" import gi gi.require_version('Gst', '1.0') from gi.repository import Gst # noqa: E402 @@ -9,6 +12,7 @@ _player = Gst.ElementFactory.make("playbin", "player") def connect_plugin(sound_file): + """Entry point for sound file""" _player.set_state(Gst.State.NULL) _player.set_property("uri", "file://" + sound_file) _player.set_state(Gst.State.PLAYING) From 433cb9818b045843128a9be52f1bff2be6c06239 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Sep 2019 16:09:35 +0530 Subject: [PATCH 144/306] sound_playfile pylint fixes --- src/plugins/sound_playfile.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py index c8216d07..6396c319 100644 --- a/src/plugins/sound_playfile.py +++ b/src/plugins/sound_playfile.py @@ -1,10 +1,14 @@ # -*- coding: utf-8 -*- - +""" +src/plugins/sound_playfile.py +=================================== +""" try: import winsound def connect_plugin(sound_file): + """Plugin's entry point""" winsound.PlaySound(sound_file, winsound.SND_FILENAME) except ImportError: import os @@ -18,7 +22,8 @@ except ImportError: args, stdout=FNULL, stderr=subprocess.STDOUT, close_fds=True) def connect_plugin(sound_file): - global play_cmd + """This function implements the entry point.""" + global play_cmd # pylint: disable=global-statement ext = os.path.splitext(sound_file)[-1] try: From 6f910f67c0ebb45f6b7455922f33c710a515ae7b Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 24 Sep 2019 14:50:20 +0530 Subject: [PATCH 145/306] filesystem flake8 fixes --- src/storage/filesystem.py | 71 ++++++++++++++++++++++++++++++++------- src/storage/sqlite.py | 14 ++++++-- src/storage/storage.py | 5 +++ 3 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index d64894a9..4f7e717d 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -3,11 +3,11 @@ from os import listdir, makedirs, path, remove, rmdir import string from threading import RLock import time -import traceback from paths import lookupAppdataFolder from storage import InventoryStorage, InventoryItem + class FilesystemInventory(InventoryStorage): topDir = "inventory" objectDir = "objects" @@ -23,7 +23,9 @@ class FilesystemInventory(InventoryStorage): raise IOError("%s exists but it's not a directory" % (createDir)) else: makedirs(createDir) - self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) + # Guarantees that two receiveDataThreads don't receive and process the same message + # concurrently (probably sent by a malicious individual) + self.lock = RLock() self._inventory = {} self._load() @@ -53,9 +55,25 @@ class FilesystemInventory(InventoryStorage): except OSError: pass try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.metadataFilename), 'w') as f: + with open( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hash), + FilesystemInventory.metadataFilename, + ), + "w", + ) as f: f.write("%s,%s,%s,%s," % (value.type, value.stream, value.expires, hexlify(value.tag))) - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.dataFilename), 'w') as f: + with open( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hash), + FilesystemInventory.dataFilename, + ), + "w", + ) as f: f.write(value.payload) except IOError: raise KeyError @@ -73,11 +91,21 @@ class FilesystemInventory(InventoryStorage): pass with self.lock: try: - remove(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.metadataFilename)) + remove( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hash), + FilesystemInventory.metadataFilename)) except IOError: pass try: - remove(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.dataFilename)) + remove( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hash), + FilesystemInventory.dataFilename)) except IOError: pass try: @@ -88,7 +116,7 @@ class FilesystemInventory(InventoryStorage): def __iter__(self): elems = [] for streamDict in self._inventory.values(): - elems.extend (streamDict.keys()) + elems.extend(streamDict.keys()) return elems.__iter__() def __len__(self): @@ -103,10 +131,12 @@ class FilesystemInventory(InventoryStorage): try: objectType, streamNumber, expiresTime, tag = self.getMetadata(hashId) try: - newInventory[streamNumber][hashId] = InventoryItem(objectType, streamNumber, None, expiresTime, tag) + newInventory[streamNumber][hashId] = InventoryItem( + objectType, streamNumber, None, expiresTime, tag) except KeyError: newInventory[streamNumber] = {} - newInventory[streamNumber][hashId] = InventoryItem(objectType, streamNumber, None, expiresTime, tag) + newInventory[streamNumber][hashId] = InventoryItem( + objectType, streamNumber, None, expiresTime, tag) except KeyError: print "error loading %s" % (hexlify(hashId)) pass @@ -122,25 +152,42 @@ class FilesystemInventory(InventoryStorage): def getData(self, hashId): try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashId), FilesystemInventory.dataFilename), 'r') as f: + with open( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hashId), + FilesystemInventory.dataFilename, + ), + "r", + ) as f: return f.read() except IOError: raise AttributeError def getMetadata(self, hashId): try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashId), FilesystemInventory.metadataFilename), 'r') as f: + with open( + path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hashId), + FilesystemInventory.metadataFilename, + ), + "r", + ) as f: objectType, streamNumber, expiresTime, tag, undef = string.split(f.read(), ",", 4) return [int(objectType), int(streamNumber), int(expiresTime), unhexlify(tag)] except IOError: raise KeyError def by_type_and_tag(self, objectType, tag): + """Get a list of objects filtered by object type and tag""" retval = [] for stream, streamDict in self._inventory: for hashId, item in streamDict: if item.type == objectType and item.tag == tag: - try: + try: if item.payload is None: item.payload = self.getData(hashId) except IOError: diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 438cbdcb..d1ec220f 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -10,9 +10,17 @@ from storage import InventoryStorage, InventoryItem class SqliteInventory(InventoryStorage): def __init__(self): super(self.__class__, self).__init__() - self._inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet). - self._objects = {} # cache for existing objects, used for quick lookups if we have an object. This is used for example whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it. - self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) + # of objects (like msg payloads and pubkey payloads) + # Does not include protocol headers (the first 24 bytes of each packet). + self._inventory = {} + # cache for existing objects, used for quick lookups if we have an object. + # This is used for example whenever we receive an inv message from a peer + # to check to see what items are new to us. + # We don't delete things out of it; instead, the singleCleaner thread clears and refills it. + self._objects = {} + # Guarantees that two receiveDataThreads don't receive and process the same message concurrently + # (probably sent by a malicious individual) + self.lock = RLock() def __contains__(self, hash): with self.lock: diff --git a/src/storage/storage.py b/src/storage/storage.py index 08c85708..050197b8 100644 --- a/src/storage/storage.py +++ b/src/storage/storage.py @@ -3,6 +3,7 @@ import collections InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') class Storage(object): + """Base class for storing inventory (extendable for other items to store)""" pass # def __init__(self): # super(self.__class__, self).__init__() @@ -31,15 +32,19 @@ class InventoryStorage(Storage, collections.MutableMapping): raise NotImplementedError def by_type_and_tag(self, objectType, tag): + """Return objects filtered by object type and tag""" raise NotImplementedError def unexpired_hashes_by_stream(self, stream): + """Return unexpired inventory vectors filtered by stream""" raise NotImplementedError def flush(self): + """Flush cache""" raise NotImplementedError def clean(self): + """Free memory / perform garbage collection""" raise NotImplementedError class MailboxStorage(Storage, collections.MutableMapping): From ac341482d4435869d4d9988da61d1450a15f8d4c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 24 Sep 2019 14:51:53 +0530 Subject: [PATCH 146/306] filesystem pylint fixes --- src/storage/filesystem.py | 55 ++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index 4f7e717d..43ba03fc 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -1,3 +1,7 @@ +""" +src/storage/filesystem.py +========================= +""" from binascii import hexlify, unhexlify from os import listdir, makedirs, path, remove, rmdir import string @@ -8,14 +12,15 @@ from paths import lookupAppdataFolder from storage import InventoryStorage, InventoryItem -class FilesystemInventory(InventoryStorage): +class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ancestors, abstract-method + """Module for using filesystem (directory with files) for inventory storage""" topDir = "inventory" objectDir = "objects" metadataFilename = "metadata" dataFilename = "data" def __init__(self): - super(self.__class__, self).__init__() + super(FilesystemInventory, self).__init__() self.baseDir = path.join(lookupAppdataFolder(), FilesystemInventory.topDir) for createDir in [self.baseDir, path.join(self.baseDir, "objects")]: if path.exists(createDir): @@ -29,29 +34,29 @@ class FilesystemInventory(InventoryStorage): self._inventory = {} self._load() - def __contains__(self, hash): + def __contains__(self, hashval): retval = False for streamDict in self._inventory.values(): - if hash in streamDict: + if hashval in streamDict: return True return False - def __getitem__(self, hash): + def __getitem__(self, hashval): for streamDict in self._inventory.values(): try: - retval = streamDict[hash] + retval = streamDict[hashval] except KeyError: continue if retval.payload is None: - retval = InventoryItem(retval.type, retval.stream, self.getData(hash), retval.expires, retval.tag) + retval = InventoryItem(retval.type, retval.stream, self.getData(hashval), retval.expires, retval.tag) return retval - raise KeyError(hash) + raise KeyError(hashval) - def __setitem__(self, hash, value): + def __setitem__(self, hashval, value): with self.lock: value = InventoryItem(*value) try: - makedirs(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash))) + makedirs(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashval))) except OSError: pass try: @@ -59,7 +64,7 @@ class FilesystemInventory(InventoryStorage): path.join( self.baseDir, FilesystemInventory.objectDir, - hexlify(hash), + hexlify(hashval), FilesystemInventory.metadataFilename, ), "w", @@ -69,7 +74,7 @@ class FilesystemInventory(InventoryStorage): path.join( self.baseDir, FilesystemInventory.objectDir, - hexlify(hash), + hexlify(hashval), FilesystemInventory.dataFilename, ), "w", @@ -78,15 +83,16 @@ class FilesystemInventory(InventoryStorage): except IOError: raise KeyError try: - self._inventory[value.stream][hash] = value + self._inventory[value.stream][hashval] = value except KeyError: self._inventory[value.stream] = {} - self._inventory[value.stream][hash] = value + self._inventory[value.stream][hashval] = value - def delHashId(self, hash): - for stream in self._inventory.keys(): + def delHashId(self, hashval): + """Remove object from inventory""" + for stream in self._inventory: try: - del self._inventory[stream][hash] + del self._inventory[stream][hashval] except KeyError: pass with self.lock: @@ -95,7 +101,7 @@ class FilesystemInventory(InventoryStorage): path.join( self.baseDir, FilesystemInventory.objectDir, - hexlify(hash), + hexlify(hashval), FilesystemInventory.metadataFilename)) except IOError: pass @@ -104,12 +110,12 @@ class FilesystemInventory(InventoryStorage): path.join( self.baseDir, FilesystemInventory.objectDir, - hexlify(hash), + hexlify(hashval), FilesystemInventory.dataFilename)) except IOError: pass try: - rmdir(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash))) + rmdir(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashval))) except IOError: pass @@ -139,18 +145,20 @@ class FilesystemInventory(InventoryStorage): objectType, streamNumber, None, expiresTime, tag) except KeyError: print "error loading %s" % (hexlify(hashId)) - pass self._inventory = newInventory # for i, v in self._inventory.items(): # print "loaded stream: %s, %i items" % (i, len(v)) def stream_list(self): + """Return list of streams""" return self._inventory.keys() def object_list(self): + """Return inventory vectors (hashes) from a directory""" return [unhexlify(x) for x in listdir(path.join(self.baseDir, FilesystemInventory.objectDir))] def getData(self, hashId): + """Get object data""" try: with open( path.join( @@ -166,6 +174,7 @@ class FilesystemInventory(InventoryStorage): raise AttributeError def getMetadata(self, hashId): + """Get object metadata""" try: with open( path.join( @@ -196,12 +205,14 @@ class FilesystemInventory(InventoryStorage): return retval def hashes_by_stream(self, stream): + """Return inventory vectors (hashes) for a stream""" try: return self._inventory[stream].keys() except KeyError: return [] def unexpired_hashes_by_stream(self, stream): + """Return unexpired hashes in the inventory for a particular stream""" t = int(time.time()) try: return [x for x, value in self._inventory[stream].items() if value.expires > t] @@ -209,9 +220,11 @@ class FilesystemInventory(InventoryStorage): return [] def flush(self): + """Flush the inventory and create a new, empty one""" self._load() def clean(self): + """Clean out old items from the inventory""" minTime = int(time.time()) - (60 * 60 * 30) deletes = [] for stream, streamDict in self._inventory.items(): From 54ebbcb7db1f9ec0b2a0d0fe04ec189b70dd2b2a Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 25 Sep 2019 13:07:29 +0530 Subject: [PATCH 147/306] sqlite flake8 fixes --- src/storage/sqlite.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index d1ec220f..eb41b5c0 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -1,12 +1,11 @@ -import collections -from threading import current_thread, enumerate as threadingEnumerate, RLock -import Queue +from threading import RLock import sqlite3 import time -from helper_sql import * +from helper_sql import sqlQuery, SqlBulkExecute, sqlExecute from storage import InventoryStorage, InventoryItem + class SqliteInventory(InventoryStorage): def __init__(self): super(self.__class__, self).__init__() @@ -36,7 +35,9 @@ class SqliteInventory(InventoryStorage): with self.lock: if hash in self._inventory: return self._inventory[hash] - rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', sqlite3.Binary(hash)) + rows = sqlQuery( + 'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', + sqlite3.Binary(hash)) if not rows: raise KeyError(hash) return InventoryItem(*rows[0]) @@ -63,18 +64,22 @@ class SqliteInventory(InventoryStorage): def by_type_and_tag(self, objectType, tag): with self.lock: values = [value for value in self._inventory.values() if value.type == objectType and value.tag == tag] - values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', objectType, sqlite3.Binary(tag))) + values += (InventoryItem(*value) for value in sqlQuery( + 'SELECT objecttype, streamnumber, payload, expirestime, tag \ + FROM inventory WHERE objecttype=? AND tag=?', objectType, sqlite3.Binary(tag))) return values def unexpired_hashes_by_stream(self, stream): with self.lock: t = int(time.time()) hashes = [x for x, value in self._inventory.items() if value.stream == stream and value.expires > t] - hashes += (str(payload) for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) + hashes += (str(payload) for payload, in sqlQuery( + 'SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) return hashes def flush(self): - with self.lock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + with self.lock: + # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. with SqlBulkExecute() as sql: for objectHash, value in self._inventory.items(): sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', sqlite3.Binary(objectHash), *value) @@ -82,8 +87,7 @@ class SqliteInventory(InventoryStorage): def clean(self): with self.lock: - sqlExecute('DELETE FROM inventory WHERE expirestime Date: Wed, 25 Sep 2019 15:16:28 +0530 Subject: [PATCH 148/306] sqlite pylint fixes --- src/storage/sqlite.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index eb41b5c0..0c2b4afa 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -1,14 +1,19 @@ -from threading import RLock +""" +src/storage/sqlite.py +========================= +""" import sqlite3 import time +from threading import RLock from helper_sql import sqlQuery, SqlBulkExecute, sqlExecute from storage import InventoryStorage, InventoryItem -class SqliteInventory(InventoryStorage): +class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors + """Inventory using SQLite""" def __init__(self): - super(self.__class__, self).__init__() + super(SqliteInventory, self).__init__() # of objects (like msg payloads and pubkey payloads) # Does not include protocol headers (the first 24 bytes of each packet). self._inventory = {} @@ -21,34 +26,34 @@ class SqliteInventory(InventoryStorage): # (probably sent by a malicious individual) self.lock = RLock() - def __contains__(self, hash): + def __contains__(self, hash_): with self.lock: - if hash in self._objects: + if hash_ in self._objects: return True - rows = sqlQuery('SELECT streamnumber FROM inventory WHERE hash=?', sqlite3.Binary(hash)) + rows = sqlQuery('SELECT streamnumber FROM inventory WHERE hash=?', sqlite3.Binary(hash_)) if not rows: return False - self._objects[hash] = rows[0][0] + self._objects[hash_] = rows[0][0] return True - def __getitem__(self, hash): + def __getitem__(self, hash_): with self.lock: - if hash in self._inventory: - return self._inventory[hash] + if hash_ in self._inventory: + return self._inventory[hash_] rows = sqlQuery( 'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', - sqlite3.Binary(hash)) + sqlite3.Binary(hash_)) if not rows: - raise KeyError(hash) + raise KeyError(hash_) return InventoryItem(*rows[0]) - def __setitem__(self, hash, value): + def __setitem__(self, hash_, value): with self.lock: value = InventoryItem(*value) - self._inventory[hash] = value - self._objects[hash] = value.stream + self._inventory[hash_] = value + self._objects[hash_] = value.stream - def __delitem__(self, hash): + def __delitem__(self, hash_): raise NotImplementedError def __iter__(self): From e924e9208f3669d8ccfd8aaffb82dbbb6420b063 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 25 Sep 2019 16:39:15 +0530 Subject: [PATCH 149/306] storage flake8 fixes --- src/storage/storage.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/storage/storage.py b/src/storage/storage.py index 050197b8..4e603021 100644 --- a/src/storage/storage.py +++ b/src/storage/storage.py @@ -2,15 +2,17 @@ import collections InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') + class Storage(object): """Base class for storing inventory (extendable for other items to store)""" pass # def __init__(self): # super(self.__class__, self).__init__() + class InventoryStorage(Storage, collections.MutableMapping): def __init__(self): -# super(self.__class__, self).__init__() + # super(self.__class__, self).__init__() self.numberOfInventoryLookupsPerformed = 0 def __contains__(self, hash): @@ -47,7 +49,8 @@ class InventoryStorage(Storage, collections.MutableMapping): """Free memory / perform garbage collection""" raise NotImplementedError + class MailboxStorage(Storage, collections.MutableMapping): def __init__(self): -# super(self.__class__, self).__init__() + # super(self.__class__, self).__init__() pass From fba2d6d8375fa6968dd1a0c01354e2f7b08ce490 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 26 Sep 2019 14:12:15 +0530 Subject: [PATCH 150/306] storage pylint fixes --- src/storage/storage.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/storage/storage.py b/src/storage/storage.py index 4e603021..482937e7 100644 --- a/src/storage/storage.py +++ b/src/storage/storage.py @@ -1,3 +1,7 @@ +""" +src/storage/storage.py +====================== +""" import collections InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') @@ -6,25 +10,24 @@ InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload exp class Storage(object): """Base class for storing inventory (extendable for other items to store)""" pass -# def __init__(self): -# super(self.__class__, self).__init__() class InventoryStorage(Storage, collections.MutableMapping): + """Module used for inventory storage""" def __init__(self): - # super(self.__class__, self).__init__() + # pylint: disable=super-init-not-called self.numberOfInventoryLookupsPerformed = 0 - def __contains__(self, hash): + def __contains__(self, _): raise NotImplementedError - def __getitem__(self, hash): + def __getitem__(self, _): raise NotImplementedError - def __setitem__(self, hash, value): + def __setitem__(self, _, value): raise NotImplementedError - def __delitem__(self, hash): + def __delitem__(self, _): raise NotImplementedError def __iter__(self): @@ -50,7 +53,8 @@ class InventoryStorage(Storage, collections.MutableMapping): raise NotImplementedError -class MailboxStorage(Storage, collections.MutableMapping): +class MailboxStorage(Storage, collections.MutableMapping): # pylint: disable=abstract-method + """Method for storing mails""" def __init__(self): - # super(self.__class__, self).__init__() + # pylint: disable=super-init-not-called pass From 40e15579fdeee55352a28545f664fc7bc8b602c6 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 27 Sep 2019 19:31:55 +0530 Subject: [PATCH 151/306] messagetypes init flake and pylint fixes --- src/messagetypes/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 06783eac..7319dfd5 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,3 +1,7 @@ +""" +src/messagetypes/__init__.py +============================ +""" from importlib import import_module from os import path, listdir from string import lower @@ -6,12 +10,15 @@ from debug import logger import messagetypes import paths -class MsgBase(object): - def encode(self): + +class MsgBase(object): # pylint: disable=too-few-public-methods + """Base class for message types""" + def __init__(self): self.data = {"": lower(type(self).__name__)} def constructObject(data): + """Constructing an object""" whitelist = ["message"] if data[""] not in whitelist: return None @@ -32,6 +39,7 @@ def constructObject(data): else: return returnObj + if paths.frozen is not None: import messagetypes.message import messagetypes.vote From c12fd486ac51ff1a822a5deb490d7a188446dab7 Mon Sep 17 00:00:00 2001 From: Navjot Date: Fri, 27 Sep 2019 22:01:37 +0530 Subject: [PATCH 152/306] worked on alter search approch or making app preformance faster --- src/bitmessagekivy/main.kv | 119 ++++++++++++---------- src/bitmessagekivy/mpybit.py | 188 +++++++++++++++-------------------- 2 files changed, 149 insertions(+), 158 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 920ca2ef..be6f76e9 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -82,52 +82,52 @@ text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: draft_cnt icon: 'message-draw' text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Starred" icon:'star' on_release: app.root.ids.scr_mngr.current = 'starred' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: icon: 'archive' text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'archieve' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: icon: 'email-open-outline' text: "Spam" on_release: app.root.ids.scr_mngr.current = 'spam' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: allmail_cnt text: "All Mails" icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'allmails' badge_text: "0" - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -135,37 +135,37 @@ text: "Address Book" icon:'book-multiple' on_release: app.root.ids.scr_mngr.current = 'addressbook' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Settings" icon:'settings' on_release: app.root.ids.scr_mngr.current = 'set' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Subscriptions/Payment" icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'payment' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Credits" icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'credits' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "new address" icon:'account-plus' on_release: app.root.ids.scr_mngr.current = 'login' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Network Status" icon:'server-network' on_release: app.root.ids.scr_mngr.current = 'networkstat' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "My Addresses" icon:'account-multiple' on_release: app.root.ids.scr_mngr.current = 'myaddress' - on_press: app.check_search_screen(self) + on_press: app.refreshScreen(self) NavigationLayout: id: nav_layout @@ -186,18 +186,6 @@ NavigationLayout: background_hue: '500' left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] right_action_items: [['account-plus', lambda x: app.addingtoaddressbook()]] - BoxLayout: - 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) ScreenManager: id: scr_mngr @@ -246,21 +234,30 @@ NavigationLayout: : name: 'inbox' - FloatLayout: - MDScrollViewRefreshLayout: - id: refresh_layout - refresh_callback: root.refresh_callback - root_layout: root - MDList: - id: ml + BoxLayout: + orientation: 'vertical' + spacing: dp(10) + SearchBar: + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml ComposerButton: : name: 'sent' - ScrollView: - do_scroll_x: False - MDList: - id: ml + BoxLayout: + orientation: 'vertical' + SearchBar: + BoxLayout: + orientation:'vertical' + ScrollView: + do_scroll_x: False + MDList: + id: ml ComposerButton: : @@ -654,23 +651,29 @@ NavigationLayout: : name: 'myaddress' - FloatLayout: - MDScrollViewRefreshLayout: - id: refresh_layout - refresh_callback: root.refresh_callback - root_layout: root - MDList: - id: ml + BoxLayout: + orientation: 'vertical' + SearchBar: + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml ComposerButton: : name: 'addressbook' BoxLayout: - orientation:'vertical' - ScrollView: - do_scroll_x: False - MDList: - id: ml + orientation: 'vertical' + SearchBar: + BoxLayout: + orientation:'vertical' + ScrollView: + do_scroll_x: False + MDList: + id: ml ComposerButton: : @@ -1222,4 +1225,18 @@ NavigationLayout: source: './images/down-arrow.png' if self.parent.is_open == True else './images/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 \ No newline at end of file + 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) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 1b4db996..518c227e 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -79,8 +79,6 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" - data = ListProperty() - def __init__(self, *args, **kwargs): """Method Parsing the address.""" super(Inbox, self).__init__(*args, **kwargs) @@ -168,7 +166,6 @@ class Inbox(Screen): def inbox_detail(self, receivedTime, *args): """Load inbox page details.""" - remove_search_bar(self) state.detailPageType = 'inbox' state.sentMailTime = receivedTime if self.manager: @@ -184,8 +181,12 @@ class Inbox(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( data_index)) - msg_count_objs = \ - self.parent.parent.parent.parent.parent.children[2].children[0].ids + try: + msg_count_objs = \ + self.parent.parent.parent.parent.children[2].children[0].ids + except Exception as e: + msg_count_objs = \ + self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.inbox_count) > 0: msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) @@ -226,13 +227,10 @@ class Inbox(Screen): """Method updates the state of application, While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" + state.searcing_text = '' + self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() - self.remove_widget(self.children[1]) - try: - screens_obj = self.parent.screens[0] - except Exception: - screens_obj = self.parent.parent.screens[0] - screens_obj.add_widget(Inbox()) + self.loadMessagelist(state.association) self.ids.refresh_layout.refresh_done() self.tick = 0 @@ -284,12 +282,11 @@ class MyAddress(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) - try: - self.manager.parent.parent\ - .parent.ids.search_bar.clear_widgets() - self.manager.current = 'login' - except Exception: - pass + if not state.searcing_text: + try: + self.manager.current = 'login' + except Exception: + pass @staticmethod def myadd_detail(fromaddress, label, *args): @@ -303,13 +300,10 @@ class MyAddress(Screen): """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 = '' + self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() - self.remove_widget(self.children[1]) - try: - screens_obj = self.parent.screens[9] - except Exception: - screens_obj = self.parent.parent.screens[9] - screens_obj.add_widget(MyAddress()) + self.init_ui() self.ids.refresh_layout.refresh_done() self.tick = 0 Clock.schedule_once(refresh_callback, 1) @@ -386,8 +380,8 @@ class AddressBook(Screen): @staticmethod def refreshs(*args): """Refresh the Widget.""" - state.navinstance.ids.sc11.clear_widgets() - state.navinstance.ids.sc11.add_widget(AddressBook()) + state.navinstance.ids.sc11.ids.ml.clear_widgets() + state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') @staticmethod def addBook_detail(address, label, *args): @@ -523,8 +517,8 @@ class DropDownWidget(BoxLayout): state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[0].children[2].children[0].ids - self.parent.parent.screens[3].clear_widgets() - self.parent.parent.screens[3].add_widget(Sent()) + self.parent.parent.screens[3].ids.ml.clear_widgets() + self.parent.parent.screens[3].loadSent(state.association) self.parent.parent.screens[16].clear_widgets() self.parent.parent.screens[16].add_widget(Allmails()) toLabel = '' @@ -701,9 +695,8 @@ class Random(Screen): self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - self.parent.parent.parent.parent.ids.sc10.clear_widgets() - self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) - navApp.add_search_bar() + self.parent.parent.parent.parent.ids.sc10.ids.ml.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.init_ui() toast('New address created') @@ -715,9 +708,6 @@ class AddressSuccessful(Screen): class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" - - data = ListProperty() - def __init__(self, *args, **kwargs): """Association with the screen.""" super(Sent, self).__init__(*args, **kwargs) @@ -742,6 +732,7 @@ class Sent(Screen): where = ['subject', 'message'] what = state.searcing_text xAddress = 'fromaddress' + data = [] queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) if state.msg_counter_objs and state.association == \ @@ -757,13 +748,13 @@ class Sent(Screen): src_mng_obj.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(len(queryreturn)) for mail in queryreturn: - self.data.append({ + data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( mail[2]) >= 50 else ( mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'lastactiontime': mail[6]}) - for item in self.data: + for item in data: meny = TwoLineAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], @@ -808,7 +799,6 @@ class Sent(Screen): def sent_detail(self, lastsenttime, *args): """Load sent mail details.""" - remove_search_bar(self) state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: @@ -1031,8 +1021,9 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label state.association = text - self.root.ids.sc1.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) + state.searcing_text = '' + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = \ @@ -1135,7 +1126,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.current = 'login' else: self.root.ids.scr_mngr.current = 'inbox' - self.add_search_bar() self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) return True @@ -1155,7 +1145,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" self.set_navbar_for_composer() - self.root.ids.search_bar.clear_widgets() + # self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -1183,8 +1173,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) if state.is_allmail or state.detailPageType == 'draft': state.is_allmail = False - else: - self.add_search_bar() state.detailPageType = '' state.in_composer = False @@ -1211,66 +1199,60 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods return label + address return '' - def searchQuery(self, instance, *args): + def searchQuery(self, instance): """Method used for showing searched mails.""" state.search_screen = self.root.ids.scr_mngr.current state.searcing_text = str(instance.text).strip() if state.search_screen == 'inbox': - self.root.ids.sc1.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) elif state.search_screen == 'addressbook': - self.root.ids.sc11.clear_widgets() - self.root.ids.sc11.add_widget(AddressBook()) + self.root.ids.sc11.ids.ml.clear_widgets() + self.root.ids.sc11.loadAddresslist(None, 'All', '') elif state.search_screen == 'myaddress': - self.root.ids.sc10.clear_widgets() - self.root.ids.sc10.add_widget(MyAddress()) + self.root.ids.sc10.ids.ml.clear_widgets() + self.root.ids.sc10.init_ui() else: - self.root.ids.sc4.clear_widgets() - self.root.ids.sc4.add_widget(Sent()) + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.loadSent(state.association) self.root.ids.scr_mngr.current = state.search_screen - def clearSreeen(self, text): - """Method is used for clear screen""" - if text == 'Sent': - self.root.ids.sc4.clear_widgets() - self.root.ids.sc4.add_widget(Sent()) - elif text == 'Draft': + def refreshScreen(self, instance): + """Method show search button only on inbox or sent screen.""" + state.searcing_text = '' + if instance.text == 'Sent': + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' + self.root.ids.sc4.loadSent(state.association) + elif instance.text == 'Inbox': + self.root.ids.sc1.ids.ml.clear_widgets() + try: + self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' + except Exception as e: + self.root.ids.sc1.children[1].children[1].ids.search_field.text = '' + self.root.ids.sc1.loadMessagelist(state.association) + elif instance.text == 'Draft': self.root.ids.sc16.clear_widgets() self.root.ids.sc16.add_widget(Draft()) - elif text == 'Trash': + elif instance.text == 'Trash': self.root.ids.sc5.clear_widgets() self.root.ids.sc5.add_widget(Trash()) - elif text == 'All Mails': + elif instance.text == 'All Mails': self.root.ids.sc17.clear_widgets() self.root.ids.sc17.add_widget(Allmails()) - - def check_search_screen(self, instance): - """Method show search button only on inbox or sent screen.""" - if instance.text in ['Sent', 'Draft', 'Trash', 'All Mails']: - self.clearSreeen(instance.text) - if instance.text in ['Inbox', 'Sent', 'Address Book', 'My Addresses']: - if not self.root.ids.search_bar.children: - self.root.ids.search_bar.add_widget( - MDIconButton(icon='magnify')) - text_field = MDTextField( - id='search_field', hint_text='Search') - text_field.bind(text=self.searchQuery) - self.root.ids.search_bar.add_widget(text_field) - self.root.ids.search_bar.children[0].text = '' - else: - self.root.ids.search_bar.clear_widgets() - state.searcing_text = '' + elif instance.text == 'Address Book': + self.root.ids.sc11.ids.ml.clear_widgets() + self.root.ids.sc11.children[1].children[1].ids.search_field.text = '' + self.root.ids.sc11.loadAddresslist(None, 'All', '') + elif instance.text == 'My Addresses': + self.root.ids.sc10.ids.ml.clear_widgets() + try: + self.root.ids.sc10.children[1].children[1].ids.search_field.text = '' + except Exception as e: + self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' + self.root.ids.sc10.init_ui() return - def add_search_bar(self): - """Method used for adding search function on screen""" - if not self.root.ids.search_bar.children: - self.root.ids.search_bar.add_widget(MDIconButton(icon='magnify')) - text_field = MDTextField( - id='search_field', hint_text='Search') - text_field.bind(text=self.searchQuery) - self.root.ids.search_bar.add_widget(text_field) - def set_identicon(self, text): """This method is use for showing identicon in address spinner""" img = identiconGeneration.generate(text) @@ -1477,8 +1459,8 @@ class MailDetail(Screen): lastactiontime = {};".format(state.sentMailTime)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) - self.parent.screens[3].clear_widgets() - self.parent.screens[3].add_widget(Sent()) + self.parent.screens[3].ids.ml.clear_widgets() + self.parent.screens[3].loadSent(state.association) elif state.detailPageType == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ @@ -1486,8 +1468,8 @@ class MailDetail(Screen): # msg_count_objs.inbox_cnt.badge_text = str( # int(state.inbox_count) - 1) # state.inbox_count = str(int(state.inbox_count) - 1) - self.parent.screens[0].clear_widgets() - self.parent.screens[0].add_widget(Inbox()) + self.parent.screens[0].ids.ml.clear_widgets() + self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( state.sentMailTime)) @@ -1519,6 +1501,7 @@ class MailDetail(Screen): composer_obj.btn.text = data[0][0] composer_obj.txt_input.text = data[0][1] composer_obj.subject.text = data[0][2] + composer_obj.body.text = '' state.kivyapp.root.ids.sc3.children[0].ids.rv.data = '' self.parent.current = 'create' state.kivyapp.set_navbar_for_composer() @@ -1603,8 +1586,8 @@ class AddbookDetailPopup(Popup): if str(self.ids.add_label.text): sqlExecute("UPDATE addressbook SET label = '{}' WHERE \ address = '{}';".format(str(self.ids.add_label.text), address)) - self.parent.children[1].ids.sc11.clear_widgets() - self.parent.children[1].ids.sc11.add_widget(AddressBook()) + self.parent.children[1].ids.sc11.ids.ml.clear_widgets() + self.parent.children[1].ids.sc11.loadAddresslist(None, 'All', '') self.dismiss() toast('Saved') @@ -1630,7 +1613,7 @@ class ShowQRCode(Screen): def qrdisplay(self): """Method used for showing QR Code.""" - self.manager.parent.parent.parent.ids.search_bar.clear_widgets() + # self.manager.parent.parent.parent.ids.search_bar.clear_widgets() self.ids.qr.clear_widgets() from kivy.garden.qrcode import QRCodeWidget self.ids.qr.add_widget(QRCodeWidget( @@ -1659,9 +1642,9 @@ class Draft(Screen): def sentaccounts(self): """Load draft accounts.""" account = state.association - self.loadSent(account, 'All', '') + self.loadDraft(account, 'All', '') - def loadSent(self, account, where="", what=""): + def loadDraft(self, account, where="", what=""): """Load draft list for Draft messages.""" xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( @@ -1807,14 +1790,6 @@ class CustomSpinner(Spinner): self.dropdown_cls.max_height = Window.size[1] / 3 -def remove_search_bar(obj): - """Remove search bar.""" - try: - obj.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() - except Exception: - obj.parent.parent.parent.parent.ids.search_bar.clear_widgets() - - class Allmails(Screen): """all mails Screen uses screen to show widgets of screens.""" @@ -1894,7 +1869,6 @@ class Allmails(Screen): def mail_detail(self, unique_id, folder, *args): """Load sent and inbox mail details.""" - remove_search_bar(self) state.detailPageType = folder state.is_allmail = True state.sentMailTime = unique_id @@ -1929,14 +1903,14 @@ class Allmails(Screen): msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) - nav_lay_obj.sc1.clear_widgets() - nav_lay_obj.sc1.add_widget(Inbox()) + nav_lay_obj.sc1.ids.ml.clear_widgets() + nav_lay_obj.sc1.loadMessagelist(state.association) else: msg_count_objs.send_cnt.badge_text = str( int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) - nav_lay_obj.sc4.clear_widgets() - nav_lay_obj.sc4.add_widget(Sent()) + nav_lay_obj.sc4.ids.ml.clear_widgets() + nav_lay_obj.sc4.loadSent(state.association) msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) msg_count_objs.allmail_cnt.badge_text = str( From 9aa7dd9d78d4eda83f78f577af7b47ccd8694fa2 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 30 Sep 2019 18:42:36 +0530 Subject: [PATCH 153/306] message pylint fixes --- src/messagetypes/message.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index f52c6b35..cd5bf762 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -1,24 +1,30 @@ +""" +src/messagetypes/message.py +=========================== +""" from debug import logger from messagetypes import MsgBase class Message(MsgBase): - def __init__(self): - return + """Encapsulate a message""" + # pylint: disable=attribute-defined-outside-init def decode(self, data): + """Decode a message""" # UTF-8 and variable type validator - if type(data["subject"]) is str: + if isinstance(data["subject"], str): self.subject = unicode(data["subject"], 'utf-8', 'replace') else: self.subject = unicode(str(data["subject"]), 'utf-8', 'replace') - if type(data["body"]) is str: + if isinstance(data["body"], str): self.body = unicode(data["body"], 'utf-8', 'replace') else: self.body = unicode(str(data["body"]), 'utf-8', 'replace') def encode(self, data): - super(Message, self).encode() + """Encode a message""" + super(Message, self).__init__() try: self.data["subject"] = data["subject"] self.data["body"] = data["body"] @@ -27,5 +33,6 @@ class Message(MsgBase): return self.data def process(self): + """Process a message""" logger.debug("Subject: %i bytes", len(self.subject)) logger.debug("Body: %i bytes", len(self.body)) From e5b92e29a2d62a5549bd36786db2fa7c7af4eb2e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 30 Sep 2019 18:42:50 +0530 Subject: [PATCH 154/306] vote pylint fixes --- src/messagetypes/vote.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index df8d267f..e128e9ba 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -1,23 +1,31 @@ +""" +src/messagetypes/vote.py +======================== +""" from debug import logger from messagetypes import MsgBase + class Vote(MsgBase): - def __init__(self): - return + """Module used to vote""" def decode(self, data): + """decode a vote""" + # pylint: disable=attribute-defined-outside-init self.msgid = data["msgid"] self.vote = data["vote"] def encode(self, data): - super(Vote, self).encode() + """Encode a vote""" + super(Vote, self).__init__() try: self.data["msgid"] = data["msgid"] self.data["vote"] = data["vote"] except KeyError as e: - logger.error("Missing key %s", e.name) + logger.error("Missing key %s", e) return self.data def process(self): + """Encode a vote""" logger.debug("msgid: %s", self.msgid) logger.debug("vote: %s", self.vote) From ec7e84a4f7151a5de6a2777593d8e9b7e9402934 Mon Sep 17 00:00:00 2001 From: surbhi Date: Mon, 30 Sep 2019 19:13:18 +0530 Subject: [PATCH 155/306] resolve conflicts relevant openssl --- src/pyelliptic/openssl.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index ae50116a..d204c22d 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -654,13 +654,9 @@ class _OpenSSL: def loadOpenSSL(): -<<<<<<< HEAD """Method find and load the OpenSSL library""" # pylint: disable=global-statement, protected-access, too-many-branches -======= - """This function finds and load the OpenSSL library""" - # pylint: disable=global-statement ->>>>>>> fba2d6d8375fa6968dd1a0c01354e2f7b08ce490 + global OpenSSL from os import path, environ from ctypes.util import find_library From 0a5379f7ab426f539d6b95a3beb6303b191e2741 Mon Sep 17 00:00:00 2001 From: Navjot Date: Mon, 30 Sep 2019 19:27:57 +0530 Subject: [PATCH 156/306] merge commit conflicts --- src/messagetypes/__init__.py | 3 +-- src/messagetypes/message.py | 16 ++++++---------- src/messagetypes/vote.py | 15 +++++++-------- src/pyelliptic/openssl.py | 1 + 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 95eee595..53d23de7 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -2,7 +2,6 @@ src/messagetypes/__init__.py ============================ """ -# pylint: disable=import-error from importlib import import_module from os import path, listdir from string import lower @@ -22,7 +21,7 @@ class MsgBase(object): # pylint: disable=too-few-public-methods def constructObject(data): - """Construct an object""" + """Constructing an object""" whitelist = ["message"] if data[""] not in whitelist: return None diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index 263a2e4a..46816d82 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -9,26 +9,22 @@ from messagetypes import MsgBase class Message(MsgBase): """Base method, helps to decode, encode and process the message""" - def __init__(self): # pylint: disable=super-init-not-called - return def decode(self, data): - """Method used for decoding the message""" + """Decode a message""" # UTF-8 and variable type validator - # pylint: disable=unidiomatic-typecheck - if type(data["subject"]) is str: + if isinstance(data["subject"], str): self.subject = unicode(data["subject"], 'utf-8', 'replace') else: self.subject = unicode(str(data["subject"]), 'utf-8', 'replace') - if type(data["body"]) is str: + if isinstance(data["body"], str): self.body = unicode(data["body"], 'utf-8', 'replace') else: self.body = unicode(str(data["body"]), 'utf-8', 'replace') def encode(self, data): - """Method used for encoding the message""" - # pylint: disable=no-member - super(Message, self).encode() + """Encode a message""" + super(Message, self).__init__() try: self.data["subject"] = data["subject"] self.data["body"] = data["body"] @@ -37,6 +33,6 @@ class Message(MsgBase): return self.data def process(self): - """Method used for process the message""" + """Process a message""" logger.debug("Subject: %i bytes", len(self.subject)) logger.debug("Body: %i bytes", len(self.body)) diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index a77e1cc7..fb5ad6c8 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -7,28 +7,27 @@ from messagetypes import MsgBase # pylint: disable=attribute-defined-outside-init + class Vote(MsgBase): """Base method, helps to decode, encode and process the message""" - def __init__(self): # pylint: disable=super-init-not-called - return def decode(self, data): - """Method used for decoding the message""" + """decode a vote""" + # pylint: disable=attribute-defined-outside-init self.msgid = data["msgid"] self.vote = data["vote"] def encode(self, data): - """Method used for encoding the message""" - # pylint: disable=no-member - super(Vote, self).encode() + """Encode a vote""" + super(Vote, self).__init__() try: self.data["msgid"] = data["msgid"] self.data["vote"] = data["vote"] except KeyError as e: - logger.error("Missing key %s", e.name) + logger.error("Missing key %s", e) return self.data def process(self): - """Method used for process the message""" + """Encode a vote""" logger.debug("msgid: %s", self.msgid) logger.debug("vote: %s", self.vote) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 17bf52c8..0b9be0ab 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -657,6 +657,7 @@ class _OpenSSL: def loadOpenSSL(): """Method find and load the OpenSSL library""" # pylint: disable=global-statement, protected-access, too-many-branches + global OpenSSL from os import path, environ from ctypes.util import find_library From 66de416627b75090687710ee69113ea20743f1c1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 30 Sep 2019 19:57:08 +0530 Subject: [PATCH 157/306] fixes after conflicts --- src/bitmessagekivy/mpybit.py | 3 +-- src/messagetypes/vote.py | 2 -- src/pyelliptic/openssl.py | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 518c227e..7f3da132 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -49,7 +49,6 @@ from kivymd.navigationdrawer import ( MDNavigationDrawer, NavigationDrawerHeaderBase) from kivymd.selectioncontrols import MDCheckbox -from kivymd.textfields import MDTextField from kivymd.theming import ThemeManager import queues from semaphores import kivyuisignaler @@ -1398,7 +1397,7 @@ class NavigationDrawerTwoLineListItem( def _update_specific_text_color(self, instance, value): pass - def _set_active(self, active, list): # pylint: disable=redefined-builtin + def _set_active(self, active, list_): pass diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index 82a5031f..319deb59 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -7,8 +7,6 @@ from messagetypes import MsgBase # pylint: disable=attribute-defined-outside-init - - class Vote(MsgBase): """Module used to vote""" diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 0b9be0ab..6c5c4a84 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -22,8 +22,6 @@ src/pyelliptic/openssl.py # pylint: disable=protected-access - - class CipherName: """Class returns cipher name, pointer and blocksize""" From 9a438c1a1a9fe252a7fee5771060ce90d3801509 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 27 Sep 2019 17:09:29 +0300 Subject: [PATCH 158/306] flake8: paths --- src/paths.py | 117 ++++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/src/paths.py b/src/paths.py index 325fcd8b..ada54c8e 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,76 +1,85 @@ -from os import environ, path -import sys +import logging +import os import re +import sys from datetime import datetime +from shutil import move + + +logger = logging.getLogger('default') # When using py2exe or py2app, the variable frozen is added to the sys -# namespace. This can be used to setup a different code path for +# namespace. This can be used to setup a different code path for # binary distributions vs source distributions. -frozen = getattr(sys,'frozen', None) +frozen = getattr(sys, 'frozen', None) + def lookupExeFolder(): + """Returns executable folder path""" if frozen: - if frozen == "macosx_app": + exeFolder = ( # targetdir/Bitmessage.app/Contents/MacOS/Bitmessage - exeFolder = path.dirname(path.dirname(path.dirname(path.dirname(sys.executable)))) + path.sep - else: - exeFolder = path.dirname(sys.executable) + path.sep + os.path.dirname(sys.executable).split(os.path.sep)[0] + os.path.sep + if frozen == "macosx_app" else + os.path.dirname(sys.executable) + os.path.sep) elif __file__: - exeFolder = path.dirname(__file__) + path.sep + exeFolder = os.path.dirname(__file__) + os.path.sep else: exeFolder = '' return exeFolder + def lookupAppdataFolder(): + """Returns path of the folder where application data is stored""" APPNAME = "PyBitmessage" - if "BITMESSAGE_HOME" in environ: - dataFolder = environ["BITMESSAGE_HOME"] - if dataFolder[-1] not in [path.sep, path.altsep]: - dataFolder += path.sep + dataFolder = os.environ.get('BITMESSAGE_HOME') + if dataFolder: + if dataFolder[-1] not in (os.path.sep, os.path.altsep): + dataFolder += os.path.sep elif sys.platform == 'darwin': - if "HOME" in environ: - dataFolder = path.join(environ["HOME"], "Library/Application Support/", APPNAME) + '/' - else: - stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.' - if 'logger' in globals(): - logger.critical(stringToLog) - else: - print stringToLog - sys.exit() - - elif 'win32' in sys.platform or 'win64' in sys.platform: - dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep - else: - from shutil import move try: - dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME) + dataFolder = os.path.join( + os.environ['HOME'], + 'Library/Application Support/', APPNAME + ) + '/' # FIXME: should also be os.path.sep except KeyError: - dataFolder = path.join(environ["HOME"], ".config", APPNAME) - - # Migrate existing data to the proper location if this is an existing install + sys.exit( + 'Could not find home folder, please report this message' + ' and your OS X version to the BitMessage Github.') + elif 'win32' in sys.platform or 'win64' in sys.platform: + dataFolder = os.path.join( + os.environ['APPDATA'].decode( + sys.getfilesystemencoding(), 'ignore'), APPNAME + ) + os.path.sep + else: try: - move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder) - stringToLog = "Moving data folder to %s" % (dataFolder) - if 'logger' in globals(): - logger.info(stringToLog) - else: - print stringToLog + dataFolder = os.path.join(os.environ['XDG_CONFIG_HOME'], APPNAME) + except KeyError: + dataFolder = os.path.join(os.environ['HOME'], '.config', APPNAME) + + # Migrate existing data to the proper location + # if this is an existing install + try: + move(os.path.join(os.environ['HOME'], '.%s' % APPNAME), dataFolder) + logger.info('Moving data folder to %s', dataFolder) except IOError: # Old directory may not exist. pass - dataFolder = dataFolder + '/' + dataFolder = dataFolder + os.path.sep return dataFolder - + + def codePath(): - if frozen == "macosx_app": - codePath = environ.get("RESOURCEPATH") - elif frozen: # windows - codePath = sys._MEIPASS - else: - codePath = path.dirname(__file__) - return codePath + """Returns path to the program sources""" + if not frozen: + return os.path.dirname(__file__) + return ( + os.environ.get('RESOURCEPATH') + if frozen == "macosx_app" else sys._MEIPASS) + def tail(f, lines=20): + """Returns last lines in the f file object""" total_lines_wanted = lines BLOCK_SIZE = 1024 @@ -78,16 +87,17 @@ def tail(f, lines=20): block_end_byte = f.tell() lines_to_go = total_lines_wanted block_number = -1 - blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting - # from the end of the file + # blocks of size BLOCK_SIZE, in reverse order starting + # from the end of the file + blocks = [] while lines_to_go > 0 and block_end_byte > 0: if (block_end_byte - BLOCK_SIZE > 0): # read the last block we haven't yet read - f.seek(block_number*BLOCK_SIZE, 2) + f.seek(block_number * BLOCK_SIZE, 2) blocks.append(f.read(BLOCK_SIZE)) else: # file too small, start from begining - f.seek(0,0) + f.seek(0, 0) # only read what was not read blocks.append(f.read(block_end_byte)) lines_found = blocks[-1].count('\n') @@ -99,9 +109,12 @@ def tail(f, lines=20): def lastCommit(): - githeadfile = path.join(codePath(), '..', '.git', 'logs', 'HEAD') + """ + Returns last commit information as dict with 'commit' and 'time' keys + """ + githeadfile = os.path.join(codePath(), '..', '.git', 'logs', 'HEAD') result = {} - if path.isfile(githeadfile): + if os.path.isfile(githeadfile): try: with open(githeadfile, 'rt') as githead: line = tail(githead, 1) From f3f6715d462e2deef524dca920631c5d52310a48 Mon Sep 17 00:00:00 2001 From: Navjot Date: Thu, 3 Oct 2019 21:57:54 +0530 Subject: [PATCH 159/306] worked on implementing sql query for sent and inbox on the bases of unique id --- .gitignore | 3 +- src/bitmessagekivy/mpybit.py | 86 +++++++++++++++++------------------- src/state.py | 2 +- 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 90a31335..0ddedf04 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ docs/_*/* docs/autodoc/ pyan/ .buildozer/ -bin/ \ No newline at end of file +bin/ +src/images/default_identicon/ \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 7f3da132..7fd1b661 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -119,7 +119,7 @@ class Inbox(Screen): 'secondary_text': mail[5][:50] + '........' if len( mail[5]) >= 50 else ( mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', - 'receivedTime': mail[6]}) + 'msgid': mail[1]}) for item in data: meny = TwoLineAvatarIconListItem( text=item['text'], @@ -130,7 +130,7 @@ class Inbox(Screen): source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( - self.inbox_detail, item['receivedTime'])) + self.inbox_detail, item['msgid'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -141,13 +141,13 @@ class Inbox(Screen): del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( - self.delete, item['receivedTime'])) + self.delete, item['msgid'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) ach_btn.bind(on_press=partial( - self.archive, item['receivedTime'])) + self.archive, item['msgid'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) @@ -163,10 +163,10 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) - def inbox_detail(self, receivedTime, *args): + def inbox_detail(self, msg_id, *args): """Load inbox page details.""" state.detailPageType = 'inbox' - state.sentMailTime = receivedTime + state.mail_id = msg_id if self.manager: src_mng_obj = self.manager else: @@ -178,7 +178,7 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing.""" sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( data_index)) try: msg_count_objs = \ @@ -207,7 +207,7 @@ class Inbox(Screen): def archive(self, data_index, instance, *args): """Archive inbox mail from inbox listing.""" sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -465,15 +465,15 @@ class DropDownWidget(BoxLayout): if status == 'success': if state.detailPageType == 'draft' and state.send_draft_mail: sqlExecute( - "UPDATE sent SET toaddress = '{0}' \ - , fromaddress ='{1}' , subject = '{2}'\ - , message = '{3}', folder = 'sent'\ - WHERE lastactiontime = '{4}';".format( + "UPDATE sent SET toaddress = ? \ + , fromaddress = ? , subject = ?\ + , message = ?, folder = 'sent'\ + WHERE ackdata = ?;", toAddress, fromAddress, subject, message, - state.send_draft_mail)) + str(state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) state.detailPageType = '' @@ -690,12 +690,12 @@ class Random(Screen): label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) - self.manager.current = 'myaddress' self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False self.parent.parent.parent.parent.ids.sc10.ids.ml.clear_widgets() self.parent.parent.parent.parent.ids.sc10.init_ui() + self.manager.current = 'myaddress' toast('New address created') @@ -752,7 +752,7 @@ class Sent(Screen): 'secondary_text': mail[2][:50] + '........' if len( mail[2]) >= 50 else ( mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', - 'lastactiontime': mail[6]}) + 'ackdata': mail[5]}) for item in data: meny = TwoLineAvatarIconListItem( text=item['text'], @@ -763,7 +763,7 @@ class Sent(Screen): source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( - self.sent_detail, item['lastactiontime'])) + self.sent_detail, item['ackdata'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -774,13 +774,13 @@ class Sent(Screen): del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( - self.delete, item['lastactiontime'])) + self.delete, item['ackdata'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) ach_btn.bind(on_press=partial( - self.archive, item['lastactiontime'])) + self.archive, item['ackdata'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) @@ -796,10 +796,10 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) - def sent_detail(self, lastsenttime, *args): + def sent_detail(self, ackdata, *args): """Load sent mail details.""" state.detailPageType = 'sent' - state.sentMailTime = lastsenttime + state.mail_id = ackdata if self.manager: src_mng_obj = self.manager else: @@ -828,7 +828,7 @@ class Sent(Screen): state.all_count = str(int(state.all_count) - 1) sqlExecute( "UPDATE sent SET folder = 'trash' \ - WHERE lastactiontime = {};".format(data_index)) + WHERE ackdata = ?;",str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') self.update_trash() @@ -837,7 +837,7 @@ class Sent(Screen): """Archive sent mail from sent mail listing.""" sqlExecute( "UPDATE sent SET folder = 'trash' \ - WHERE lastactiontime = {};".format(data_index)) + WHERE ackdata = ?;",str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -1422,8 +1422,7 @@ class MailDetail(Screen): if state.detailPageType == 'sent' or state.detailPageType == 'draft': data = sqlQuery( "select toaddress, fromaddress, subject, message, status, \ - ackdata from sent where lastactiontime = {};".format( - state.sentMailTime)) + ackdata from sent where ackdata = ?;", state.mail_id) state.status = self state.ackdata = data[0][5] self.assign_mail_details(data) @@ -1431,7 +1430,7 @@ class MailDetail(Screen): elif state.detailPageType == 'inbox': data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox \ - where received = {};".format(state.sentMailTime)) + where msgid = ?;",str(state.mail_id)) self.assign_mail_details(data) state.kivyapp.set_mail_detail_header() @@ -1455,7 +1454,7 @@ class MailDetail(Screen): if state.detailPageType == 'sent': sqlExecute( "UPDATE sent SET folder = 'trash' WHERE \ - lastactiontime = {};".format(state.sentMailTime)) + ackdata = ?;", str(state.mail_id)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) self.parent.screens[3].ids.ml.clear_widgets() @@ -1463,15 +1462,12 @@ class MailDetail(Screen): elif state.detailPageType == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ - received = {};".format(state.sentMailTime)) - # msg_count_objs.inbox_cnt.badge_text = str( - # int(state.inbox_count) - 1) - # state.inbox_count = str(int(state.inbox_count) - 1) + msgid = ?;",str(state.mail_id)) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': - sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( - state.sentMailTime)) + sqlExecute("DELETE FROM sent WHERE ackdata = ?;",str( + state.mail_id)) msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) self.parent.screens[15].clear_widgets() @@ -1494,7 +1490,7 @@ class MailDetail(Screen): """Method used for replying inbox messages.""" data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where \ - received = {};".format(state.sentMailTime)) + msgid = ?;",str(state.mail_id)) composer_obj = self.parent.screens[2].children[0].ids composer_obj.ti.text = data[0][0] composer_obj.btn.text = data[0][0] @@ -1511,7 +1507,7 @@ class MailDetail(Screen): def write_msg(self, navApp): """Method used to write on draft mail.""" - state.send_draft_mail = state.sentMailTime + state.send_draft_mail = state.mail_id composer_ids = \ self.parent.parent.parent.parent.ids.sc3.children[0].ids composer_ids.ti.text = state.write_msg['from_addr'] @@ -1662,7 +1658,7 @@ class Draft(Screen): mail[2]) > 10 else mail[2] + '\n' + " " + ( third_text[:25] + '...!') if len( third_text) > 25 else third_text, - 'lastactiontime': mail[6]}) + 'ackdata': mail[5]}) for item in self.data: meny = TwoLineAvatarIconListItem( text='Draft', @@ -1672,7 +1668,7 @@ class Draft(Screen): meny.add_widget(AvatarSampleWidget( source='./images/avatar.png')) meny.bind(on_press=partial( - self.draft_detail, item['lastactiontime'])) + self.draft_detail, item['ackdata'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -1683,7 +1679,7 @@ class Draft(Screen): del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( - self.delete_draft, item['lastactiontime'])) + self.delete_draft, item['ackdata'])) carousel.add_widget(del_btn) carousel.add_widget(meny) carousel.index = 1 @@ -1699,10 +1695,10 @@ class Draft(Screen): valign='top') self.ids.ml.add_widget(content) - def draft_detail(self, lastsenttime, *args): + def draft_detail(self, ackdata, *args): """Method used to show draft Details.""" state.detailPageType = 'draft' - state.sentMailTime = lastsenttime + state.mail_id = ackdata if self.manager: src_mng_obj = self.manager else: @@ -1713,7 +1709,7 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( + sqlExecute("DELETE FROM sent WHERE ackdata = ?;",str( data_index)) try: msg_count_objs = \ @@ -1815,11 +1811,11 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, received from\ + "SELECT toaddress, fromaddress, subject, message, folder, msgid from\ inbox WHERE folder = 'inbox' and toaddress = '{}';".format( account)) sent_and_draft = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from sent \ + "SELECT toaddress, fromaddress, subject, message, folder, ackdata from sent \ WHERE folder = 'sent' and fromaddress = '{}';".format( account)) @@ -1870,7 +1866,7 @@ class Allmails(Screen): """Load sent and inbox mail details.""" state.detailPageType = folder state.is_allmail = True - state.sentMailTime = unique_id + state.mail_id = unique_id if self.manager: src_mng_obj = self.manager else: @@ -1883,11 +1879,11 @@ class Allmails(Screen): """Delete inbox mail from all mail listing listing.""" if folder == 'inbox': sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( unique_id)) else: sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( + "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;",str( unique_id)) self.ids.ml.remove_widget(instance.parent.parent) try: diff --git a/src/state.py b/src/state.py index 07cb687a..4baf5614 100644 --- a/src/state.py +++ b/src/state.py @@ -67,7 +67,7 @@ kivyapp = None navinstance = None -sentMailTime = 0 +mail_id = 0 myAddressObj = None From a46c81ad9b13aa716037abf4b607ce3af04f7b7f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 4 Oct 2019 19:24:58 +0530 Subject: [PATCH 160/306] mpybit flake and pylint fix --- src/bitmessagekivy/mpybit.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 7fd1b661..39005727 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -178,7 +178,7 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing.""" sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) try: msg_count_objs = \ @@ -207,7 +207,7 @@ class Inbox(Screen): def archive(self, data_index, instance, *args): """Archive inbox mail from inbox listing.""" sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -469,11 +469,11 @@ class DropDownWidget(BoxLayout): , fromaddress = ? , subject = ?\ , message = ?, folder = 'sent'\ WHERE ackdata = ?;", - toAddress, - fromAddress, - subject, - message, - str(state.send_draft_mail)) + toAddress, + fromAddress, + subject, + message, + str(state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) state.detailPageType = '' @@ -828,7 +828,7 @@ class Sent(Screen): state.all_count = str(int(state.all_count) - 1) sqlExecute( "UPDATE sent SET folder = 'trash' \ - WHERE ackdata = ?;",str(data_index)) + WHERE ackdata = ?;", str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') self.update_trash() @@ -837,7 +837,7 @@ class Sent(Screen): """Archive sent mail from sent mail listing.""" sqlExecute( "UPDATE sent SET folder = 'trash' \ - WHERE ackdata = ?;",str(data_index)) + WHERE ackdata = ?;", str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -1430,7 +1430,7 @@ class MailDetail(Screen): elif state.detailPageType == 'inbox': data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox \ - where msgid = ?;",str(state.mail_id)) + where msgid = ?;", str(state.mail_id)) self.assign_mail_details(data) state.kivyapp.set_mail_detail_header() @@ -1462,11 +1462,11 @@ class MailDetail(Screen): elif state.detailPageType == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ - msgid = ?;",str(state.mail_id)) + msgid = ?;", str(state.mail_id)) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': - sqlExecute("DELETE FROM sent WHERE ackdata = ?;",str( + sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( state.mail_id)) msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) @@ -1490,7 +1490,7 @@ class MailDetail(Screen): """Method used for replying inbox messages.""" data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where \ - msgid = ?;",str(state.mail_id)) + msgid = ?;", str(state.mail_id)) composer_obj = self.parent.screens[2].children[0].ids composer_obj.ti.text = data[0][0] composer_obj.btn.text = data[0][0] @@ -1709,7 +1709,7 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute("DELETE FROM sent WHERE ackdata = ?;",str( + sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( data_index)) try: msg_count_objs = \ @@ -1724,7 +1724,6 @@ class Draft(Screen): self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') - # pylint: disable=unused-variable @staticmethod def draft_msg(src_object): """Method used for saving draft mails.""" @@ -1879,11 +1878,11 @@ class Allmails(Screen): """Delete inbox mail from all mail listing listing.""" if folder == 'inbox': sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;",str( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( unique_id)) else: sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;",str( + "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", str( unique_id)) self.ids.ml.remove_widget(instance.parent.parent) try: From 7298726ab7e029197992f77dd849577a4c58fa8c Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 9 Oct 2019 22:04:42 +0530 Subject: [PATCH 161/306] worked on android devices toast issue --- src/bitmessagekivy/main.kv | 3 +-- src/bitmessagekivy/mpybit.py | 32 +++++++++++++--------------- src/bitmessagekivy/uikivysignaler.py | 5 +++-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index be6f76e9..7e246b58 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -55,8 +55,7 @@ : drawer_logo: app.address_identicon() NavigationDrawerDivider: - - NavigationDrawerTwoLineListItem: + NavigationDrawerSubheader: text: "Accounts" NavigationDrawerIconButton: CustomSpinner: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 39005727..3e21e761 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -61,9 +61,8 @@ import identiconGeneration def toast(text): """Method will display the toast message.""" - if platform == 'linux': - from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name - toast(text) + from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name + toast(text) return @@ -379,8 +378,9 @@ class AddressBook(Screen): @staticmethod def refreshs(*args): """Refresh the Widget.""" - state.navinstance.ids.sc11.ids.ml.clear_widgets() - state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') + # state.navinstance.ids.sc11.ids.ml.clear_widgets() + # state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') + pass @staticmethod def addBook_detail(address, label, *args): @@ -1094,7 +1094,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods """Getting default image on address""" if BMConfigParser().addresses(): return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) - return '' + return './images/no_identicons.png' @staticmethod def addressexist(): @@ -1299,10 +1299,12 @@ class GrashofPopup(Popup): stored_address = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] if label and address and address not in stored_address: - state.navinstance = self.parent.children[1] + # state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + state.kivyapp.root.ids.sc11.ids.ml.clear_widgets() + state.kivyapp.root.ids.sc11.loadAddresslist(None, 'All', '') self.parent.children[1].ids.scr_mngr.current = 'addressbook' toast('Saved') @@ -1809,16 +1811,12 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" - inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, msgid from\ - inbox WHERE folder = 'inbox' and toaddress = '{}';".format( - account)) - sent_and_draft = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata from sent \ - WHERE folder = 'sent' and fromaddress = '{}';".format( - account)) - - all_mails = inbox + sent_and_draft + all_mails = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime) As actionTime \ + FROM sent \ + UNION \ + SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As actionTime \ + FROM inbox ORDER BY actionTime DESC") if all_mails: state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) state.all_count = str(len(all_mails)) diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py index 5681d25d..cb9473e2 100644 --- a/src/bitmessagekivy/uikivysignaler.py +++ b/src/bitmessagekivy/uikivysignaler.py @@ -16,8 +16,9 @@ class UIkivySignaler(Thread): if command == 'writeNewAddressToTable': label, address, streamNumber = data state.kivyapp.variable_1.append(address) - elif command == 'rerenderAddressBook': - state.kivyapp.obj_1.refreshs() + # elif command == 'rerenderAddressBook': + # state.kivyapp.obj_1.refreshs() + # Need to discuss this elif command == 'updateSentItemStatusByAckdata': state.kivyapp.status_dispatching(data) From 1960e7c8a534ba2f4e6933f368cf45644ffed4fc Mon Sep 17 00:00:00 2001 From: Navjot Date: Thu, 10 Oct 2019 21:38:52 +0530 Subject: [PATCH 162/306] resolved all mail query bug or first time address creation slow response issue --- src/bitmessagekivy/main.kv | 37 +----------------------------------- src/bitmessagekivy/mpybit.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 7e246b58..759bd71c 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,42 +1,18 @@ #:import Toolbar kivymd.toolbar.Toolbar -#:import ThemeManager kivymd.theming.ThemeManager -#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer #:import NavigationLayout kivymd.navigationdrawer.NavigationLayout #:import NavigationDrawerDivider kivymd.navigationdrawer.NavigationDrawerDivider -#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar #:import NavigationDrawerSubheader kivymd.navigationdrawer.NavigationDrawerSubheader #:import MDCheckbox kivymd.selectioncontrols.MDCheckbox -#:import MDSwitch kivymd.selectioncontrols.MDSwitch #:import MDList kivymd.list.MDList #:import OneLineListItem kivymd.list.OneLineListItem -#:import TwoLineListItem kivymd.list.TwoLineListItem -#:import ThreeLineListItem kivymd.list.ThreeLineListItem -#:import OneLineAvatarListItem kivymd.list.OneLineAvatarListItem -#:import OneLineIconListItem kivymd.list.OneLineIconListItem -#:import OneLineAvatarIconListItem kivymd.list.OneLineAvatarIconListItem #:import MDTextField kivymd.textfields.MDTextField -#:import MDSpinner kivymd.spinner.MDSpinner -#:import MDCard kivymd.card.MDCard -#:import MDSeparator kivymd.card.MDSeparator -#:import MDDropdownMenu kivymd.menu.MDDropdownMenu #:import get_color_from_hex kivy.utils.get_color_from_hex #:import colors kivymd.color_definitions.colors -#:import SmartTile kivymd.grid.SmartTile -#:import MDSlider kivymd.slider.MDSlider #:import MDTabbedPanel kivymd.tabs.MDTabbedPanel #:import MDTab kivymd.tabs.MDTab -#:import MDProgressBar kivymd.progressbar.MDProgressBar -#:import MDAccordion kivymd.accordion.MDAccordion -#:import MDAccordionItem kivymd.accordion.MDAccordionItem -#:import MDAccordionSubItem kivymd.accordion.MDAccordionSubItem -#:import MDThemePicker kivymd.theme_picker.MDThemePicker -#:import MDBottomNavigation kivymd.tabs.MDBottomNavigation -#:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory -#:import MDTextButton kivymd.button.MDTextButton -#:import FadeTransition kivy.uix.screenmanager.FadeTransition #:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout #:set color_button (0.784, 0.443, 0.216, 1) # brown @@ -142,7 +118,7 @@ on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Subscriptions/Payment" - icon:'wallet' + icon:'bell' on_release: app.root.ids.scr_mngr.current = 'payment' on_press: app.refreshScreen(self) NavigationDrawerIconButton: @@ -416,17 +392,6 @@ NavigationLayout: helper_text_mode: "on_error" BoxLayout: spacing:50 - AnchorLayout: - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.reset_composer() - MDLabel: - font_style: 'Title' - text: 'reset' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' : readonly: False diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 3e21e761..9640de8c 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -558,6 +558,7 @@ class DropDownWidget(BoxLayout): self.ids.txt_input.text = '' self.ids.subject.text = '' self.ids.body.text = '' + toast("Reset message") def auto_fill_fromaddr(self): """Mehtod used to fill the text automatically From Address.""" @@ -694,6 +695,7 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False self.parent.parent.parent.parent.ids.sc10.ids.ml.clear_widgets() + self.manager.current = 'myaddress' self.parent.parent.parent.parent.ids.sc10.init_ui() self.manager.current = 'myaddress' toast('New address created') @@ -1158,6 +1160,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods 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[0].reset_composer()], ['send', lambda x: self.root.ids.sc3.children[0].send(self)]] def back_press(self): @@ -1167,7 +1170,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.toolbar.left_action_items = \ [['menu', lambda x: self.root.toggle_nav_drawer()]] self.root.ids.scr_mngr.current = 'inbox' \ - if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType + if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType if state.detailPageType else 'inbox' 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': @@ -1465,6 +1468,8 @@ class MailDetail(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ msgid = ?;", str(state.mail_id)) + msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': @@ -1593,7 +1598,7 @@ class AddbookDetailPopup(Popup): window_obj = self.parent.children[1].ids window_obj.sc3.children[0].ids.txt_input.text = self.address window_obj.sc3.children[0].ids.ti.text = '' - window_obj.sc3.children[0].ids.btn.text = '' + window_obj.sc3.children[0].ids.btn.text = 'Select' window_obj.sc3.children[0].ids.subject.text = '' window_obj.sc3.children[0].ids.body.text = '' window_obj.scr_mngr.current = 'create' @@ -1813,10 +1818,10 @@ class Allmails(Screen): """Load Inbox, Sent anf Draft list of messages.""" all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime) As actionTime \ - FROM sent \ + FROM sent WHERE folder = 'sent'\ UNION \ SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As actionTime \ - FROM inbox ORDER BY actionTime DESC") + FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") if all_mails: state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) state.all_count = str(len(all_mails)) From 0bcaf8806ea22f1900c8165cc2575643e5963d49 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 11 Oct 2019 14:44:32 +0530 Subject: [PATCH 163/306] fixes after pull --- src/bitmessagekivy/mpybit.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 9640de8c..99578149 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1170,7 +1170,9 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.toolbar.left_action_items = \ [['menu', lambda x: self.root.toggle_nav_drawer()]] self.root.ids.scr_mngr.current = 'inbox' \ - if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType if state.detailPageType else 'inbox' + if state.in_composer else 'allmails'\ + if state.is_allmail else state.detailPageType\ + if state.detailPageType else 'inbox' 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': @@ -1817,11 +1819,10 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" all_mails = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime) As actionTime \ - FROM sent WHERE folder = 'sent'\ - UNION \ - SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As actionTime \ - FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") + "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime)" + " As actionTime FROM sent WHERE folder = 'sent' UNION" + " SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As" + " actionTime FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") if all_mails: state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) state.all_count = str(len(all_mails)) From a2a1f3f0b5eff03f32ea17e9d87d0490c79489c4 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 11 Oct 2019 16:41:48 +0530 Subject: [PATCH 164/306] Quality issues fixed --- src/paths.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/paths.py b/src/paths.py index b203680a..92c49a85 100644 --- a/src/paths.py +++ b/src/paths.py @@ -46,7 +46,7 @@ def lookupAppdataFolder(): dataFolder = os.path.join( os.environ['HOME'], 'Library/Application Support/', APPNAME - ) + '/' # FIXME: should also be os.path.sep + ) + '/' # ..fixme:: should also be os.path.sep except KeyError: sys.exit( 'Could not find home folder, please report this message' @@ -78,6 +78,7 @@ def lookupAppdataFolder(): def codePath(): """Returns path to the program sources""" + # pylint: disable=protected-access if not frozen: return os.path.dirname(__file__) return ( @@ -85,7 +86,6 @@ def codePath(): if frozen == "macosx_app" else sys._MEIPASS) - def tail(f, lines=20): """Returns last lines in the f file object""" total_lines_wanted = lines @@ -132,4 +132,4 @@ def lastCommit(): ) except (IOError, AttributeError, TypeError): pass - return result \ No newline at end of file + return result From 20ba0a2efcea49cbf6222e8db363b36d4ce764ff Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 15 Oct 2019 18:42:23 +0530 Subject: [PATCH 165/306] query and quality fixes mpybit --- src/bitmessagekivy/mpybit.py | 145 ++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 99578149..7270514b 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -19,7 +19,8 @@ from kivy.properties import ( ListProperty, NumericProperty, ObjectProperty, - StringProperty) + StringProperty +) from kivy.uix.behaviors import FocusBehavior from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button @@ -44,10 +45,12 @@ from kivymd.list import ( ILeftBodyTouch, IRightBodyTouch, TwoLineAvatarIconListItem, - TwoLineListItem) + TwoLineListItem +) from kivymd.navigationdrawer import ( MDNavigationDrawer, - NavigationDrawerHeaderBase) + NavigationDrawerHeaderBase +) from kivymd.selectioncontrols import MDCheckbox from kivymd.theming import ThemeManager import queues @@ -61,7 +64,8 @@ import identiconGeneration def toast(text): """Method will display the toast message.""" - from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name + # pylint: disable=redefined-outer-name + from kivymd.toast.kivytoast import toast toast(text) return @@ -180,11 +184,9 @@ class Inbox(Screen): "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) try: - msg_count_objs = \ - self.parent.parent.parent.parent.children[2].children[0].ids - except Exception as e: - msg_count_objs = \ - self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + except Exception: + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.inbox_count) > 0: msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) @@ -436,20 +438,21 @@ class SelectableLabel(RecycleDataViewBehavior, Label): class RV(RecycleView): """Recycling View.""" - def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): """Recycling Method.""" + # pylint: disable=useless-super-delegation super(RV, self).__init__(**kwargs) class DropDownWidget(BoxLayout): """Adding Dropdown Widget.""" + # pylint: disable=too-many-statements, inconsistent-return-statements, too-many-locals txt_input = ObjectProperty() rv = ObjectProperty() - def send(self, navApp): # pylint: disable=too-many-statements, inconsistent-return-statements + def send(self, navApp): """Send message from one address to another.""" - # pylint: disable=too-many-locals fromAddress = str(self.ids.ti.text) toAddress = str(self.ids.txt_input.text) subject = self.ids.subject.text.encode('utf-8').strip() @@ -460,15 +463,14 @@ class DropDownWidget(BoxLayout): if sendMessageToPeople: if toAddress != '' and subject and message: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = \ - decodeAddress(toAddress) + status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) if status == 'success': if state.detailPageType == 'draft' and state.send_draft_mail: sqlExecute( - "UPDATE sent SET toaddress = ? \ - , fromaddress = ? , subject = ?\ - , message = ?, folder = 'sent'\ - WHERE ackdata = ?;", + "UPDATE sent SET toaddress = ?" + ", fromaddress = ? , subject = ?" + ", message = ?, folder = 'sent'" + " WHERE ackdata = ?;", toAddress, fromAddress, subject, @@ -575,8 +577,9 @@ class MyTextInput(TextInput): starting_no = NumericProperty(3) suggestion_text = '' - def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): """Getting Text Input.""" + # pylint: disable=useless-super-delegation super(MyTextInput, self).__init__(**kwargs) def on_text(self, instance, value): @@ -606,8 +609,9 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" - def get_available_credits(self, instance): # pylint: disable=no-self-use + def get_available_credits(self, instance): """Method helps to get the available credits""" + # pylint: disable=no-self-use state.availabe_credit = instance.parent.children[1].text existing_credits = state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text if len(existing_credits.split(' ')) > 1: @@ -736,8 +740,7 @@ class Sent(Screen): data = [] queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - if state.msg_counter_objs and state.association == \ - state.check_sent_acc: + if state.msg_counter_objs and state.association == state.check_sent_acc: state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(int(state.sent_count) + 1) state.all_count = str(int(state.all_count) + 1) @@ -829,8 +832,8 @@ class Sent(Screen): state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) sqlExecute( - "UPDATE sent SET folder = 'trash' \ - WHERE ackdata = ?;", str(data_index)) + "UPDATE sent SET folder = 'trash'" + " WHERE ackdata = ?;", str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') self.update_trash() @@ -838,8 +841,8 @@ class Sent(Screen): def archive(self, data_index, instance, *args): """Archive sent mail from sent mail listing.""" sqlExecute( - "UPDATE sent SET folder = 'trash' \ - WHERE ackdata = ?;", str(data_index)) + "UPDATE sent SET folder = 'trash'" + " WHERE ackdata = ?;", str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -870,14 +873,13 @@ class Trash(Screen): if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, received from \ - inbox WHERE folder = 'trash' and toaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder, received from" + " inbox WHERE folder = 'trash' and toaddress = '{}';".format( state.association)) sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from \ - sent WHERE folder = 'trash' and fromaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from" + " sent WHERE folder = 'trash' and fromaddress = '{}';".format( state.association)) trash_data = inbox + sent @@ -954,8 +956,9 @@ class Setting(Screen): pass -class NavigateApp(App): # pylint: disable=too-many-public-methods +class NavigateApp(App): """Navigation Layout of class.""" + # pylint: disable=too-many-public-methods theme_cls = ThemeManager() previous_date = ObjectProperty() @@ -1026,25 +1029,24 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc1.ids.ml.clear_widgets() self.root.ids.sc1.loadMessagelist(state.association) self.root.ids.scr_mngr.current = 'inbox' - - msg_counter_objs = \ - self.root_window.children[1].children[2].children[0].ids + msg_counter_objs = self.root_window.children[1].children[2].children[0].ids state.sent_count = str( sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and \ - folder = 'sent' ;".format(state.association))[0][0]) + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'sent' ;".format(state.association))[0][0]) state.inbox_count = str( sqlQuery( - "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and \ - folder = 'inbox' ;".format(state.association))[0][0]) - state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent \ - where fromaddress = '{0}' and folder = 'trash' ) \ - +(SELECT count(*) FROM inbox where toaddress = '{0}' and \ - folder = 'trash') AS SumCount".format(state.association))[0][0]) + "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" + " folder = 'inbox' ;".format(state.association))[0][0]) + state.trash_count = str(sqlQuery( + "SELECT (SELECT count(*) FROM sent" + " where fromaddress = '{0}' and folder = 'trash' )" + "+(SELECT count(*) FROM inbox where toaddress = '{0}' and" + " folder = 'trash') AS SumCount".format(state.association))[0][0]) state.draft_count = str( sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and \ - folder = 'draft' ;".format(state.association))[0][0]) + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'draft' ;".format(state.association))[0][0]) state.all_count = str(int(state.sent_count) + int(state.inbox_count)) if msg_counter_objs: @@ -1165,10 +1167,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def back_press(self): """Method used for going back from composer to previous page.""" - 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.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.scr_mngr.current = 'inbox' \ if state.in_composer else 'allmails'\ if state.is_allmail else state.detailPageType\ @@ -1232,7 +1232,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc1.ids.ml.clear_widgets() try: self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' - except Exception as e: + except Exception: self.root.ids.sc1.children[1].children[1].ids.search_field.text = '' self.root.ids.sc1.loadMessagelist(state.association) elif instance.text == 'Draft': @@ -1252,7 +1252,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc10.ids.ml.clear_widgets() try: self.root.ids.sc10.children[1].children[1].ids.search_field.text = '' - except Exception as e: + except Exception: self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' self.root.ids.sc10.init_ui() return @@ -1285,8 +1285,9 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" - def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): """Grash of pop screen settings.""" + # pylint: disable=useless-super-delegation super(GrashofPopup, self).__init__(**kwargs) def savecontact(self): @@ -1428,16 +1429,16 @@ class MailDetail(Screen): self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent' or state.detailPageType == 'draft': data = sqlQuery( - "select toaddress, fromaddress, subject, message, status, \ - ackdata from sent where ackdata = ?;", state.mail_id) + "select toaddress, fromaddress, subject, message, status," + " ackdata from sent where ackdata = ?;", state.mail_id) state.status = self state.ackdata = data[0][5] self.assign_mail_details(data) state.kivyapp.set_mail_detail_header() elif state.detailPageType == 'inbox': data = sqlQuery( - "select toaddress, fromaddress, subject, message from inbox \ - where msgid = ?;", str(state.mail_id)) + "select toaddress, fromaddress, subject, message from inbox" + " where msgid = ?;", str(state.mail_id)) self.assign_mail_details(data) state.kivyapp.set_mail_detail_header() @@ -1460,16 +1461,16 @@ class MailDetail(Screen): msg_count_objs = state.kivyapp.root.children[2].children[0].ids if state.detailPageType == 'sent': sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE \ - ackdata = ?;", str(state.mail_id)) + "UPDATE sent SET folder = 'trash' WHERE" + " ackdata = ?;", str(state.mail_id)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) self.parent.screens[3].ids.ml.clear_widgets() self.parent.screens[3].loadSent(state.association) elif state.detailPageType == 'inbox': sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE \ - msgid = ?;", str(state.mail_id)) + "UPDATE inbox SET folder = 'trash' WHERE" + " msgid = ?;", str(state.mail_id)) msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].ids.ml.clear_widgets() @@ -1498,8 +1499,8 @@ class MailDetail(Screen): def inbox_reply(self): """Method used for replying inbox messages.""" data = sqlQuery( - "select toaddress, fromaddress, subject, message from inbox where \ - msgid = ?;", str(state.mail_id)) + "select toaddress, fromaddress, subject, message from inbox where" + " msgid = ?;", str(state.mail_id)) composer_obj = self.parent.screens[2].children[0].ids composer_obj.ti.text = data[0][0] composer_obj.btn.text = data[0][0] @@ -1517,8 +1518,7 @@ class MailDetail(Screen): def write_msg(self, navApp): """Method used to write on draft mail.""" state.send_draft_mail = state.mail_id - composer_ids = \ - self.parent.parent.parent.parent.ids.sc3.children[0].ids + composer_ids = self.parent.parent.parent.parent.ids.sc3.children[0].ids composer_ids.ti.text = state.write_msg['from_addr'] composer_ids.btn.text = state.write_msg['from_addr'] composer_ids.txt_input.text = state.write_msg['to_addr'] @@ -1544,8 +1544,9 @@ class MyaddDetailPopup(Popup): address_label = StringProperty() address = StringProperty() - def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): """My Address Details screen setting.""" + # pylint: disable=useless-super-delegation super(MyaddDetailPopup, self).__init__(**kwargs) def set_address(self, address, label): @@ -1576,8 +1577,9 @@ class AddbookDetailPopup(Popup): address_label = StringProperty() address = StringProperty() - def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): """Method used set screen of address detail page.""" + # pylint: disable=useless-super-delegation super(AddbookDetailPopup, self).__init__(**kwargs) def set_addbook_data(self, address, label): @@ -1588,8 +1590,9 @@ class AddbookDetailPopup(Popup): def update_addbook_label(self, address): """Updating the label of address book address.""" if str(self.ids.add_label.text): - sqlExecute("UPDATE addressbook SET label = '{}' WHERE \ - address = '{}';".format(str(self.ids.add_label.text), address)) + sqlExecute( + "UPDATE addressbook SET label = '{}' WHERE" + " address = '{}';".format(str(self.ids.add_label.text), address)) self.parent.children[1].ids.sc11.ids.ml.clear_widgets() self.parent.children[1].ids.sc11.loadAddresslist(None, 'All', '') self.dismiss() @@ -1721,8 +1724,7 @@ class Draft(Screen): sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( data_index)) try: - msg_count_objs = \ - self.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids @@ -1747,8 +1749,7 @@ class Draft(Screen): sendMessageToPeople = True if sendMessageToPeople: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = \ - decodeAddress(toAddress) + status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' From 69a7dc594aa8d080deb1f7d13107002638d6714c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 3 Oct 2019 12:13:02 +0300 Subject: [PATCH 166/306] Ignore deprecated flake8 W503 --- setup.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 3236eed1..a4e0547c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,14 +1,17 @@ # Since there is overlap in the violations that the different tools check for, it makes sense to quiesce some warnings # in some tools if those warnings in other tools are preferred. This avoids the need to add duplicate lint warnings. +# max-line-length should be removed ASAP! + [pycodestyle] max-line-length = 119 [flake8] max-line-length = 119 -ignore = E722,F841 +ignore = E722,F841,W503 # E722: pylint is preferred for bare-except # F841: pylint is preferred for unused-variable +# W503: deprecated: https://bugs.python.org/issue26763 - https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator # pylint honours the [MESSAGES CONTROL] section # as well as [MASTER] section From 5cf8ef06cc5262c68c7d2ae00f5b25b23ab69ed8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 16 Oct 2019 15:07:39 +0300 Subject: [PATCH 167/306] A symlink for famous setuptools bug https://bitbucket.org/tarek/distribute/issues/177 --- pybitmessage | 1 + 1 file changed, 1 insertion(+) create mode 120000 pybitmessage diff --git a/pybitmessage b/pybitmessage new file mode 120000 index 00000000..e8310385 --- /dev/null +++ b/pybitmessage @@ -0,0 +1 @@ +src \ No newline at end of file From c99997dbb9f0ebe1352357bb5b40ed52e66d8b3f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 12 Oct 2019 17:12:19 +0300 Subject: [PATCH 168/306] Fix mistakes in Exception() instantiation --- src/class_smtpServer.py | 11 ++++++----- src/namecoin.py | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index d87ab69b..99d9c4b3 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -21,6 +21,7 @@ from version import softwareVersion SMTPDOMAIN = "bmaddr.lan" LISTENPORT = 8425 + class smtpServerChannel(smtpd.SMTPChannel): def smtp_EHLO(self, arg): if not arg: @@ -113,9 +114,9 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): try: sender, domain = p.sub(r'\1', mailfrom).split("@") if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) + raise Exception("Bad domain %s" % domain) if sender not in BMConfigParser().addresses(): - raise Exception("Nonexisting user %s", sender) + raise Exception("Nonexisting user %s" % sender) except Exception as err: logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) msg_from = self.decode_header("from") @@ -123,9 +124,9 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): msg_from = p.sub(r'\1', self.decode_header("from")[0]) sender, domain = msg_from.split("@") if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) + raise Exception("Bad domain %s" % domain) if sender not in BMConfigParser().addresses(): - raise Exception("Nonexisting user %s", sender) + raise Exception("Nonexisting user %s" % sender) except Exception as err: logger.error("Bad headers from %s: %s", msg_from, repr(err)) return @@ -145,7 +146,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): try: rcpt, domain = p.sub(r'\1', to).split("@") if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) + raise Exception("Bad domain %s" % domain) logger.debug("Sending %s to %s about %s", sender, rcpt, msg_subject) self.send(sender, rcpt, msg_subject, body) logger.info("Relayed %s to %s", sender, rcpt) diff --git a/src/namecoin.py b/src/namecoin.py index 6674bdcd..579fb0ab 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -258,7 +258,7 @@ class namecoinConnection(object): resp = self.con.getresponse() result = resp.read() if resp.status != 200: - raise Exception("Namecoin returned status %i: %s" % resp.status, resp.reason) + raise Exception("Namecoin returned status %i: %s" % (resp.status, resp.reason)) except: logger.info("HTTP receive error") except: @@ -288,7 +288,7 @@ class namecoinConnection(object): return result except socket.error as exc: - raise Exception("Socket error in RPC connection: %s" % str(exc)) + raise Exception("Socket error in RPC connection: %s" % exc) def lookupNamecoinFolder(): From 9a3a5ec9e8886ae3163ded9059526c69b544acd2 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 9 Oct 2019 11:46:47 +0300 Subject: [PATCH 169/306] Adjusted conf and rst to fix modindex and get informative index --- docs/conf.py | 114 ++++++++++++++----- docs/contribute.dir/develop.dir/fabric.rst | 2 +- docs/contribute.dir/develop.dir/overview.rst | 2 +- docs/index.rst | 12 +- 4 files changed, 98 insertions(+), 32 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a4dae7c7..96c9f146 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,35 +2,24 @@ """ Configuration file for the Sphinx documentation builder. -This file does only contain a selection of the most common options. For a -full list see the documentation: +For a full list of options see the documentation: http://www.sphinx-doc.org/en/master/config - --- Path setup -------------------------------------------------------------- - -If extensions (or modules to document with autodoc) are in another directory, -add these directories to sys.path here. If the directory is relative to the -documentation root, use os.path.abspath to make it absolute, like shown here. """ import os import sys -from sphinx.apidoc import main -from mock import Mock as MagicMock - -sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('../src')) -sys.path.insert(0, os.path.abspath('../src/pyelliptic')) -import version +from importlib import import_module + +import version # noqa:E402 # -- Project information ----------------------------------------------------- project = u'PyBitmessage' -copyright = u'2018, The Bitmessage Team' # pylint: disable=redefined-builtin +copyright = u'2019, The Bitmessage Team' # pylint: disable=redefined-builtin author = u'The Bitmessage Team' # The short X.Y version @@ -50,12 +39,13 @@ release = version # ones. extensions = [ 'sphinx.ext.autodoc', - # 'sphinx.ext.doctest', # Currently disabled due to bad doctests + 'sphinx.ext.coverage', # FIXME: unused + 'sphinx.ext.imgmath', # legacy unused 'sphinx.ext.intersphinx', + 'sphinx.ext.linkcode', + 'sphinx.ext.napoleon', 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.imgmath', - 'sphinx.ext.viewcode', + 'sphinxcontrib.apidoc', 'm2r', ] @@ -75,23 +65,29 @@ master_doc = 'index' # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +# language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' +# Don't prepend every class or function name with full module path +add_module_names = False + +# A list of ignored prefixes for module index sorting. +modindex_common_prefix = ['pybitmessage.'] + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -114,10 +110,7 @@ html_static_path = ['_static'] # # html_sidebars = {} -# Deal with long lines in source view -html_theme_options = { - 'page_width': '1366px', -} +html_show_sourcelink = False # -- Options for HTMLHelp output --------------------------------------------- @@ -199,10 +192,75 @@ epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- +autodoc_mock_imports = [ + 'debug', + 'pybitmessage.bitmessagekivy', + 'pybitmessage.bitmessagemain', + 'pybitmessage.bitmessageqt.addressvalidator', + 'pybitmessage.helper_startup', + 'pybitmessage.network.httpd', + 'pybitmessage.network.https', + 'ctypes', + 'dialog', + 'gi', + 'kivy', + 'logging', + 'msgpack', + 'numpy', + 'pkg_resources', + 'pycanberra', + 'pyopencl', + 'PyQt4', + 'pyxdg', + 'qrcode', + 'stem', +] + +# Apidoc settings +apidoc_module_dir = '../pybitmessage' +apidoc_output_dir = 'autodoc' +apidoc_excluded_paths = [ + 'bitmessagekivy', 'bitmessagemain.py', 'build_osx.py', + 'bitmessageqt/addressvalidator.py', 'bitmessageqt/migrationwizard.py', + 'bitmessageqt/newaddresswizard.py', + 'class_objectProcessor.py', 'defaults.py', 'helper_startup.py', + 'kivymd', 'main.py', 'navigationdrawer', 'network/http*', + 'pybitmessage', 'queues.py', 'tests', 'version.py' +] +apidoc_module_first = True +apidoc_separate_modules = True +apidoc_toc_file = False +apidoc_extra_args = ['-a'] + +# Napoleon settings +napoleon_google_docstring = True + + +# linkcode function +def linkcode_resolve(domain, info): + """This generates source URL's for sphinx.ext.linkcode""" + if domain != 'py' or not info['module']: + return + try: + home = os.path.abspath(import_module('pybitmessage').__path__[0]) + mod = import_module(info['module']).__file__ + except ImportError: + return + repo = 'https://github.com/Bitmessage/PyBitmessage/blob/v0.6/src%s' + path = mod.replace(home, '') + if path != mod: + # put the link only for top level definitions + if len(info['fullname'].split('.')) > 1: + return + if path.endswith('.pyc'): + path = path[:-1] + return repo % path + + # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = {'https://docs.python.org/2.7/': None} # -- Options for todo extension ---------------------------------------------- diff --git a/docs/contribute.dir/develop.dir/fabric.rst b/docs/contribute.dir/develop.dir/fabric.rst index 434ccf7b..8003f33a 100644 --- a/docs/contribute.dir/develop.dir/fabric.rst +++ b/docs/contribute.dir/develop.dir/fabric.rst @@ -1,2 +1,2 @@ -.. mdinclude:: fabfile/README.md +.. mdinclude:: ../../../fabfile/README.md diff --git a/docs/contribute.dir/develop.dir/overview.rst b/docs/contribute.dir/develop.dir/overview.rst index e83d884b..342c9dbb 100644 --- a/docs/contribute.dir/develop.dir/overview.rst +++ b/docs/contribute.dir/develop.dir/overview.rst @@ -62,7 +62,7 @@ To re-build them, run `fab build_docs:dep_graphs=true`. Note that the dot graph .. figure:: ../../../../_static/deps-sfdp.png :alt: SFDP graph of dependencies :width: 100 pc - + :index:`SFDP` graph of dependencies .. figure:: ../../../../_static/deps-dot.png diff --git a/docs/index.rst b/docs/index.rst index 9dddfa28..cc8c9523 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,12 +1,20 @@ .. mdinclude:: ../README.md +Documentation +------------- +.. toctree:: + :maxdepth: 3 + + autodoc/pybitmessage + +Legacy pages +------------ .. toctree:: :maxdepth: 2 - overview usage contribute - + Indices and tables ------------------ From d412e8341b5adf640b98bfa932c56d0c2f476864 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 9 Oct 2019 11:12:21 +0300 Subject: [PATCH 170/306] Create requirements.txt for readthedocs --- docs/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..55219ec5 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +m2r +sphinxcontrib-apidoc From b5df2421417e4460f3ef6791316616d25454ce0f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 10 Oct 2019 16:38:13 +0300 Subject: [PATCH 171/306] Fixed badly formatted docstrings and some wrong text --- src/api.py | 6 +----- src/class_singleCleaner.py | 17 ++++++++-------- src/highlevelcrypto.py | 6 +++--- src/namecoin.py | 41 ++++++++++++++++++-------------------- src/network/bmobject.py | 4 +--- src/protocol.py | 10 +++------- src/pyelliptic/__init__.py | 13 +++++++----- src/pyelliptic/hash.py | 5 +---- src/pyelliptic/openssl.py | 10 ++++------ 9 files changed, 49 insertions(+), 63 deletions(-) diff --git a/src/api.py b/src/api.py index fad5d623..f92abeb4 100644 --- a/src/api.py +++ b/src/api.py @@ -1,19 +1,15 @@ # pylint: disable=too-many-locals,too-many-lines,no-self-use,too-many-public-methods,too-many-branches # pylint: disable=too-many-statements -""" -src/api.py -========== # Copyright (c) 2012-2016 Jonathan Warren # Copyright (c) 2012-2019 The Bitmessage developers +""" This is not what you run to run the Bitmessage API. Instead, enable the API ( https://bitmessage.org/wiki/API ) and optionally enable daemon mode ( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py. """ -from __future__ import absolute_import - import base64 import errno import hashlib diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index a5938716..49e15f49 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -2,19 +2,20 @@ The singleCleaner class is a timer-driven thread that cleans data structures to free memory, resends messages when a remote node doesn't respond, and sends pong messages to keep connections alive if the network isn't busy. + It cleans these data structures in memory: -inventory (moves data to the on-disk sql database) -inventorySets (clears then reloads data out of sql database) + - inventory (moves data to the on-disk sql database) + - inventorySets (clears then reloads data out of sql database) It cleans these tables on the disk: -inventory (clears expired objects) -pubkeys (clears pubkeys older than 4 weeks old which we have not used - personally) -knownNodes (clears addresses which have not been online for over 3 days) + - inventory (clears expired objects) + - pubkeys (clears pubkeys older than 4 weeks old which we have not used + personally) + - knownNodes (clears addresses which have not been online for over 3 days) It resends messages when there has been no response: -resends getpubkey messages in 5 days (then 10 days, then 20 days, etc...) -resends msg messages in 5 days (then 10 days, then 20 days, etc...) + - resends getpubkey messages in 5 days (then 10 days, then 20 days, etc...) + - resends msg messages in 5 days (then 10 days, then 20 days, etc...) """ diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 02fb85ab..3d894ae8 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -100,9 +100,9 @@ def pointMult(secret): Evidently, this type of error can occur very rarely: - File "highlevelcrypto.py", line 54, in pointMult - group = OpenSSL.EC_KEY_get0_group(k) - WindowsError: exception: access violation reading 0x0000000000000008 + >>> File "highlevelcrypto.py", line 54, in pointMult + >>> group = OpenSSL.EC_KEY_get0_group(k) + >>> WindowsError: exception: access violation reading 0x0000000000000008 """ while True: try: diff --git a/src/namecoin.py b/src/namecoin.py index 579fb0ab..c9238f63 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -1,31 +1,28 @@ # pylint: disable=too-many-branches,protected-access """ Copyright (C) 2013 by Daniel Kraft -This file is part of the Bitmessage project. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -.. todo:: from debug import logger crashes PyBitmessage due to a circular dependency. The debug module will also -override/disable logging.getLogger() # loggers so module level logging functions are used instead +Namecoin queries """ +# This file is part of the Bitmessage project. -from __future__ import absolute_import +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. import base64 import httplib diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 0a4c12b7..e19eaac9 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -1,7 +1,5 @@ """ -src/network/bmobject.py -====================== - +BMObject and it's exceptions. """ import time diff --git a/src/protocol.py b/src/protocol.py index 1031b950..ef101a72 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,13 +1,8 @@ # pylint: disable=too-many-boolean-expressions,too-many-return-statements,too-many-locals,too-many-statements """ -protocol.py -=========== - Low-level protocol-related functions. """ -from __future__ import absolute_import - import base64 import hashlib import random @@ -205,12 +200,13 @@ def isProofOfWorkSufficient(data, recvTime=0): """ Validate an object's Proof of Work using method described in: - https://bitmessage.org/wiki/Proof_of_work + https://bitmessage.org/wiki/Proof_of_work + Arguments: int nonceTrialsPerByte (default: from default.py) int payloadLengthExtraBytes (default: from default.py) float recvTime (optional) UNIX epoch time when object was - received from the network (default: current system time) + received from the network (default: current system time) Returns: True if PoW valid and sufficient, False in all other cases """ diff --git a/src/pyelliptic/__init__.py b/src/pyelliptic/__init__.py index 7aa666e0..65279ded 100644 --- a/src/pyelliptic/__init__.py +++ b/src/pyelliptic/__init__.py @@ -1,10 +1,13 @@ """ -src/pyelliptic/__init__.py -===================================== +Copyright (C) 2010 +Author: Yann GUIBET +Contact: + +Python OpenSSL wrapper. +For modern cryptography with ECC, AES, HMAC, Blowfish, ... + +This is an abandoned package maintained inside of the PyBitmessage. """ -# Copyright (C) 2010 -# Author: Yann GUIBET -# Contact: from .openssl import OpenSSL from .ecc import ECC diff --git a/src/pyelliptic/hash.py b/src/pyelliptic/hash.py index c21dd6a4..f098d631 100644 --- a/src/pyelliptic/hash.py +++ b/src/pyelliptic/hash.py @@ -1,8 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- """ -src/pyelliptic/hash.py -===================== +Wrappers for hash functions from OpenSSL. """ # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index fcde01ec..152a780c 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -1,14 +1,12 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -src/pyelliptic/openssl.py -===================== -""" # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. # # Software slightly changed by Jonathan Warren # pylint: disable=protected-access +""" +This module loads openssl libs with ctypes and incapsulates +needed openssl functionality in class _OpenSSL. +""" import sys import ctypes From 4d15c8e590309a0c009ca6a2c8b763e9ef0e526b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 13 Oct 2019 13:10:06 +0300 Subject: [PATCH 172/306] Fix fallback package docstring --- src/fallback/__init__.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/fallback/__init__.py b/src/fallback/__init__.py index d45c754d..9a8d646f 100644 --- a/src/fallback/__init__.py +++ b/src/fallback/__init__.py @@ -1,13 +1,19 @@ """ -.. todo:: hello world +Fallback expressions help PyBitmessage modules to run without some external +dependencies. + + +RIPEMD160Hash +------------- + +We need to check :mod:`hashlib` for RIPEMD-160, as it won't be available +if OpenSSL is not linked against or the linked OpenSSL has RIPEMD disabled. +Try to use `pycryptodome `_ +in that case. """ import hashlib -# We need to check hashlib for RIPEMD-160, as it won't be available -# if OpenSSL is not linked against or the linked OpenSSL has RIPEMD -# disabled. - try: hashlib.new('ripemd160') except ValueError: From 53cc08edec9d092c525537f873d0fb05b25c79b8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 10 Oct 2019 17:31:02 +0300 Subject: [PATCH 173/306] Renamed invalid python module http-old --- src/network/{http-old.py => http_old.py} | 4 ---- 1 file changed, 4 deletions(-) rename src/network/{http-old.py => http_old.py} (96%) diff --git a/src/network/http-old.py b/src/network/http_old.py similarity index 96% rename from src/network/http-old.py rename to src/network/http_old.py index c97927d9..64d09983 100644 --- a/src/network/http-old.py +++ b/src/network/http_old.py @@ -1,7 +1,3 @@ -""" -src/network/http-old.py -======================= -""" import asyncore import socket import time From 9e72e3b2afa858dbca3e50535f88110f65d8f16b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 11 Oct 2019 14:14:08 +0300 Subject: [PATCH 174/306] Rewritten epytext strings in qidenticon and removed __all__ --- src/qidenticon.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/qidenticon.py b/src/qidenticon.py index 8db8430a..deafc570 100644 --- a/src/qidenticon.py +++ b/src/qidenticon.py @@ -1,23 +1,19 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- # pylint: disable=too-many-locals,too-many-arguments,too-many-function-args """ -= usage = +Usage +----- -== python == >>> import qtidenticon >>> qtidenticon.render_identicon(code, size) Return a PIL Image class instance which have generated identicon image. -```size``` specifies `patch size`. Generated image size is 3 * ```size```. +``size`` specifies `patch size`. Generated image size is 3 * ``size``. """ from PyQt4 import QtGui from PyQt4.QtCore import QSize, QPointF, Qt from PyQt4.QtGui import QPixmap, QPainter, QPolygonF -__all__ = ['render_identicon', 'IdenticonRendererBase'] - class IdenticonRendererBase(object): """Encapsulate methods around rendering identicons""" @@ -26,7 +22,7 @@ class IdenticonRendererBase(object): def __init__(self, code): """ - @param code code for icon + :param code: code for icon """ if not isinstance(code, int): code = int(code) @@ -36,8 +32,8 @@ class IdenticonRendererBase(object): """ render identicon to QPicture - @param size identicon patchsize. (image size is 3 * [size]) - @return QPicture + :param size: identicon patchsize. (image size is 3 * [size]) + :returns: :class:`QPicture` """ # decode the code @@ -79,7 +75,7 @@ class IdenticonRendererBase(object): def drawPatchQt(self, pos, turn, invert, patch_type, image, size, foreColor, backColor, penwidth): # pylint: disable=unused-argument """ - @param size patch size + :param size: patch size """ path = self.PATH_SET[patch_type] if not path: @@ -134,7 +130,7 @@ class IdenticonRendererBase(object): class DonRenderer(IdenticonRendererBase): """ Don Park's implementation of identicon - see : http://www.docuverse.com/blog/donpark/2007/01/19/identicon-updated-and-source-released + see: http://www.docuverse.com/blog/donpark/2007/01/19/identicon-updated-and-source-released """ PATH_SET = [ From 7ba296a6fe6c6eef601de6a2725b917d076cfe23 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 11 Oct 2019 17:15:26 +0300 Subject: [PATCH 175/306] Remove "Edit on Github" link: https://github.com/sphinx-doc/sphinx/issues/2386 --- docs/_static/custom.css | 4 ++++ docs/conf.py | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 docs/_static/custom.css diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..5192985c --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,4 @@ +/* Hide "On GitHub" section from versions menu */ +li.wy-breadcrumbs-aside > a.fa { + display: none; +} diff --git a/docs/conf.py b/docs/conf.py index 96c9f146..b6e75cc1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -100,6 +100,10 @@ html_theme = 'sphinx_rtd_theme' # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +html_css_files = [ + 'custom.css', +] + # Custom sidebar templates, must be a dictionary that maps document names # to template names. # From 86932617bd50d8b46070845d366093af53e2a242 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 11 Oct 2019 18:50:35 +0300 Subject: [PATCH 176/306] Add setuptools sphinx integration --- .gitignore | 1 + setup.py | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 2bcb5340..701bb079 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ dist *.egg-info docs/_*/* docs/autodoc/ +build/sphinx/ pyan/ diff --git a/setup.py b/setup.py index 61afa91e..3e585b6b 100644 --- a/setup.py +++ b/setup.py @@ -17,13 +17,7 @@ EXTRAS_REQUIRE = { 'qrcode': ['qrcode'], 'sound;platform_system=="Windows"': ['winsound'], 'tor': ['stem'], - 'docs': [ - 'sphinx', # fab build_docs - 'graphviz', # fab build_docs - 'curses', # src/depends.py - 'python2-pythondialog', # src/depends.py - 'm2r', # fab build_docs - ] + 'docs': ['sphinx', 'sphinxcontrib-apidoc', 'm2r'] } @@ -155,5 +149,9 @@ if __name__ == "__main__": # ] }, scripts=['src/pybitmessage'], - cmdclass={'install': InstallCmd} + cmdclass={'install': InstallCmd}, + command_options={ + 'build_sphinx': { + 'source_dir': ('setup.py', 'docs')} + } ) From 5cf4d8a946db2095156f8653b69e7b06beabbee9 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 15 Oct 2019 15:01:43 +0300 Subject: [PATCH 177/306] Update README --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c3dcb540..17049e7a 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,10 @@ Development ---------- Bitmessage is a collaborative project. You are welcome to submit pull requests although if you plan to put a non-trivial amount of work into coding new -features, it is recommended that you first solicit feedback on the DevTalk -pseudo-mailing list: -BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh +features, it is recommended that you first describe your ideas in the +separate issue. -Feel welcome to join chan "bitmessage", BM-2cWy7cvHoq3f1rYMerRJp8PT653jjSuEdY -which is on preview here: https://beamstat.com/chan/bitmessage +Feel welcome to join chan "bitmessage", BM-2cWy7cvHoq3f1rYMerRJp8PT653jjSuEdY References ---------- From 86f0860cb21770e15791c615bf2a566be7e72db3 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 16 Oct 2019 14:42:16 +0300 Subject: [PATCH 178/306] Slightly rewritten docstrings in singleinstance --- src/singleinstance.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index c2def912..03bda504 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -1,8 +1,13 @@ -#! /usr/bin/env python +""" +This is based upon the singleton class from +`tendo `_ +which is under the Python Software Foundation License version 2 +""" import atexit import os import sys + import state try: @@ -15,10 +20,6 @@ class singleinstance: """ Implements a single instance application by creating a lock file at appdata. - - This is based upon the singleton class from tendo - https://github.com/pycontribs/tendo - which is under the Python Software Foundation License version 2 """ def __init__(self, flavor_id="", daemon=False): self.initialized = False From c63ed02153869aeefb35502df8e60c29dba68b2f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 16 Oct 2019 17:53:37 +0300 Subject: [PATCH 179/306] Minimal changes to document Singleton and class definitions it wraps --- src/bmconfigparser.py | 6 ++++-- src/singleton.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 726d32eb..7f28d1b8 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -43,8 +43,10 @@ BMConfigDefaults = { @Singleton class BMConfigParser(ConfigParser.SafeConfigParser): - """Singleton class inherited from ConfigParser.SafeConfigParser - with additional methods specific to bitmessage config.""" + """ + Singleton class inherited from :class:`ConfigParser.SafeConfigParser` + with additional methods specific to bitmessage config. + """ _temp = {} diff --git a/src/singleton.py b/src/singleton.py index 1eef08e1..5c6c43be 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -1,6 +1,21 @@ +""" +Singleton decorator definition +""" + +from functools import wraps + + def Singleton(cls): + """ + Decorator implementing the singleton pattern: + it restricts the instantiation of a class to one "single" instance. + """ instances = {} + + # https://github.com/sphinx-doc/sphinx/issues/3783 + @wraps(cls) def getinstance(): + """Find an instance or save newly created one""" if cls not in instances: instances[cls] = cls() return instances[cls] From 7a89109fc917c5af530c9643aa8faca32ab99cf8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 6 Aug 2019 14:04:33 +0300 Subject: [PATCH 180/306] New logging approach in order to reduce imports from submodules and use logging without risk of circular import. Only subpackage that imports from debug is bitmessageqt - because it also uses debug.resetLogging(). Instead of from debug import logger is now recommended to use: import logging logger = logging.getLogger('default') All subclasses of StoppableThread now have a logger attribute. All threading related stuff except for set_thread_name() was moved from helper_threading to network.threads. Fixed two my mistakes from previous edit of debug in a1a8d3a: - logger.handlers is not dict but iterable - sys.excepthook should be set unconditionally --- src/api.py | 2 +- src/bitmessagemain.py | 2 +- src/class_addressGenerator.py | 21 ++++--- src/class_singleCleaner.py | 93 +++++++++++++++---------------- src/class_singleWorker.py | 84 ++++++++++++++-------------- src/class_smtpDeliver.py | 14 ++--- src/class_smtpServer.py | 46 ++++++++------- src/debug.py | 86 ++++++++++++++++------------ src/helper_threading.py | 39 +------------ src/messagetypes/__init__.py | 10 ++-- src/messagetypes/message.py | 9 ++- src/messagetypes/vote.py | 9 ++- src/network/addrthread.py | 4 +- src/network/advanceddispatcher.py | 6 +- src/network/announcethread.py | 10 ++-- src/network/bmobject.py | 4 +- src/network/bmproto.py | 4 +- src/network/connectionchooser.py | 4 +- src/network/connectionpool.py | 4 +- src/network/dandelion.py | 6 +- src/network/downloadthread.py | 9 +-- src/network/invthread.py | 2 +- src/network/networkthread.py | 11 +--- src/network/proxy.py | 7 ++- src/network/receivequeuethread.py | 19 +++---- src/network/tcp.py | 4 +- src/network/threads.py | 49 ++++++++++++++++ src/network/tls.py | 3 +- src/network/udp.py | 12 ++-- src/network/uploadthread.py | 31 ++++++----- src/shutdown.py | 14 ++--- src/upnp.py | 2 +- 32 files changed, 328 insertions(+), 292 deletions(-) create mode 100644 src/network/threads.py diff --git a/src/api.py b/src/api.py index f92abeb4..b7f5c62d 100644 --- a/src/api.py +++ b/src/api.py @@ -38,8 +38,8 @@ from bmconfigparser import BMConfigParser from debug import logger from helper_ackPayload import genAckPayload from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure -from helper_threading import StoppableThread from inventory import Inventory +from network.threads import StoppableThread str_chan = '[chan]' diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 1dd2f271..4ad9311f 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -41,7 +41,7 @@ import shared import knownnodes import state import shutdown -from debug import logger +from debug import logger # this should go before any threads # Classes from class_sqlThread import sqlThread diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index d930fc99..fa268377 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -12,10 +12,9 @@ import shared import defaults import highlevelcrypto from bmconfigparser import BMConfigParser -from debug import logger from addresses import decodeAddress, encodeAddress, encodeVarint from fallback import RIPEMD160Hash -from helper_threading import StoppableThread +from network.threads import StoppableThread class addressGenerator(StoppableThread): @@ -85,12 +84,12 @@ class addressGenerator(StoppableThread): elif queueValue[0] == 'stopThread': break else: - logger.error( + self.logger.error( 'Programming error: A structure with the wrong number' ' of values was passed into the addressGeneratorQueue.' ' Here is the queueValue: %r\n', queueValue) if addressVersionNumber < 3 or addressVersionNumber > 4: - logger.error( + self.logger.error( 'Program error: For some reason the address generator' ' queue has been given a request to create at least' ' one version %s address which it cannot do.\n', @@ -139,10 +138,10 @@ class addressGenerator(StoppableThread): '\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash ): break - logger.info( + self.logger.info( 'Generated address with ripe digest: %s', hexlify(ripe)) try: - logger.info( + self.logger.info( 'Address generator calculated %s addresses at %s' ' addresses per second before finding one with' ' the correct ripe-prefix.', @@ -210,7 +209,7 @@ class addressGenerator(StoppableThread): or command == 'getDeterministicAddress' \ or command == 'createChan' or command == 'joinChan': if len(deterministicPassphrase) == 0: - logger.warning( + self.logger.warning( 'You are creating deterministic' ' address(es) using a blank passphrase.' ' Bitmessage will do it but it is rather stupid.') @@ -263,10 +262,10 @@ class addressGenerator(StoppableThread): ): break - logger.info( + self.logger.info( 'Generated address with ripe digest: %s', hexlify(ripe)) try: - logger.info( + self.logger.info( 'Address generator calculated %s addresses' ' at %s addresses per second before finding' ' one with the correct ripe-prefix.', @@ -316,7 +315,7 @@ class addressGenerator(StoppableThread): addressAlreadyExists = True if addressAlreadyExists: - logger.info( + self.logger.info( '%s already exists. Not adding it again.', address ) @@ -329,7 +328,7 @@ class addressGenerator(StoppableThread): ).arg(address) )) else: - logger.debug('label: %s', label) + self.logger.debug('label: %s', label) BMConfigParser().set(address, 'label', label) BMConfigParser().set(address, 'enabled', 'true') BMConfigParser().set(address, 'decoy', 'false') diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 49e15f49..fc53a5b0 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -24,16 +24,15 @@ import os import shared import time -import tr -from bmconfigparser import BMConfigParser -from helper_sql import sqlQuery, sqlExecute -from helper_threading import StoppableThread -from inventory import Inventory -from network.connectionpool import BMConnectionPool -from debug import logger import knownnodes import queues import state +import tr +from bmconfigparser import BMConfigParser +from helper_sql import sqlQuery, sqlExecute +from inventory import Inventory +from network.connectionpool import BMConnectionPool +from network.threads import StoppableThread class singleCleaner(StoppableThread): @@ -99,7 +98,7 @@ class singleCleaner(StoppableThread): ) for row in queryreturn: if len(row) < 2: - logger.error( + self.logger.error( 'Something went wrong in the singleCleaner thread:' ' a query did not return the requested fields. %r', row @@ -108,9 +107,9 @@ class singleCleaner(StoppableThread): break toAddress, ackData, status = row if status == 'awaitingpubkey': - resendPubkeyRequest(toAddress) + self.resendPubkeyRequest(toAddress) elif status == 'msgsent': - resendMsg(ackData) + self.resendMsg(ackData) try: # Cleanup knownnodes and handle possible severe exception @@ -118,7 +117,7 @@ class singleCleaner(StoppableThread): knownnodes.cleanupKnownNodes() except Exception as err: if "Errno 28" in str(err): - logger.fatal( + self.logger.fatal( '(while writing knownnodes to disk)' ' Alert: Your disk or data storage volume is full.' ) @@ -161,41 +160,41 @@ class singleCleaner(StoppableThread): if state.shutdown == 0: self.stop.wait(singleCleaner.cycleLength) + def resendPubkeyRequest(self, address): + """Resend pubkey request for address""" + self.logger.debug( + 'It has been a long time and we haven\'t heard a response to our' + ' getpubkey request. Sending again.' + ) + try: + # We need to take this entry out of the neededPubkeys structure + # because the queues.workerQueue checks to see whether the entry + # is already present and will not do the POW and send the message + # because it assumes that it has already done it recently. + del state.neededPubkeys[address] + except: + pass -def resendPubkeyRequest(address): - logger.debug( - 'It has been a long time and we haven\'t heard a response to our' - ' getpubkey request. Sending again.' - ) - try: - # We need to take this entry out of the neededPubkeys structure - # because the queues.workerQueue checks to see whether the entry - # is already present and will not do the POW and send the message - # because it assumes that it has already done it recently. - del state.neededPubkeys[address] - except: - pass + queues.UISignalQueue.put(( + 'updateStatusBar', + 'Doing work necessary to again attempt to request a public key...' + )) + sqlExecute( + '''UPDATE sent SET status='msgqueued' WHERE toaddress=?''', + address) + queues.workerQueue.put(('sendmessage', '')) - queues.UISignalQueue.put(( - 'updateStatusBar', - 'Doing work necessary to again attempt to request a public key...' - )) - sqlExecute( - '''UPDATE sent SET status='msgqueued' WHERE toaddress=?''', - address) - queues.workerQueue.put(('sendmessage', '')) - - -def resendMsg(ackdata): - logger.debug( - 'It has been a long time and we haven\'t heard an acknowledgement' - ' to our msg. Sending again.' - ) - sqlExecute( - '''UPDATE sent SET status='msgqueued' WHERE ackdata=?''', - ackdata) - queues.workerQueue.put(('sendmessage', '')) - queues.UISignalQueue.put(( - 'updateStatusBar', - 'Doing work necessary to again attempt to deliver a message...' - )) + def resendMsg(self, ackdata): + """Resend message by ackdata""" + self.logger.debug( + 'It has been a long time and we haven\'t heard an acknowledgement' + ' to our msg. Sending again.' + ) + sqlExecute( + '''UPDATE sent SET status='msgqueued' WHERE ackdata=?''', + ackdata) + queues.workerQueue.put(('sendmessage', '')) + queues.UISignalQueue.put(( + 'updateStatusBar', + 'Doing work necessary to again attempt to deliver a message...' + )) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 0798296e..77fa18c0 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -26,10 +26,9 @@ import state import tr from addresses import calculateInventoryHash, decodeAddress, decodeVarint, encodeVarint from bmconfigparser import BMConfigParser -from debug import logger from helper_sql import sqlExecute, sqlQuery -from helper_threading import StoppableThread from inventory import Inventory +from network.threads import StoppableThread def sizeof_fmt(num, suffix='h/s'): @@ -98,7 +97,7 @@ class singleWorker(StoppableThread): '''SELECT ackdata FROM sent WHERE status = 'msgsent' ''') for row in queryreturn: ackdata, = row - logger.info('Watching for ackdata %s', hexlify(ackdata)) + self.logger.info('Watching for ackdata %s', hexlify(ackdata)) shared.ackdataForWhichImWatching[ackdata] = 0 # Fix legacy (headerless) watched ackdata to include header @@ -173,14 +172,14 @@ class singleWorker(StoppableThread): self.busy = 0 return else: - logger.error( + self.logger.error( 'Probable programming error: The command sent' ' to the workerThread is weird. It is: %s\n', command ) queues.workerQueue.task_done() - logger.info("Quitting...") + self.logger.info("Quitting...") def _getKeysForAddress(self, address): privSigningKeyBase58 = BMConfigParser().get( @@ -217,25 +216,24 @@ class singleWorker(StoppableThread): )) / (2 ** 16)) )) initialHash = hashlib.sha512(payload).digest() - logger.info( + self.logger.info( '%s Doing proof of work... TTL set to %s', log_prefix, TTL) if log_time: start_time = time.time() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info( + self.logger.info( '%s Found proof of work %s Nonce: %s', log_prefix, trialValue, nonce ) try: delta = time.time() - start_time - logger.info( + self.logger.info( 'PoW took %.1f seconds, speed %s.', delta, sizeof_fmt(nonce / delta) ) except: # NameError pass payload = pack('>Q', nonce) + payload - # inventoryHash = calculateInventoryHash(payload) return payload def doPOWForMyV2Pubkey(self, adressHash): @@ -260,7 +258,7 @@ class singleWorker(StoppableThread): _, _, pubSigningKey, pubEncryptionKey = \ self._getKeysForAddress(myAddress) except Exception as err: - logger.error( + self.logger.error( 'Error within doPOWForMyV2Pubkey. Could not read' ' the keys from the keys.dat file for a requested' ' address. %s\n', err @@ -278,7 +276,8 @@ class singleWorker(StoppableThread): Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') - logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash)) + self.logger.info( + 'broadcasting inv with hash: %s', hexlify(inventoryHash)) queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) @@ -303,7 +302,7 @@ class singleWorker(StoppableThread): # The address has been deleted. return if BMConfigParser().safeGetBoolean(myAddress, 'chan'): - logger.info('This is a chan address. Not sending pubkey.') + self.logger.info('This is a chan address. Not sending pubkey.') return _, addressVersionNumber, streamNumber, adressHash = decodeAddress( myAddress) @@ -333,7 +332,7 @@ class singleWorker(StoppableThread): privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \ self._getKeysForAddress(myAddress) except Exception as err: - logger.error( + self.logger.error( 'Error within sendOutOrStoreMyV3Pubkey. Could not read' ' the keys from the keys.dat file for a requested' ' address. %s\n', err @@ -360,7 +359,8 @@ class singleWorker(StoppableThread): Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') - logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash)) + self.logger.info( + 'broadcasting inv with hash: %s', hexlify(inventoryHash)) queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) @@ -383,7 +383,7 @@ class singleWorker(StoppableThread): # The address has been deleted. return if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'): - logger.info('This is a chan address. Not sending pubkey.') + self.logger.info('This is a chan address. Not sending pubkey.') return _, addressVersionNumber, streamNumber, addressHash = decodeAddress( myAddress) @@ -402,7 +402,7 @@ class singleWorker(StoppableThread): privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \ self._getKeysForAddress(myAddress) except Exception as err: - logger.error( + self.logger.error( 'Error within sendOutOrStoreMyV4Pubkey. Could not read' ' the keys from the keys.dat file for a requested' ' address. %s\n', err @@ -450,7 +450,8 @@ class singleWorker(StoppableThread): doubleHashOfAddressData[32:] ) - logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash)) + self.logger.info( + 'broadcasting inv with hash: %s', hexlify(inventoryHash)) queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) @@ -459,7 +460,7 @@ class singleWorker(StoppableThread): myAddress, 'lastpubkeysendtime', str(int(time.time()))) BMConfigParser().save() except Exception as err: - logger.error( + self.logger.error( 'Error: Couldn\'t add the lastpubkeysendtime' ' to the keys.dat file. Error message: %s', err ) @@ -497,7 +498,7 @@ class singleWorker(StoppableThread): objectType, streamNumber, buffer(payload), embeddedTime, buffer(tag) ) - logger.info( + self.logger.info( 'sending inv (within sendOnionPeerObj function) for object: %s', hexlify(inventoryHash)) queues.invQueue.put((streamNumber, inventoryHash)) @@ -520,7 +521,7 @@ class singleWorker(StoppableThread): _, addressVersionNumber, streamNumber, ripe = \ decodeAddress(fromaddress) if addressVersionNumber <= 1: - logger.error( + self.logger.error( 'Error: In the singleWorker thread, the ' ' sendBroadcast function doesn\'t understand' ' the address version.\n') @@ -636,7 +637,7 @@ class singleWorker(StoppableThread): # to not let the user try to send a message this large # until we implement message continuation. if len(payload) > 2 ** 18: # 256 KiB - logger.critical( + self.logger.critical( 'This broadcast object is too large to send.' ' This should never happen. Object size: %s', len(payload) @@ -647,7 +648,7 @@ class singleWorker(StoppableThread): objectType = 3 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) - logger.info( + self.logger.info( 'sending inv (within sendBroadcast function)' ' for object: %s', hexlify(inventoryHash) @@ -867,8 +868,8 @@ class singleWorker(StoppableThread): "MainWindow", "Looking up the receiver\'s public key")) )) - logger.info('Sending a message.') - logger.debug( + self.logger.info('Sending a message.') + self.logger.debug( 'First 150 characters of message: %s', repr(message[:150]) ) @@ -912,7 +913,7 @@ class singleWorker(StoppableThread): if not shared.BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'willinglysendtomobile' ): - logger.info( + self.logger.info( 'The receiver is a mobile user but the' ' sender (you) has not selected that you' ' are willing to send to mobiles. Aborting' @@ -978,7 +979,7 @@ class singleWorker(StoppableThread): defaults.networkDefaultPayloadLengthExtraBytes: requiredPayloadLengthExtraBytes = \ defaults.networkDefaultPayloadLengthExtraBytes - logger.debug( + self.logger.debug( 'Using averageProofOfWorkNonceTrialsPerByte: %s' ' and payloadLengthExtraBytes: %s.', requiredAverageProofOfWorkNonceTrialsPerByte, @@ -1043,8 +1044,9 @@ class singleWorker(StoppableThread): l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. - logger.info('Sending a message.') - logger.debug('First 150 characters of message: %r', message[:150]) + self.logger.info('Sending a message.') + self.logger.debug( + 'First 150 characters of message: %r', message[:150]) behaviorBitfield = protocol.getBitfield(fromaddress) try: @@ -1063,7 +1065,7 @@ class singleWorker(StoppableThread): " message. %1" ).arg(l10n.formatTimestamp())) )) - logger.error( + self.logger.error( 'Error within sendMsg. Could not read the keys' ' from the keys.dat file for our own address. %s\n', err) @@ -1139,14 +1141,14 @@ class singleWorker(StoppableThread): payload += encodeVarint(encodedMessage.length) payload += encodedMessage.data if BMConfigParser().has_section(toaddress): - logger.info( + self.logger.info( 'Not bothering to include ackdata because we are' ' sending to ourselves or a chan.' ) fullAckPayload = '' elif not protocol.checkBitfield( behaviorBitfield, protocol.BITFIELD_DOESACK): - logger.info( + self.logger.info( 'Not bothering to include ackdata because' ' the receiver said that they won\'t relay it anyway.' ) @@ -1199,7 +1201,7 @@ class singleWorker(StoppableThread): requiredPayloadLengthExtraBytes )) / (2 ** 16)) )) - logger.info( + self.logger.info( '(For msg message) Doing proof of work. Total required' ' difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / @@ -1211,12 +1213,12 @@ class singleWorker(StoppableThread): powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info( + self.logger.info( '(For msg message) Found proof of work %s Nonce: %s', trialValue, nonce ) try: - logger.info( + self.logger.info( 'PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime)) @@ -1231,7 +1233,7 @@ class singleWorker(StoppableThread): # in the code to not let the user try to send a message # this large until we implement message continuation. if len(encryptedPayload) > 2 ** 18: # 256 KiB - logger.critical( + self.logger.critical( 'This msg object is too large to send. This should' ' never happen. Object size: %i', len(encryptedPayload) @@ -1262,7 +1264,7 @@ class singleWorker(StoppableThread): " Sent on %1" ).arg(l10n.formatTimestamp())) )) - logger.info( + self.logger.info( 'Broadcasting inv for my msg(within sendmsg function): %s', hexlify(inventoryHash) ) @@ -1315,7 +1317,7 @@ class singleWorker(StoppableThread): toStatus, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if toStatus != 'success': - logger.error( + self.logger.error( 'Very abnormal error occurred in requestPubKey.' ' toAddress is: %r. Please report this error to Atheros.', toAddress @@ -1329,7 +1331,7 @@ class singleWorker(StoppableThread): toAddress ) if not queryReturn: - logger.critical( + self.logger.critical( 'BUG: Why are we requesting the pubkey for %s' ' if there are no messages in the sent folder' ' to that address?', toAddress @@ -1377,11 +1379,11 @@ class singleWorker(StoppableThread): payload += encodeVarint(streamNumber) if addressVersionNumber <= 3: payload += ripe - logger.info( + self.logger.info( 'making request for pubkey with ripe: %s', hexlify(ripe)) else: payload += tag - logger.info( + self.logger.info( 'making request for v4 pubkey with tag: %s', hexlify(tag)) # print 'trial value', trialValue @@ -1402,7 +1404,7 @@ class singleWorker(StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') - logger.info('sending inv (for the getpubkey message)') + self.logger.info('sending inv (for the getpubkey message)') queues.invQueue.put((streamNumber, inventoryHash)) # wait 10% past expiration diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index fa607220..58cd4631 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -5,7 +5,6 @@ src/class_smtpDeliver.py # pylint: disable=unused-variable import smtplib -import sys import urlparse from email.header import Header from email.mime.text import MIMEText @@ -13,8 +12,7 @@ from email.mime.text import MIMEText import queues import state from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import StoppableThread +from network.threads import StoppableThread SMTPDOMAIN = "bmaddr.lan" @@ -75,10 +73,12 @@ class smtpDeliver(StoppableThread): client.starttls() client.ehlo() client.sendmail(msg['From'], [to], msg.as_string()) - logger.info("Delivered via SMTP to %s through %s:%i ...", to, u.hostname, u.port) + self.logger.info( + 'Delivered via SMTP to %s through %s:%i ...', + to, u.hostname, u.port) client.quit() except: - logger.error("smtp delivery error", exc_info=True) + self.logger.error('smtp delivery error', exc_info=True) elif command == 'displayNewSentMessage': toAddress, fromLabel, fromAddress, subject, message, ackdata = data elif command == 'updateNetworkStatusTab': @@ -112,5 +112,5 @@ class smtpDeliver(StoppableThread): elif command == 'stopThread': break else: - sys.stderr.write( - 'Command sent to smtpDeliver not recognized: %s\n' % command) + self.logger.warning( + 'Command sent to smtpDeliver not recognized: %s', command) diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 99d9c4b3..924333a6 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -1,26 +1,28 @@ import asyncore import base64 import email -from email.parser import Parser -from email.header import decode_header +import logging import re import signal import smtpd import threading import time +from email.header import decode_header +from email.parser import Parser +import queues from addresses import decodeAddress from bmconfigparser import BMConfigParser -from debug import logger -from helper_sql import sqlExecute from helper_ackPayload import genAckPayload -from helper_threading import StoppableThread -import queues +from helper_sql import sqlExecute +from network.threads import StoppableThread from version import softwareVersion SMTPDOMAIN = "bmaddr.lan" LISTENPORT = 8425 +logger = logging.getLogger('default') + class smtpServerChannel(smtpd.SMTPChannel): def smtp_EHLO(self, arg): @@ -39,7 +41,7 @@ class smtpServerChannel(smtpd.SMTPChannel): decoded = base64.b64decode(authstring) correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \ "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "") - logger.debug("authstring: %s / %s", correctauth, decoded) + logger.debug('authstring: %s / %s', correctauth, decoded) if correctauth == decoded: self.auth = True self.push('235 2.7.0 Authentication successful') @@ -50,7 +52,7 @@ class smtpServerChannel(smtpd.SMTPChannel): def smtp_DATA(self, arg): if not hasattr(self, "auth") or not self.auth: - self.push ("530 Authentication required") + self.push('530 Authentication required') return smtpd.SMTPChannel.smtp_DATA(self, arg) @@ -98,17 +100,15 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): return ret - def process_message(self, peer, mailfrom, rcpttos, data): -# print 'Receiving message from:', peer p = re.compile(".*<([^>]+)>") if not hasattr(self.channel, "auth") or not self.channel.auth: - logger.error("Missing or invalid auth") + logger.error('Missing or invalid auth') return try: self.msg_headers = Parser().parsestr(data) except: - logger.error("Invalid headers") + logger.error('Invalid headers') return try: @@ -118,7 +118,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): if sender not in BMConfigParser().addresses(): raise Exception("Nonexisting user %s" % sender) except Exception as err: - logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) + logger.debug('Bad envelope from %s: %r', mailfrom, err) msg_from = self.decode_header("from") try: msg_from = p.sub(r'\1', self.decode_header("from")[0]) @@ -128,7 +128,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): if sender not in BMConfigParser().addresses(): raise Exception("Nonexisting user %s" % sender) except Exception as err: - logger.error("Bad headers from %s: %s", msg_from, repr(err)) + logger.error('Bad headers from %s: %r', msg_from, err) return try: @@ -147,11 +147,12 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): rcpt, domain = p.sub(r'\1', to).split("@") if domain != SMTPDOMAIN: raise Exception("Bad domain %s" % domain) - logger.debug("Sending %s to %s about %s", sender, rcpt, msg_subject) + logger.debug( + 'Sending %s to %s about %s', sender, rcpt, msg_subject) self.send(sender, rcpt, msg_subject, body) - logger.info("Relayed %s to %s", sender, rcpt) + logger.info('Relayed %s to %s', sender, rcpt) except Exception as err: - logger.error( "Bad to %s: %s", to, repr(err)) + logger.error('Bad to %s: %r', to, err) continue return @@ -169,21 +170,24 @@ class smtpServer(StoppableThread): def run(self): asyncore.loop(1) + def signals(signal, frame): - print "Got signal, terminating" + logger.warning('Got signal, terminating') for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): thread.stopThread() + def runServer(): - print "Running SMTPd thread" + logger.warning('Running SMTPd thread') smtpThread = smtpServer() smtpThread.start() signal.signal(signal.SIGINT, signals) signal.signal(signal.SIGTERM, signals) - print "Processing" + logger.warning('Processing') smtpThread.join() - print "The end" + logger.warning('The end') + if __name__ == "__main__": runServer() diff --git a/src/debug.py b/src/debug.py index d3730d7f..7d523b3c 100644 --- a/src/debug.py +++ b/src/debug.py @@ -1,26 +1,38 @@ """ Logging and debuging facility -============================= +----------------------------- Levels: - DEBUG - Detailed information, typically of interest only when diagnosing problems. - INFO - Confirmation that things are working as expected. - WARNING - An indication that something unexpected happened, or indicative of some problem in the - near future (e.g. 'disk space low'). The software is still working as expected. - ERROR - Due to a more serious problem, the software has not been able to perform some function. - CRITICAL - A serious error, indicating that the program itself may be unable to continue running. + DEBUG + Detailed information, typically of interest only when diagnosing problems. + INFO + Confirmation that things are working as expected. + WARNING + An indication that something unexpected happened, or indicative of + some problem in the near future (e.g. 'disk space low'). The software + is still working as expected. + ERROR + Due to a more serious problem, the software has not been able to + perform some function. + CRITICAL + A serious error, indicating that the program itself may be unable to + continue running. -There are three loggers: `console_only`, `file_only` and `both`. +There are three loggers by default: `console_only`, `file_only` and `both`. +You can configure logging in the logging.dat in the appdata dir. +It's format is described in the :func:`logging.config.fileConfig` doc. -Use: `from debug import logger` to import this facility into whatever module you wish to log messages from. - Logging is thread-safe so you don't have to worry about locks, just import and log. +Use: +>>> import logging +>>> logger = logging.getLogger('default') + +The old form: ``from debug import logger`` is also may be used, +but only in the top level modules. + +Logging is thread-safe so you don't have to worry about locks, +just import and log. """ import ConfigParser @@ -28,6 +40,7 @@ import logging import logging.config import os import sys + import helper_startup import state @@ -41,10 +54,17 @@ log_level = 'WARNING' def log_uncaught_exceptions(ex_cls, ex, tb): + """The last resort logging function used for sys.excepthook""" logging.critical('Unhandled exception', exc_info=(ex_cls, ex, tb)) def configureLogging(): + """ + Configure logging, + using either logging.dat file in the state.appdata dir + or dictionary with hardcoded settings. + """ + sys.excepthook = log_uncaught_exceptions fail_msg = '' try: logging_config = os.path.join(state.appdata, 'logging.dat') @@ -63,9 +83,7 @@ def configureLogging(): # no need to confuse the user if the logger config is missing entirely fail_msg = 'Using default logger configuration' - sys.excepthook = log_uncaught_exceptions - - logging.config.dictConfig({ + logging_config = { 'version': 1, 'formatters': { 'default': { @@ -107,34 +125,28 @@ def configureLogging(): 'level': log_level, 'handlers': ['console'], }, - }) + } + + logging_config['loggers']['default'] = logging_config['loggers'][ + 'file_only' if '-c' in sys.argv else 'both'] + logging.config.dictConfig(logging_config) return True, fail_msg -def initLogging(): - preconfigured, msg = configureLogging() - if preconfigured: - if '-c' in sys.argv: - logger = logging.getLogger('file_only') - else: - logger = logging.getLogger('both') - else: - logger = logging.getLogger('default') - - if msg: - logger.log(logging.WARNING if preconfigured else logging.INFO, msg) - return logger - - def resetLogging(): + """Reconfigure logging in runtime when state.appdata dir changed""" global logger - for i in logger.handlers.iterkeys(): + for i in logger.handlers: logger.removeHandler(i) i.flush() i.close() - logger = initLogging() + configureLogging() + logger = logging.getLogger('default') # ! -logger = initLogging() +preconfigured, msg = configureLogging() +logger = logging.getLogger('default') +if msg: + logger.log(logging.WARNING if preconfigured else logging.INFO, msg) diff --git a/src/helper_threading.py b/src/helper_threading.py index 4b0a074e..e4fbe940 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -1,9 +1,6 @@ -"""Helper threading perform all the threading operations.""" +"""set_thread_name for threads that don't use StoppableThread""" import threading -from contextlib import contextmanager - -import helper_random try: import prctl @@ -22,37 +19,3 @@ else: threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap threading.Thread._Thread__bootstrap = _thread_name_hack - - -class StoppableThread(threading.Thread): - name = None - - def __init__(self, name=None): - if name: - self.name = name - super(StoppableThread, self).__init__(name=self.name) - self.initStop() - helper_random.seed() - - def initStop(self): - self.stop = threading.Event() - self._stopped = False - - def stopThread(self): - self._stopped = True - self.stop.set() - - -class BusyError(threading.ThreadError): - pass - - -@contextmanager -def nonBlocking(lock): - locked = lock.acquire(False) - if not locked: - raise BusyError - try: - yield - finally: - lock.release() diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 7319dfd5..af6bcdaa 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,17 +1,15 @@ -""" -src/messagetypes/__init__.py -============================ -""" +import logging from importlib import import_module from os import path, listdir from string import lower -from debug import logger import messagetypes import paths +logger = logging.getLogger('default') -class MsgBase(object): # pylint: disable=too-few-public-methods + +class MsgBase(object): # pylint: disable=too-few-public-methods """Base class for message types""" def __init__(self): self.data = {"": lower(type(self).__name__)} diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index cd5bf762..573732d4 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -1,10 +1,9 @@ -""" -src/messagetypes/message.py -=========================== -""" -from debug import logger +import logging + from messagetypes import MsgBase +logger = logging.getLogger('default') + class Message(MsgBase): """Encapsulate a message""" diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index e128e9ba..b559c256 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -1,10 +1,9 @@ -""" -src/messagetypes/vote.py -======================== -""" -from debug import logger +import logging + from messagetypes import MsgBase +logger = logging.getLogger('default') + class Vote(MsgBase): """Module used to vote""" diff --git a/src/network/addrthread.py b/src/network/addrthread.py index 9f516e80..d5d21599 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -1,9 +1,9 @@ import Queue -from helper_threading import StoppableThread +import state from network.connectionpool import BMConnectionPool from queues import addrQueue -import state +from threads import StoppableThread class AddrThread(StoppableThread): diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index c8f125f0..eeb50bdf 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -10,8 +10,7 @@ import time import network.asyncore_pollchoose as asyncore import state -from debug import logger -from helper_threading import BusyError, nonBlocking +from threads import BusyError, nonBlocking class ProcessingError(Exception): @@ -84,7 +83,8 @@ class AdvancedDispatcher(asyncore.dispatcher): try: cmd = getattr(self, "state_" + str(self.state)) except AttributeError: - logger.error("Unknown state %s", self.state, exc_info=True) + self.logger.error( + 'Unknown state %s', self.state, exc_info=True) raise UnknownStateError(self.state) if not cmd(): break diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 59fad128..5cd27ede 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -2,22 +2,20 @@ src/network/announcethread.py ================================= """ + import time +import state from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import StoppableThread from network.bmproto import BMProto from network.connectionpool import BMConnectionPool from network.udp import UDPSocket -import state +from threads import StoppableThread class AnnounceThread(StoppableThread): """A thread to manage regular announcing of this node""" - def __init__(self): - super(AnnounceThread, self).__init__(name="Announcer") - logger.info("init announce thread") + name = "Announcer" def run(self): lastSelfAnnounced = 0 diff --git a/src/network/bmobject.py b/src/network/bmobject.py index e19eaac9..ac6429e4 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -2,15 +2,17 @@ BMObject and it's exceptions. """ +import logging import time import protocol import state from addresses import calculateInventoryHash -from debug import logger from inventory import Inventory from network.dandelion import Dandelion +logger = logging.getLogger('default') + class BMObjectInsufficientPOWError(Exception): """Exception indicating the object doesn't have sufficient proof of work.""" diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 0a2cdc7e..839630d8 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -5,6 +5,7 @@ src/network/bmproto.py # pylint: disable=attribute-defined-outside-init import base64 import hashlib +import logging import socket import struct import time @@ -16,7 +17,6 @@ import knownnodes import protocol import state from bmconfigparser import BMConfigParser -from debug import logger from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher from network.dandelion import Dandelion @@ -30,6 +30,8 @@ from objectracker import missingObjects, ObjectTracker from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue from randomtrackingdict import RandomTrackingDict +logger = logging.getLogger('default') + class BMProtoError(ProxyError): """A Bitmessage Protocol Base Error""" diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 53ce30b7..ead8b31b 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -1,13 +1,15 @@ # pylint: disable=too-many-branches +import logging import random # nosec import knownnodes import protocol import state from bmconfigparser import BMConfigParser -from debug import logger from queues import Queue, portCheckerQueue +logger = logging.getLogger('default') + def getDiscoveredPeer(): try: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 4d16df49..1267522a 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -3,6 +3,7 @@ src/network/connectionpool.py ================================== """ import errno +import logging import re import socket import time @@ -14,7 +15,6 @@ import protocol import state from bmconfigparser import BMConfigParser from connectionchooser import chooseConnection -from debug import logger from proxy import Proxy from singleton import Singleton from tcp import ( @@ -22,6 +22,8 @@ from tcp import ( TCPConnection, TCPServer) from udp import UDPSocket +logger = logging.getLogger('default') + @Singleton # pylint: disable=too-many-instance-attributes diff --git a/src/network/dandelion.py b/src/network/dandelion.py index fa9081cb..eed3c6ff 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -2,6 +2,7 @@ src/network/dandelion.py ======================== """ +import logging from collections import namedtuple from random import choice, sample, expovariate from threading import RLock @@ -9,7 +10,6 @@ from time import time import connectionpool import state -from debug import logging from queues import invQueue from singleton import Singleton @@ -24,6 +24,8 @@ MAX_STEMS = 2 Stem = namedtuple('Stem', ['child', 'stream', 'timeout']) +logger = logging.getLogger('default') + @Singleton class Dandelion(): # pylint: disable=old-style-class @@ -72,7 +74,7 @@ class Dandelion(): # pylint: disable=old-style-class def removeHash(self, hashId, reason="no reason specified"): """Switch inventory vector from stem to fluff mode""" - logging.debug( + logger.debug( "%s entering fluff mode due to %s.", ''.join('%02x' % ord(i) for i in hashId), reason) with self.lock: diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index a4b58862..472b32c0 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -2,17 +2,17 @@ src/network/downloadthread.py ============================= """ + import time import addresses import helper_random import protocol from dandelion import Dandelion -from debug import logger -from helper_threading import StoppableThread from inventory import Inventory from network.connectionpool import BMConnectionPool from objectracker import missingObjects +from threads import StoppableThread class DownloadThread(StoppableThread): @@ -25,7 +25,6 @@ class DownloadThread(StoppableThread): def __init__(self): super(DownloadThread, self).__init__(name="Downloader") - logger.info("init download thread") self.lastCleaned = time.time() def cleanPending(self): @@ -78,7 +77,9 @@ class DownloadThread(StoppableThread): continue payload[0:0] = addresses.encodeVarint(chunkCount) i.append_write_buf(protocol.CreatePacket('getdata', payload)) - logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, chunkCount) + self.logger.debug( + '%s:%i Requesting %i objects', + i.destination.host, i.destination.port, chunkCount) requested += chunkCount if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() diff --git a/src/network/invthread.py b/src/network/invthread.py index ad3a0764..bffa6ecb 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -9,10 +9,10 @@ from time import time import addresses import protocol import state -from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool from network.dandelion import Dandelion from queues import invQueue +from threads import StoppableThread def handleExpiredDandelion(expired): diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 2a22367f..ba560906 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -1,20 +1,13 @@ -""" -src/network/networkthread.py -============================ -""" import network.asyncore_pollchoose as asyncore import state -from debug import logger -from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool from queues import excQueue +from threads import StoppableThread class BMNetworkThread(StoppableThread): """A thread to handle network concerns""" - def __init__(self): - super(BMNetworkThread, self).__init__(name="Asyncore") - logger.info("init asyncore thread") + name = "Asyncore" def run(self): try: diff --git a/src/network/proxy.py b/src/network/proxy.py index 479663d3..e65ac6a7 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -3,6 +3,7 @@ src/network/proxy.py ==================== """ # pylint: disable=protected-access +import logging import socket import time @@ -10,7 +11,8 @@ import asyncore_pollchoose as asyncore import state from advanceddispatcher import AdvancedDispatcher from bmconfigparser import BMConfigParser -from debug import logger + +logger = logging.getLogger('default') class ProxyError(Exception): @@ -144,5 +146,6 @@ class Proxy(AdvancedDispatcher): def state_proxy_handshake_done(self): """Handshake is complete at this point""" - self.connectedAt = time.time() # pylint: disable=attribute-defined-outside-init + # pylint: disable=attribute-defined-outside-init + self.connectedAt = time.time() return False diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 5d8cbd37..13c12ce2 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -2,18 +2,16 @@ import errno import Queue import socket -from debug import logger -from helper_threading import StoppableThread +import state from network.connectionpool import BMConnectionPool from network.advanceddispatcher import UnknownStateError from queues import receiveDataQueue -import state +from threads import StoppableThread class ReceiveQueueThread(StoppableThread): def __init__(self, num=0): super(ReceiveQueueThread, self).__init__(name="ReceiveQueue_%i" % num) - logger.info("init receive queue thread %i", num) def run(self): while not self._stopped and state.shutdown == 0: @@ -26,11 +24,12 @@ class ReceiveQueueThread(StoppableThread): break # cycle as long as there is data - # methods should return False if there isn't enough data, or the connection is to be aborted - - # state_* methods should return False if there isn't enough data, + # methods should return False if there isn't enough data, # or the connection is to be aborted + # state_* methods should return False if there isn't + # enough data, or the connection is to be aborted + try: connection = BMConnectionPool().getConnectionByAddr(dest) # KeyError = connection object not found @@ -40,13 +39,13 @@ class ReceiveQueueThread(StoppableThread): try: connection.process() # UnknownStateError = state isn't implemented - except (UnknownStateError): + except UnknownStateError: pass except socket.error as err: if err.errno == errno.EBADF: connection.set_state("close", 0) else: - logger.error("Socket error: %s", str(err)) + self.logger.error('Socket error: %s', err) except: - logger.error("Error processing", exc_info=True) + self.logger.error('Error processing', exc_info=True) receiveDataQueue.task_done() diff --git a/src/network/tcp.py b/src/network/tcp.py index da02df2f..368ca5e0 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -4,6 +4,7 @@ src/network/tcp.py ================== """ +import logging import math import random import socket @@ -18,7 +19,6 @@ import protocol import shared import state from bmconfigparser import BMConfigParser -from debug import logger from helper_random import randomBytes from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher @@ -30,6 +30,8 @@ from network.socks5 import Socks5Connection from network.tls import TLSDispatcher from queues import UISignalQueue, invQueue, receiveDataQueue +logger = logging.getLogger('default') + class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes diff --git a/src/network/threads.py b/src/network/threads.py new file mode 100644 index 00000000..9bdaa85d --- /dev/null +++ b/src/network/threads.py @@ -0,0 +1,49 @@ +"""Threading primitives for the network package""" + +import logging +import random +import threading +from contextlib import contextmanager + + +class StoppableThread(threading.Thread): + """Base class for application threads with stopThread method""" + name = None + logger = logging.getLogger('default') + + def __init__(self, name=None): + if name: + self.name = name + super(StoppableThread, self).__init__(name=self.name) + self.stop = threading.Event() + self._stopped = False + random.seed() + self.logger.info('Init thread %s', self.name) + + def stopThread(self): + """Stop the thread""" + self._stopped = True + self.stop.set() + + +class BusyError(threading.ThreadError): + """ + Thread error raised when another connection holds the lock + we are trying to acquire. + """ + pass + + +@contextmanager +def nonBlocking(lock): + """ + A context manager which acquires given lock non-blocking + and raises BusyError if failed to acquire. + """ + locked = lock.acquire(False) + if not locked: + raise BusyError + try: + yield + finally: + lock.release() diff --git a/src/network/tls.py b/src/network/tls.py index 17b1ee1f..52f17c29 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -2,17 +2,18 @@ SSL/TLS negotiation. """ +import logging import os import socket import ssl import sys -from debug import logger from network.advanceddispatcher import AdvancedDispatcher import network.asyncore_pollchoose as asyncore from queues import receiveDataQueue import paths +logger = logging.getLogger('default') _DISCONNECTED_SSL = frozenset((ssl.SSL_ERROR_EOF,)) diff --git a/src/network/udp.py b/src/network/udp.py index 01dc1f7b..97c6aee5 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -2,24 +2,27 @@ src/network/udp.py ================== """ +import logging import time import socket import state import protocol from bmproto import BMProto -from debug import logger from objectracker import ObjectTracker from queues import receiveDataQueue +logger = logging.getLogger('default') -class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes + +class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes """Bitmessage protocol over UDP (class)""" port = 8444 announceInterval = 60 def __init__(self, host=None, sock=None, announcing=False): - super(BMProto, self).__init__(sock=sock) # pylint: disable=bad-super-call + # pylint: disable=bad-super-call + super(BMProto, self).__init__(sock=sock) self.verackReceived = True self.verackSent = True # .. todo:: sort out streams @@ -79,7 +82,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attribut decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue - if (seenTime < time.time() - self.maxTimeOffset or seenTime > time.time() + self.maxTimeOffset): + if (seenTime < time.time() - self.maxTimeOffset + or seenTime > time.time() + self.maxTimeOffset): continue if decodedIP is False: # if the address isn't local, interpret it as diff --git a/src/network/uploadthread.py b/src/network/uploadthread.py index 9b29ef0a..1b57bd9a 100644 --- a/src/network/uploadthread.py +++ b/src/network/uploadthread.py @@ -1,26 +1,23 @@ """ src/network/uploadthread.py """ -# pylint: disable=unsubscriptable-object import time import helper_random import protocol -from debug import logger -from helper_threading import StoppableThread from inventory import Inventory from network.connectionpool import BMConnectionPool from network.dandelion import Dandelion from randomtrackingdict import RandomTrackingDict +from threads import StoppableThread class UploadThread(StoppableThread): - """This is a thread that uploads the objects that the peers requested from me """ + """ + This is a thread that uploads the objects that the peers requested from me + """ maxBufSize = 2097152 # 2MB - - def __init__(self): - super(UploadThread, self).__init__(name="Uploader") - logger.info("init upload thread") + name = "Uploader" def run(self): while not self._stopped: @@ -47,22 +44,26 @@ class UploadThread(StoppableThread): if Dandelion().hasHash(chunk) and \ i != Dandelion().objectChildStem(chunk): i.antiIntersectionDelay() - logger.info('%s asked for a stem object we didn\'t offer to it.', - i.destination) + self.logger.info( + '%s asked for a stem object we didn\'t offer to it.', + i.destination) break try: - payload.extend(protocol.CreatePacket('object', - Inventory()[chunk].payload)) + payload.extend(protocol.CreatePacket( + 'object', Inventory()[chunk].payload)) chunk_count += 1 except KeyError: i.antiIntersectionDelay() - logger.info('%s asked for an object we don\'t have.', i.destination) + self.logger.info( + '%s asked for an object we don\'t have.', + i.destination) break if not chunk_count: continue i.append_write_buf(payload) - logger.debug("%s:%i Uploading %i objects", - i.destination.host, i.destination.port, chunk_count) + self.logger.debug( + '%s:%i Uploading %i objects', + i.destination.host, i.destination.port, chunk_count) uploaded += chunk_count if not uploaded: self.stop.wait(1) diff --git a/src/shutdown.py b/src/shutdown.py index f136ac75..85d11d67 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -3,15 +3,15 @@ import Queue import threading import time -from debug import logger -from helper_sql import sqlQuery, sqlStoredProcedure -from helper_threading import StoppableThread -from knownnodes import saveKnownNodes -from inventory import Inventory -from queues import ( - addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue) import shared import state +from debug import logger +from helper_sql import sqlQuery, sqlStoredProcedure +from inventory import Inventory +from knownnodes import saveKnownNodes +from network.threads import StoppableThread +from queues import ( + addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue) def doCleanShutdown(): diff --git a/src/upnp.py b/src/upnp.py index fdc4bc1d..b1ee2e7b 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -21,8 +21,8 @@ import state import tr from bmconfigparser import BMConfigParser from debug import logger -from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool +from network.threads import StoppableThread def createRequestXML(service, action, arguments=None): From d2a896697d83e1f99bdd649af8771fb73c54393d Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 7 Aug 2019 18:31:08 +0300 Subject: [PATCH 181/306] Used logger.isEnabledFor() to prevent unneeded calculations --- src/class_objectProcessor.py | 57 ++++++++++++++++++++---------------- src/network/bmproto.py | 2 +- src/network/dandelion.py | 7 +++-- src/network/tls.py | 41 ++++++++++++++++---------- 4 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 1a9c0d81..6ae46658 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -1,4 +1,5 @@ import hashlib +import logging import random import shared import threading @@ -24,10 +25,11 @@ import protocol import queues import state import tr -from debug import logger from fallback import RIPEMD160Hash import l10n +logger = logging.getLogger('default') + class objectProcessor(threading.Thread): """ @@ -316,13 +318,14 @@ class objectProcessor(threading.Thread): '\x04' + publicSigningKey + '\x04' + publicEncryptionKey) ripe = RIPEMD160Hash(sha.digest()).digest() - logger.debug( - 'within recpubkey, addressVersion: %s, streamNumber: %s' - '\nripe %s\npublicSigningKey in hex: %s' - '\npublicEncryptionKey in hex: %s', - addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) - ) + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + 'within recpubkey, addressVersion: %s, streamNumber: %s' + '\nripe %s\npublicSigningKey in hex: %s' + '\npublicEncryptionKey in hex: %s', + addressVersion, streamNumber, hexlify(ripe), + hexlify(publicSigningKey), hexlify(publicEncryptionKey) + ) address = encodeAddress(addressVersion, streamNumber, ripe) @@ -380,13 +383,14 @@ class objectProcessor(threading.Thread): sha.update(publicSigningKey + publicEncryptionKey) ripe = RIPEMD160Hash(sha.digest()).digest() - logger.debug( - 'within recpubkey, addressVersion: %s, streamNumber: %s' - '\nripe %s\npublicSigningKey in hex: %s' - '\npublicEncryptionKey in hex: %s', - addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) - ) + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + 'within recpubkey, addressVersion: %s, streamNumber: %s' + '\nripe %s\npublicSigningKey in hex: %s' + '\npublicEncryptionKey in hex: %s', + addressVersion, streamNumber, hexlify(ripe), + hexlify(publicSigningKey), hexlify(publicEncryptionKey) + ) address = encodeAddress(addressVersion, streamNumber, ripe) queryreturn = sqlQuery( @@ -579,17 +583,18 @@ class objectProcessor(threading.Thread): logger.debug('ECDSA verify failed') return logger.debug('ECDSA verify passed') - logger.debug( - 'As a matter of intellectual curiosity, here is the Bitcoin' - ' address associated with the keys owned by the other person:' - ' %s ..and here is the testnet address: %s. The other person' - ' must take their private signing key from Bitmessage and' - ' import it into Bitcoin (or a service like Blockchain.info)' - ' for it to be of any use. Do not use this unless you know' - ' what you are doing.', - helper_bitcoin.calculateBitcoinAddressFromPubkey(pubSigningKey), - helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey) - ) + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + 'As a matter of intellectual curiosity, here is the Bitcoin' + ' address associated with the keys owned by the other person:' + ' %s ..and here is the testnet address: %s. The other person' + ' must take their private signing key from Bitmessage and' + ' import it into Bitcoin (or a service like Blockchain.info)' + ' for it to be of any use. Do not use this unless you know' + ' what you are doing.', + helper_bitcoin.calculateBitcoinAddressFromPubkey(pubSigningKey), + helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey) + ) # Used to detect and ignore duplicate messages in our inbox sigHash = hashlib.sha512( hashlib.sha512(signature).digest()).digest()[32:] diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 839630d8..6375f393 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -510,7 +510,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.timeOffset = self.timestamp - int(time.time()) logger.debug('remoteProtocolVersion: %i', self.remoteProtocolVersion) logger.debug('services: 0x%08X', self.services) - logger.debug('time offset: %i', self.timestamp - int(time.time())) + logger.debug('time offset: %i', self.timeOffset) logger.debug('my external IP: %s', self.sockNode.host) logger.debug( 'remote node incoming address: %s:%i', diff --git a/src/network/dandelion.py b/src/network/dandelion.py index eed3c6ff..0f68cc24 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -74,9 +74,10 @@ class Dandelion(): # pylint: disable=old-style-class def removeHash(self, hashId, reason="no reason specified"): """Switch inventory vector from stem to fluff mode""" - logger.debug( - "%s entering fluff mode due to %s.", - ''.join('%02x' % ord(i) for i in hashId), reason) + if logger.isEnabledFor(logging.DEBUG): + logger.debug( + '%s entering fluff mode due to %s.', + ''.join('%02x' % ord(i) for i in hashId), reason) with self.lock: try: del self.hashMap[hashId] diff --git a/src/network/tls.py b/src/network/tls.py index 52f17c29..d5c4e23a 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -39,12 +39,13 @@ else: sslProtocolCiphers = "AECDH-AES256-SHA" -class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instance-attributes +class TLSDispatcher(AdvancedDispatcher): """TLS functionality for classes derived from AdvancedDispatcher""" - # pylint: disable=too-many-arguments, super-init-not-called, unused-argument + # pylint: disable=too-many-instance-attributes + # pylint: disable=too-many-arguments,super-init-not-called,unused-argument def __init__( - self, address=None, sock=None, certfile=None, keyfile=None, - server_side=False, ciphers=sslProtocolCiphers + self, address=None, sock=None, certfile=None, keyfile=None, + server_side=False, ciphers=sslProtocolCiphers ): self.want_read = self.want_write = True if certfile is None: @@ -96,7 +97,10 @@ class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instanc @staticmethod def state_tls_handshake(): - """Do nothing while TLS handshake is pending, as during this phase we need to react to callbacks instead""" + """ + Do nothing while TLS handshake is pending, as during this phase + we need to react to callbacks instead + """ return False def writable(self): @@ -122,10 +126,11 @@ class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instanc except AttributeError: return AdvancedDispatcher.readable(self) - def handle_read(self): # pylint: disable=inconsistent-return-statements + def handle_read(self): # pylint: disable=inconsistent-return-statements """ - Handle reads for sockets during TLS handshake. Requires special treatment as during the handshake, buffers must - remain empty and normal reads must be ignored + Handle reads for sockets during TLS handshake. Requires special + treatment as during the handshake, buffers must remain empty + and normal reads must be ignored. """ try: # wait for write buffer flush @@ -147,10 +152,11 @@ class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instanc self.handle_close() return - def handle_write(self): # pylint: disable=inconsistent-return-statements + def handle_write(self): # pylint: disable=inconsistent-return-statements """ - Handle writes for sockets during TLS handshake. Requires special treatment as during the handshake, buffers - must remain empty and normal writes must be ignored + Handle writes for sockets during TLS handshake. Requires special + treatment as during the handshake, buffers must remain empty + and normal writes must be ignored. """ try: # wait for write buffer flush @@ -193,18 +199,23 @@ class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instanc if not (self.want_write or self.want_read): raise except socket.error as err: - if err.errno in asyncore._DISCONNECTED: # pylint: disable=protected-access + # pylint: disable=protected-access + if err.errno in asyncore._DISCONNECTED: self.handle_close() else: raise else: if sys.version_info >= (2, 7, 9): self.tlsVersion = self.sslSocket.version() - logger.debug("%s:%i: TLS handshake success, TLS protocol version: %s", - self.destination.host, self.destination.port, self.sslSocket.version()) + logger.debug( + '%s:%i: TLS handshake success, TLS protocol version: %s', + self.destination.host, self.destination.port, + self.tlsVersion) else: self.tlsVersion = "TLSv1" - logger.debug("%s:%i: TLS handshake success", self.destination.host, self.destination.port) + logger.debug( + '%s:%i: TLS handshake success', + self.destination.host, self.destination.port) # The handshake has completed, so remove this channel and... self.del_channel() self.set_socket(self.sslSocket) From bbdbca253b69103f2219e7013260e100775df97f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 14 Aug 2019 18:34:34 +0300 Subject: [PATCH 182/306] Added warnings about changing port settings in api and network.tcp --- src/api.py | 5 ++++- src/network/tcp.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api.py b/src/api.py index b7f5c62d..f9d0a518 100644 --- a/src/api.py +++ b/src/api.py @@ -95,6 +95,8 @@ class singleAPI(StoppableThread): for attempt in range(50): try: if attempt > 0: + logger.warning( + 'Failed to start API listener on port %s', port) port = random.randint(32767, 65535) se = StoppableXMLRPCServer( (BMConfigParser().get( @@ -106,8 +108,9 @@ class singleAPI(StoppableThread): continue else: if attempt > 0: + logger.warning('Setting apiport to %s', port) BMConfigParser().set( - "bitmessagesettings", "apiport", str(port)) + 'bitmessagesettings', 'apiport', str(port)) BMConfigParser().save() break se.register_introspection_functions() diff --git a/src/network/tcp.py b/src/network/tcp.py index 368ca5e0..a1691ceb 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -371,6 +371,7 @@ class TCPServer(AdvancedDispatcher): for attempt in range(50): try: if attempt > 0: + logger.warning('Failed to bind on port %s', port) port = random.randint(32767, 65535) self.bind((host, port)) except socket.error as e: @@ -378,6 +379,7 @@ class TCPServer(AdvancedDispatcher): continue else: if attempt > 0: + logger.warning('Setting port to %s', port) BMConfigParser().set( 'bitmessagesettings', 'port', str(port)) BMConfigParser().save() From a48b51721d386eafbc4a07d69990997d70727112 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 30 Aug 2019 14:56:46 +0300 Subject: [PATCH 183/306] Test new logging approach, both debug.logger and resetLogging --- src/debug.py | 6 ++-- src/tests/test_logger.py | 69 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/tests/test_logger.py diff --git a/src/debug.py b/src/debug.py index 7d523b3c..472b0d02 100644 --- a/src/debug.py +++ b/src/debug.py @@ -68,7 +68,8 @@ def configureLogging(): fail_msg = '' try: logging_config = os.path.join(state.appdata, 'logging.dat') - logging.config.fileConfig(logging_config) + logging.config.fileConfig( + logging_config, disable_existing_loggers=False) return ( False, 'Loaded logger configuration from %s' % logging_config @@ -80,7 +81,8 @@ def configureLogging(): ' logging config\n%s' % \ (logging_config, sys.exc_info()) else: - # no need to confuse the user if the logger config is missing entirely + # no need to confuse the user if the logger config + # is missing entirely fail_msg = 'Using default logger configuration' logging_config = { diff --git a/src/tests/test_logger.py b/src/tests/test_logger.py new file mode 100644 index 00000000..57448911 --- /dev/null +++ b/src/tests/test_logger.py @@ -0,0 +1,69 @@ +""" +Testing the logger configuration +""" + +import logging +import os +import tempfile +import unittest + + +class TestLogger(unittest.TestCase): + """A test case for bmconfigparser""" + + conf_template = ''' +[loggers] +keys=root + +[handlers] +keys=default + +[formatters] +keys=default + +[formatter_default] +format=%(asctime)s {1} %(message)s + +[handler_default] +class=FileHandler +level=NOTSET +formatter=default +args=('{0}', 'w') + +[logger_root] +level=DEBUG +handlers=default +''' + + def test_fileConfig(self): + """Put logging.dat with special pattern and check it was used""" + tmp = os.environ['BITMESSAGE_HOME'] = tempfile.gettempdir() + log_config = os.path.join(tmp, 'logging.dat') + log_file = os.path.join(tmp, 'debug.log') + + def gen_log_config(pattern): + """A small closure to generate logging.dat with custom pattern""" + with open(log_config, 'wb') as dst: + dst.write(self.conf_template.format(log_file, pattern)) + + pattern = r' o_0 ' + gen_log_config(pattern) + + try: + from pybitmessage.debug import logger, resetLogging + if not os.path.isfile(log_file): # second pass + pattern = r' <===> ' + gen_log_config(pattern) + resetLogging() + except ImportError: + self.fail('There is no package pybitmessage. Things gone wrong.') + finally: + os.remove(log_config) + + logger_ = logging.getLogger('default') + + self.assertEqual(logger, logger_) + + logger_.info('Testing the logger...') + + self.assertRegexpMatches(open(log_file).read(), pattern) From f0b4e4ded4592bb2c5f5b60a8704438ba07d2ca1 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 17 Oct 2019 23:37:56 +0300 Subject: [PATCH 184/306] Replaced logging.getLogger() in other possible places --- src/l10n.py | 3 +-- src/plugins/proxyconfig_stem.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/l10n.py b/src/l10n.py index b3b16341..d18f4199 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -6,8 +6,7 @@ import time from bmconfigparser import BMConfigParser -#logger = logging.getLogger(__name__) -logger = logging.getLogger('file_only') +logger = logging.getLogger('default') DEFAULT_ENCODING = 'ISO8859-1' diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index 5bb9a726..bdbfe8ca 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -18,7 +18,7 @@ class DebugLogger(object): """Safe logger wrapper for tor and plugin's logs""" # pylint: disable=too-few-public-methods def __init__(self): - self._logger = logging.getLogger(__name__.split('.', 1)[0]) + self._logger = logging.getLogger('default') self._levels = { 'err': 40, 'warn': 30, From b42f536d23ab617ac56fc71f9a7743333ad499ef Mon Sep 17 00:00:00 2001 From: George McCandless <5fk7echy8@riseup.net> Date: Tue, 8 Oct 2019 20:08:42 +0000 Subject: [PATCH 185/306] Add a checkbox to the network settings tab that allows restricting outbound connections to onion services (i.e., hosts that end with '.onion'). --- src/bitmessageqt/settings.py | 10 ++++++++++ src/bitmessageqt/settings.ui | 7 +++++++ src/network/connectionchooser.py | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 513f285b..982328cc 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -99,6 +99,8 @@ class SettingsDialog(QtGui.QDialog): config.getboolean('bitmessagesettings', 'socksauthentication')) self.checkBoxSocksListen.setChecked( config.getboolean('bitmessagesettings', 'sockslisten')) + self.checkBoxOnionOnly.setChecked( + config.safeGetBoolean('bitmessagesettings', 'onionservicesonly')) proxy_type = config.safeGet( 'bitmessagesettings', 'socksproxytype', 'none') @@ -110,6 +112,7 @@ class SettingsDialog(QtGui.QDialog): self.lineEditSocksPassword.setEnabled(False) self.checkBoxAuthentication.setEnabled(False) self.checkBoxSocksListen.setEnabled(False) + self.checkBoxOnionOnly.setEnabled(False) elif proxy_type == 'SOCKS4a': self.comboBoxProxyType.setCurrentIndex(1) elif proxy_type == 'SOCKS5': @@ -200,11 +203,13 @@ class SettingsDialog(QtGui.QDialog): self.lineEditSocksPassword.setEnabled(False) self.checkBoxAuthentication.setEnabled(False) self.checkBoxSocksListen.setEnabled(False) + self.checkBoxOnionOnly.setEnabled(False) elif comboBoxIndex in (1, 2): self.lineEditSocksHostname.setEnabled(True) self.lineEditSocksPort.setEnabled(True) self.checkBoxAuthentication.setEnabled(True) self.checkBoxSocksListen.setEnabled(True) + self.checkBoxOnionOnly.setEnabled(True) if self.checkBoxAuthentication.isChecked(): self.lineEditSocksUsername.setEnabled(True) self.lineEditSocksPassword.setEnabled(True) @@ -334,6 +339,11 @@ class SettingsDialog(QtGui.QDialog): self.lineEditSocksPassword.text())) self.config.set('bitmessagesettings', 'sockslisten', str( self.checkBoxSocksListen.isChecked())) + if self.checkBoxOnionOnly.isChecked() \ + and not self.config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'): + self.net_restart_needed = True + self.config.set('bitmessagesettings', 'onionservicesonly', str( + self.checkBoxOnionOnly.isChecked())) try: # Rounding to integers just for aesthetics self.config.set('bitmessagesettings', 'maxdownloadrate', str( diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 307c06c2..963f2e64 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -403,6 +403,13 @@
+ + + + Only connect to onion services (*.onion) + + + diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index ead8b31b..838ca45d 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -26,6 +26,8 @@ def getDiscoveredPeer(): def chooseConnection(stream): haveOnion = BMConfigParser().safeGet( "bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' + onionOnly = BMConfigParser().safeGetBoolean( + "bitmessagesettings", "onionservicesonly") if state.trustedPeer: return state.trustedPeer try: @@ -49,6 +51,9 @@ def chooseConnection(stream): logger.warning('Error in %s', peer) rating = 0 if haveOnion: + # do not connect to raw IP addresses--keep all traffic within Tor overlay + if onionOnly and not peer.host.endswith('.onion'): + continue # onion addresses have a higher priority when SOCKS if peer.host.endswith('.onion') and rating > 0: rating = 1 From f871cd450c15270209e33d3c350fa76b2936d147 Mon Sep 17 00:00:00 2001 From: George McCandless <5fk7echy8@riseup.net> Date: Thu, 24 Oct 2019 19:35:32 +0000 Subject: [PATCH 186/306] Add test for 'onionservicesonly' mode. Credit to Dmitri Bogomolov in commit 557a8cc6d2bec881b8a3c531d3f725460ed515f5. --- src/tests/core.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/core.py b/src/tests/core.py index b01c6b69..8d24a768 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -173,6 +173,22 @@ class TestCore(unittest.TestCase): self.fail( 'Failed to connect during %s sec' % (time.time() - _started)) + def test_onionservicesonly(self): + """test onionservicesonly networking mode""" + BMConfigParser().set('bitmessagesettings', 'onionservicesonly', True) + self._initiate_bootstrap() + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + for _ in range(360): + time.sleep(1) + for n, peer in enumerate(BMConnectionPool().outboundConnections): + if n > 2: + return + if not peer.host.endswith('.onion'): + self.fail( + 'Found non onion hostname %s in outbound connections!' + % peer.host) + self.fail('Failed to connect to at least 3 nodes within 360 sec') + def test_bootstrap(self): """test bootstrapping""" self._initiate_bootstrap() From 1a7ef791e548fb3329ee1e6320081c071cde777b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 21 Oct 2019 11:12:29 +0300 Subject: [PATCH 187/306] message_data_reader is obsolete --- src/message_data_reader.py | 136 ------------------------------------- 1 file changed, 136 deletions(-) delete mode 100644 src/message_data_reader.py diff --git a/src/message_data_reader.py b/src/message_data_reader.py deleted file mode 100644 index de6ed6c0..00000000 --- a/src/message_data_reader.py +++ /dev/null @@ -1,136 +0,0 @@ -# pylint: disable=too-many-locals -""" -This program can be used to print out everything in your Inbox or Sent folders and also take things out of the trash. -Scroll down to the bottom to see the functions that you can uncomment. Save then run this file. -The functions which only read the database file seem to function just -fine even if you have Bitmessage running but you should definitly close -it before running the functions that make changes (like taking items out -of the trash). -""" - -from __future__ import absolute_import - -import sqlite3 -from binascii import hexlify -from time import strftime, localtime - -import paths -import queues - - -appdata = paths.lookupAppdataFolder() - -conn = sqlite3.connect(appdata + 'messages.dat') -conn.text_factory = str -cur = conn.cursor() - - -def readInbox(): - """Print each row from inbox table""" - print 'Printing everything in inbox table:' - item = '''select * from inbox''' - parameters = '' - cur.execute(item, parameters) - output = cur.fetchall() - for row in output: - print row - - -def readSent(): - """Print each row from sent table""" - print 'Printing everything in Sent table:' - item = '''select * from sent where folder !='trash' ''' - parameters = '' - cur.execute(item, parameters) - output = cur.fetchall() - for row in output: - (msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, - sleeptill, status, retrynumber, folder, encodingtype, ttl) = row # pylint: disable=unused-variable - print(hexlify(msgid), toaddress, 'toripe:', hexlify(toripe), 'fromaddress:', fromaddress, 'ENCODING TYPE:', - encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', hexlify(ackdata), - lastactiontime, status, retrynumber, folder) - - -def readSubscriptions(): - """Print each row from subscriptions table""" - print 'Printing everything in subscriptions table:' - item = '''select * from subscriptions''' - parameters = '' - cur.execute(item, parameters) - output = cur.fetchall() - for row in output: - print row - - -def readPubkeys(): - """Print each row from pubkeys table""" - print 'Printing everything in pubkeys table:' - item = '''select address, transmitdata, time, usedpersonally from pubkeys''' - parameters = '' - cur.execute(item, parameters) - output = cur.fetchall() - for row in output: - address, transmitdata, time, usedpersonally = row - print( - 'Address:', address, '\tTime first broadcast:', unicode( - strftime('%a, %d %b %Y %I:%M %p', localtime(time)), 'utf-8'), - '\tUsed by me personally:', usedpersonally, '\tFull pubkey message:', hexlify(transmitdata), - ) - - -def readInventory(): - """Print each row from inventory table""" - print 'Printing everything in inventory table:' - item = '''select hash, objecttype, streamnumber, payload, expirestime from inventory''' - parameters = '' - cur.execute(item, parameters) - output = cur.fetchall() - for row in output: - obj_hash, objecttype, streamnumber, payload, expirestime = row - print 'Hash:', hexlify(obj_hash), objecttype, streamnumber, '\t', hexlify(payload), '\t', unicode( - strftime('%a, %d %b %Y %I:%M %p', localtime(expirestime)), 'utf-8') - - -def takeInboxMessagesOutOfTrash(): - """Update all inbox messages with folder=trash to have folder=inbox""" - item = '''update inbox set folder='inbox' where folder='trash' ''' - parameters = '' - cur.execute(item, parameters) - _ = cur.fetchall() - conn.commit() - print 'done' - - -def takeSentMessagesOutOfTrash(): - """Update all sent messages with folder=trash to have folder=sent""" - item = '''update sent set folder='sent' where folder='trash' ''' - parameters = '' - cur.execute(item, parameters) - _ = cur.fetchall() - conn.commit() - print 'done' - - -def markAllInboxMessagesAsUnread(): - """Update all messages in inbox to have read=0""" - item = '''update inbox set read='0' ''' - parameters = '' - cur.execute(item, parameters) - _ = cur.fetchall() - conn.commit() - queues.UISignalQueue.put(('changedInboxUnread', None)) - print 'done' - - -def vacuum(): - """Perform a vacuum on the database""" - item = '''VACUUM''' - parameters = '' - cur.execute(item, parameters) - _ = cur.fetchall() - conn.commit() - print 'done' - - -if __name__ == '__main__': - readInbox() From ee5be281793582a8c62e690e0248d910b544ab5c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:51:59 +0530 Subject: [PATCH 188/306] helper_threading quality fixes --- src/helper_threading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper_threading.py b/src/helper_threading.py index e4fbe940..56dd7063 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -16,6 +16,6 @@ else: def _thread_name_hack(self): set_thread_name(self.name) threading.Thread.__bootstrap_original__(self) - + # pylint: disable=protected-access threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap threading.Thread._Thread__bootstrap = _thread_name_hack From afce50008571996e686c23861fe30b5071dfba12 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:52:41 +0530 Subject: [PATCH 189/306] knownnodes quality fixes --- src/knownnodes.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/knownnodes.py b/src/knownnodes.py index ba21bac7..1d9e6897 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -82,6 +82,7 @@ def pickle_deserialize_old_knownnodes(source): def saveKnownNodes(dirName=None): + """Save knownnodes to filesystem""" if dirName is None: dirName = state.appdata with knownNodesLock: @@ -90,6 +91,7 @@ def saveKnownNodes(dirName=None): def addKnownNode(stream, peer, lastseen=None, is_self=False): + """Add a new node to the dict""" knownNodes[stream][peer] = { "lastseen": lastseen or time.time(), "rating": 1 if is_self else 0, @@ -98,6 +100,7 @@ def addKnownNode(stream, peer, lastseen=None, is_self=False): def createDefaultKnownNodes(): + """Creating default Knownnodes""" past = time.time() - 2418600 # 28 days - 10 min for peer in DEFAULT_NODES: addKnownNode(1, peer, past) @@ -105,6 +108,7 @@ def createDefaultKnownNodes(): def readKnownNodes(): + """Load knownnodes from filesystem""" try: with open(state.appdata + 'knownnodes.dat', 'rb') as source: with knownNodesLock: @@ -131,6 +135,7 @@ def readKnownNodes(): def increaseRating(peer): + """Increase rating of a peer node""" increaseAmount = 0.1 maxRating = 1 with knownNodesLock: @@ -145,6 +150,7 @@ def increaseRating(peer): def decreaseRating(peer): + """Decrease rating of a peer node""" decreaseAmount = 0.1 minRating = -1 with knownNodesLock: @@ -159,6 +165,7 @@ def decreaseRating(peer): def trimKnownNodes(recAddrStream=1): + """Triming Knownnodes""" if len(knownNodes[recAddrStream]) < \ BMConfigParser().safeGetInt("knownnodes", "maxnodes"): return From 1181db66e00ba433c91c85ddf7f7916cc44f45fc Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:52:56 +0530 Subject: [PATCH 190/306] l10n quality fixes --- src/l10n.py | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/l10n.py b/src/l10n.py index d18f4199..bdfb03b3 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -1,4 +1,6 @@ - +""" +Localization +""" import logging import os import time @@ -49,7 +51,7 @@ except: if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): time_format = BMConfigParser().get('bitmessagesettings', 'timeformat') - #Test the format string + # Test the format string try: time.strftime(time_format) except: @@ -58,48 +60,52 @@ if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): else: time_format = DEFAULT_TIME_FORMAT -#It seems some systems lie about the encoding they use so we perform -#comprehensive decoding tests +# It seems some systems lie about the encoding they use so we perform +# comprehensive decoding tests if time_format != DEFAULT_TIME_FORMAT: try: - #Check day names + # Check day names for i in xrange(7): unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)), encoding) - #Check month names + # Check month names for i in xrange(1, 13): unicode(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)), encoding) - #Check AM/PM + # Check AM/PM unicode(time.strftime(time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0)), encoding) unicode(time.strftime(time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0)), encoding) - #Check DST + # Check DST unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1)), encoding) except: logger.exception('Could not decode locale formatted timestamp') time_format = DEFAULT_TIME_FORMAT encoding = DEFAULT_ENCODING + def setlocale(category, newlocale): + """Set the locale""" locale.setlocale(category, newlocale) # it looks like some stuff isn't initialised yet when this is called the # first time and its init gets the locale settings from the environment os.environ["LC_ALL"] = newlocale -def formatTimestamp(timestamp = None, as_unicode = True): - #For some reason some timestamps are strings so we need to sanitize. + +def formatTimestamp(timestamp=None, as_unicode=True): + """Return a formatted timestamp""" + # For some reason some timestamps are strings so we need to sanitize. if timestamp is not None and not isinstance(timestamp, int): try: timestamp = int(timestamp) except: timestamp = None - #timestamp can't be less than 0. + # timestamp can't be less than 0. if timestamp is not None and timestamp < 0: timestamp = None if timestamp is None: timestring = time.strftime(time_format) else: - #In case timestamp is too far in the future + # In case timestamp is too far in the future try: timestring = time.strftime(time_format, time.localtime(timestamp)) except ValueError: @@ -109,17 +115,21 @@ def formatTimestamp(timestamp = None, as_unicode = True): return unicode(timestring, encoding) return timestring + def getTranslationLanguage(): - userlocale = None - if BMConfigParser().has_option('bitmessagesettings', 'userlocale'): - userlocale = BMConfigParser().get('bitmessagesettings', 'userlocale') + """Return the user's language choice""" + userlocale = BMConfigParser().safeGet( + 'bitmessagesettings', 'userlocale', 'system') + return userlocale if userlocale and userlocale != 'system' else language - if userlocale in [None, '', 'system']: - return language - return userlocale - def getWindowsLocale(posixLocale): + """ + Get the Windows locale + Technically this converts the locale string from UNIX to Windows format, + because they use different ones in their + libraries. E.g. "en_EN.UTF-8" to "english". + """ if posixLocale in windowsLanguageMap: return windowsLanguageMap[posixLocale] if "." in posixLocale: From cacac00e21b12d61c55be0dd3cec267bba292222 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:53:23 +0530 Subject: [PATCH 191/306] openclpow quality fixes --- src/openclpow.py | 53 +++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/openclpow.py b/src/openclpow.py index eb91a07f..fad25fa3 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -1,8 +1,9 @@ #!/usr/bin/env python2.7 +""" +Module for Proof of Work using OpenCL +""" from struct import pack, unpack -import time import hashlib -import random import os from bmconfigparser import BMConfigParser @@ -27,6 +28,8 @@ except ImportError: def initCL(): + """Initlialise OpenCL engine""" + # pylint: disable=global-statement global ctx, queue, program, hash_dt, libAvailable if libAvailable is False: return @@ -40,12 +43,13 @@ def initCL(): for platform in cl.get_platforms(): gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) if BMConfigParser().safeGet("bitmessagesettings", "opencl") == platform.vendor: - enabledGpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) + enabledGpus.extend(platform.get_devices( + device_type=cl.device_type.GPU)) if platform.vendor not in vendors: vendors.append(platform.vendor) except: pass - if (len(enabledGpus) > 0): + if enabledGpus: ctx = cl.Context(devices=enabledGpus) queue = cl.CommandQueue(ctx) f = open(os.path.join(paths.codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') @@ -55,23 +59,29 @@ def initCL(): else: logger.info("No OpenCL GPUs found") del enabledGpus[:] - except Exception as e: + except Exception: logger.error("OpenCL fail: ", exc_info=True) del enabledGpus[:] + def openclAvailable(): - return (len(gpus) > 0) + """Are there any OpenCL GPUs available?""" + return bool(gpus) + def openclEnabled(): - return (len(enabledGpus) > 0) + """Is OpenCL enabled (and available)?""" + return bool(enabledGpus) -def do_opencl_pow(hash, target): + +def do_opencl_pow(hash_, target): + """Perform PoW using OpenCL""" output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) - if (len(enabledGpus) == 0): + if not enabledGpus: return output[0][0] data = numpy.zeros(1, dtype=hash_dt, order='C') - data[0]['v'] = ("0000000000000000" + hash).decode("hex") + data[0]['v'] = ("0000000000000000" + hash_).decode("hex") data[0]['target'] = target hash_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=data) @@ -83,9 +93,8 @@ def do_opencl_pow(hash, target): kernel.set_arg(0, hash_buf) kernel.set_arg(1, dest_buf) - start = time.time() progress = 0 - globamt = worksize*2000 + globamt = worksize * 2000 while output[0][0] == 0 and shutdown == 0: kernel.set_arg(2, pack("Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - print "{} - value {} < {}".format(nonce, trialValue, target) - + initCL() + target_ = 54227212183 + initialHash = ("3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590" + "b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3").decode("hex") + nonce = do_opencl_pow(initialHash.encode("hex"), target_) + trialValue, = unpack( + '>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8]) + print "{} - value {} < {}".format(nonce, trialValue, target_) From 27be035e518792f4d38972c55d36ceea8f011c2b Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:53:38 +0530 Subject: [PATCH 192/306] paths quality fixes --- src/paths.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/paths.py b/src/paths.py index ada54c8e..59bc5e42 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,3 +1,6 @@ +""" +Path related functions +""" import logging import os import re @@ -41,7 +44,8 @@ def lookupAppdataFolder(): dataFolder = os.path.join( os.environ['HOME'], 'Library/Application Support/', APPNAME - ) + '/' # FIXME: should also be os.path.sep + ) + '/' + except KeyError: sys.exit( 'Could not find home folder, please report this message' @@ -75,6 +79,7 @@ def codePath(): return os.path.dirname(__file__) return ( os.environ.get('RESOURCEPATH') + # pylint: disable=protected-access if frozen == "macosx_app" else sys._MEIPASS) @@ -91,7 +96,7 @@ def tail(f, lines=20): # from the end of the file blocks = [] while lines_to_go > 0 and block_end_byte > 0: - if (block_end_byte - BLOCK_SIZE > 0): + if block_end_byte - BLOCK_SIZE > 0: # read the last block we haven't yet read f.seek(block_number * BLOCK_SIZE, 2) blocks.append(f.read(BLOCK_SIZE)) From 6f91ba1b33d1ebd469535213b9e680f405054216 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:53:53 +0530 Subject: [PATCH 193/306] shared quality fixes --- src/shared.py | 106 +++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/src/shared.py b/src/shared.py index 6d03bcca..1a2add28 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,21 +1,28 @@ -from __future__ import division +""" +Some shared functions + +.. deprecated:: 0.6.3 + Should be moved to different places and this file removed, + but it needs refactoring. +""" +from __future__ import division # Libraries. +import hashlib import os import sys import stat import threading -import hashlib import subprocess from binascii import hexlify from pyelliptic import arithmetic # Project imports. -import state import highlevelcrypto +import state +from addresses import decodeAddress, encodeVarint from bmconfigparser import BMConfigParser from debug import logger -from addresses import decodeAddress, encodeVarint from helper_sql import sqlQuery @@ -56,6 +63,7 @@ maximumLengthOfTimeToBotherResendingMessages = 0 def isAddressInMyAddressBook(address): + """Is address in my addressbook?""" queryreturn = sqlQuery( '''select address from addressbook where address=?''', address) @@ -64,6 +72,7 @@ def isAddressInMyAddressBook(address): # At this point we should really just have a isAddressInMy(book, address)... def isAddressInMySubscriptionsList(address): + """Am I subscribed to this address?""" queryreturn = sqlQuery( '''select * from subscriptions where address=?''', str(address)) @@ -71,6 +80,7 @@ def isAddressInMySubscriptionsList(address): def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): + """Am I subscribed to this address, is it in my addressbook or whitelist?""" if isAddressInMyAddressBook(address): return True @@ -90,7 +100,8 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return False -def decodeWalletImportFormat(WIFstring): +def decodeWalletImportFormat(WIFstring): # pylint: disable=inconsistent-return-statements + """Convert private key from base58 that's used in the config file to 8-bit binary string""" fullString = arithmetic.changebase(WIFstring, 58, 256) privkey = fullString[:-4] if fullString[-4:] != \ @@ -101,7 +112,7 @@ def decodeWalletImportFormat(WIFstring): ' 6 characters of the PRIVATE key: %s', str(WIFstring)[:6] ) - os._exit(0) + os._exit(0) # pylint: disable=protected-access # return "" elif privkey[0] == '\x80': # checksum passed return privkey[1:] @@ -111,10 +122,11 @@ def decodeWalletImportFormat(WIFstring): ' the checksum passed but the key doesn\'t begin with hex 80.' ' Here is the PRIVATE key: %s', WIFstring ) - os._exit(0) + os._exit(0) # pylint: disable=protected-access def reloadMyAddressHashes(): + """Reinitialise runtime data (e.g. encryption objects, address hashes) from the config file""" logger.debug('reloading keys from keys.dat file') myECCryptorObjects.clear() myAddressesByHash.clear() @@ -128,26 +140,21 @@ def reloadMyAddressHashes(): if isEnabled: hasEnabledKeys = True # status - _, addressVersionNumber, streamNumber, hash = \ - decodeAddress(addressInKeysFile) + addressVersionNumber, streamNumber, hashobj = decodeAddress(addressInKeysFile)[1:] if addressVersionNumber in (2, 3, 4): # Returns a simple 32 bytes of information encoded # in 64 Hex characters, or null if there was an error. privEncryptionKey = hexlify(decodeWalletImportFormat( - BMConfigParser().get(addressInKeysFile, 'privencryptionkey')) - ) - + BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))) # It is 32 bytes encoded as 64 hex characters if len(privEncryptionKey) == 64: - myECCryptorObjects[hash] = \ + myECCryptorObjects[hashobj] = \ highlevelcrypto.makeCryptor(privEncryptionKey) - myAddressesByHash[hash] = addressInKeysFile + myAddressesByHash[hashobj] = addressInKeysFile tag = hashlib.sha512(hashlib.sha512( encodeVarint(addressVersionNumber) + - encodeVarint(streamNumber) + hash).digest() - ).digest()[32:] + encodeVarint(streamNumber) + hashobj).digest()).digest()[32:] myAddressesByTag[tag] = addressInKeysFile - else: logger.error( 'Error in reloadMyAddressHashes: Can\'t handle' @@ -159,6 +166,7 @@ def reloadMyAddressHashes(): def reloadBroadcastSendersForWhichImWatching(): + """Reinitialise runtime data for the broadcasts I'm subscribed to from the config file""" broadcastSendersForWhichImWatching.clear() MyECSubscriptionCryptorObjects.clear() queryreturn = sqlQuery('SELECT address FROM subscriptions where enabled=1') @@ -166,9 +174,9 @@ def reloadBroadcastSendersForWhichImWatching(): for row in queryreturn: address, = row # status - _, addressVersionNumber, streamNumber, hash = decodeAddress(address) + addressVersionNumber, streamNumber, hashobj = decodeAddress(address)[1:] if addressVersionNumber == 2: - broadcastSendersForWhichImWatching[hash] = 0 + broadcastSendersForWhichImWatching[hashobj] = 0 # Now, for all addresses, even version 2 addresses, # we should create Cryptor objects in a dictionary which we will # use to attempt to decrypt encrypted broadcast messages. @@ -176,14 +184,14 @@ def reloadBroadcastSendersForWhichImWatching(): if addressVersionNumber <= 3: privEncryptionKey = hashlib.sha512( encodeVarint(addressVersionNumber) + - encodeVarint(streamNumber) + hash + encodeVarint(streamNumber) + hashobj ).digest()[:32] - MyECSubscriptionCryptorObjects[hash] = \ + MyECSubscriptionCryptorObjects[hashobj] = \ highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) else: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512( encodeVarint(addressVersionNumber) + - encodeVarint(streamNumber) + hash + encodeVarint(streamNumber) + hashobj ).digest()).digest() tag = doubleHashOfAddressData[32:] privEncryptionKey = doubleHashOfAddressData[:32] @@ -192,21 +200,22 @@ def reloadBroadcastSendersForWhichImWatching(): def fixPotentiallyInvalidUTF8Data(text): + """Sanitise invalid UTF-8 strings""" try: unicode(text, 'utf-8') return text except: return 'Part of the message is corrupt. The message cannot be' \ - ' displayed the normal way.\n\n' + repr(text) + ' displayed the normal way.\n\n' + repr(text) -# Checks sensitive file permissions for inappropriate umask -# during keys.dat creation. (Or unwise subsequent chmod.) -# -# Returns true iff file appears to have appropriate permissions. def checkSensitiveFilePermissions(filename): + """ + :param str filename: path to the file + :return: True if file appears to have appropriate permissions. + """ if sys.platform == 'win32': - # TODO: This might deserve extra checks by someone familiar with + # .. todo:: This might deserve extra checks by someone familiar with # Windows systems. return True elif sys.platform[:7] == 'freebsd': @@ -214,30 +223,30 @@ def checkSensitiveFilePermissions(filename): present_permissions = os.stat(filename)[0] disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO return present_permissions & disallowed_permissions == 0 - else: - try: - # Skip known problems for non-Win32 filesystems - # without POSIX permissions. - fstype = subprocess.check_output( - 'stat -f -c "%%T" %s' % (filename), - shell=True, - stderr=subprocess.STDOUT - ) - if 'fuseblk' in fstype: - logger.info( - 'Skipping file permissions check for %s.' - ' Filesystem fuseblk detected.', filename) - return True - except: - # Swallow exception here, but we might run into trouble later! - logger.error('Could not determine filesystem type. %s', filename) - present_permissions = os.stat(filename)[0] - disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO - return present_permissions & disallowed_permissions == 0 + try: + # Skip known problems for non-Win32 filesystems + # without POSIX permissions. + fstype = subprocess.check_output( + 'stat -f -c "%%T" %s' % (filename), + shell=True, + stderr=subprocess.STDOUT + ) + if 'fuseblk' in fstype: + logger.info( + 'Skipping file permissions check for %s.' + ' Filesystem fuseblk detected.', filename) + return True + except: + # Swallow exception here, but we might run into trouble later! + logger.error('Could not determine filesystem type. %s', filename) + present_permissions = os.stat(filename)[0] + disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO + return present_permissions & disallowed_permissions == 0 # Fixes permissions on a sensitive file. def fixSensitiveFilePermissions(filename, hasEnabledKeys): + """Try to change file permissions to be more restrictive""" if hasEnabledKeys: logger.warning( 'Keyfile had insecure permissions, and there were enabled' @@ -262,6 +271,7 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys): def openKeysFile(): + """Open keys file with an external editor""" if 'linux' in sys.platform: subprocess.call(["xdg-open", state.appdata + 'keys.dat']) else: From 503d0b33d074cf09d928d945cfff5c89ac9dd7d4 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:54:04 +0530 Subject: [PATCH 194/306] shutdown quality fixes --- src/shutdown.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shutdown.py b/src/shutdown.py index 85d11d67..1d40a90f 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -1,3 +1,4 @@ +"""shutdown function""" import os import Queue import threading @@ -15,8 +16,7 @@ from queues import ( def doCleanShutdown(): - # Used to tell proof of work worker threads - # and the objectProcessorThread to exit. + """Used to tell proof of work worker threads and the objectProcessorThread to exit.""" state.shutdown = 1 objectProcessorQueue.put(('checkShutdownVariable', 'no data')) @@ -53,7 +53,7 @@ def doCleanShutdown(): for thread in threading.enumerate(): if (thread is not threading.currentThread() and - isinstance(thread, StoppableThread) and + isinstance(thread, StoppableThread) and thread.name != 'SQL'): logger.debug("Waiting for thread %s", thread.name) thread.join() @@ -76,10 +76,10 @@ def doCleanShutdown(): except Queue.Empty: break - if shared.thisapp.daemon or not state.enableGUI: # FIXME redundant? + if shared.thisapp.daemon or not state.enableGUI: # ..fixme:: redundant? logger.info('Clean shutdown complete.') shared.thisapp.cleanup() - os._exit(0) + os._exit(0) # pylint: disable=protected-access else: logger.info('Core shutdown complete.') for thread in threading.enumerate(): From b9ad6a3bac4b0ec05822e3ff6b4c9790e23570fc Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:54:20 +0530 Subject: [PATCH 195/306] singleinstance quality fixes --- src/singleinstance.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index 03bda504..d0a0871c 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -16,7 +16,7 @@ except ImportError: pass -class singleinstance: +class singleinstance(object): """ Implements a single instance application by creating a lock file at appdata. @@ -40,6 +40,7 @@ class singleinstance: atexit.register(self.cleanup) def lock(self): + """Obtain single instance lock""" if self.lockPid is None: self.lockPid = os.getpid() if sys.platform == 'win32': @@ -52,8 +53,7 @@ class singleinstance: self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR | os.O_TRUNC ) - except OSError: - type, e, tb = sys.exc_info() + except OSError as e: if e.errno == 13: print( 'Another instance of this application' @@ -84,6 +84,7 @@ class singleinstance: self.fp.flush() def cleanup(self): + """Release single instance lock""" if not self.initialized: return if self.daemon and self.lockPid == os.getpid(): @@ -94,7 +95,7 @@ class singleinstance: os.close(self.fd) else: fcntl.lockf(self.fp, fcntl.LOCK_UN) - except Exception, e: + except Exception: pass return From fda5d23c2d93e23f5ef14c63ab539a37cba74702 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:54:37 +0530 Subject: [PATCH 196/306] state quality fixes --- src/state.py | 56 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/state.py b/src/state.py index 3e051edf..a3b930ab 100644 --- a/src/state.py +++ b/src/state.py @@ -1,30 +1,42 @@ +""" +Global runtime variables. +""" import collections neededPubkeys = {} streamsInWhichIAmParticipating = [] -# For UPnP extPort = None +"""For UPnP""" -# for Tor hidden service socksIP = None +"""for Tor hidden service""" -appdata = '' # holds the location of the application data storage directory +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 +""" + Set to 1 by the doCleanShutdown function. + Used to tell the proof of work worker threads to exit. +""" # 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 +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 +sqlReady = False +"""set to true by sqlTread when ready for processing""" maximumNumberOfHalfOpenConnections = 0 @@ -35,17 +47,19 @@ 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 +""" + 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. +""" discoveredPeers = {} From 58e5fac6d724b1bd65dbebe76ad093379fb39b34 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 22 Oct 2019 19:54:52 +0530 Subject: [PATCH 197/306] tr quality fixes --- src/tr.py | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/tr.py b/src/tr.py index 8b41167f..87e67219 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,22 +1,36 @@ +""" +Translating text +""" import os import state -# This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions. + class translateClass: + """ + This is used so that the translateText function can be used + when we are in daemon mode and not using any QT functions. + """ + # pylint: disable=old-style-class,too-few-public-methods def __init__(self, context, text): self.context = context self.text = text - def arg(self,argument): - if '%' in self.text: - return translateClass(self.context, self.text.replace('%','',1)) # This doesn't actually do anything with the arguments because we don't have a UI in which to display this information anyway. - else: - return self.text -def _translate(context, text, disambiguation = None, encoding = None, n = None): + def arg(self, _): + """Replace argument placeholders""" + if '%' in self.text: + # This doesn't actually do anything with the arguments + # because we don't have a UI in which to display this information anyway. + return translateClass(self.context, self.text.replace('%', '', 1)) + return self.text + + +def _translate(context, text, disambiguation=None, encoding=None, n=None): # pylint: disable=unused-argument return translateText(context, text, n) -def translateText(context, text, n = None): + +def translateText(context, text, n=None): + """Translate text in context""" try: enableGUI = state.enableGUI except AttributeError: # inside the plugin @@ -25,15 +39,17 @@ def translateText(context, text, n = None): try: from PyQt4 import QtCore, QtGui except Exception as err: - print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' + print 'PyBitmessage requires PyQt unless you want to run it as a daemon'\ + ' and interact with it using the API.'\ + ' You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download'\ + ' or by searching Google for \'PyQt Download\'.'\ + ' If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' print 'Error message:', err - os._exit(0) + os._exit(0) # pylint: disable=protected-access if n is None: return QtGui.QApplication.translate(context, text) - else: - return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) + return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) else: if '%' in text: - return translateClass(context, text.replace('%','',1)) - else: - return text + return translateClass(context, text.replace('%', '', 1)) + return text From d3cbe45608ac8b31977e9d6e6b20accbb36af4a0 Mon Sep 17 00:00:00 2001 From: navjot Date: Thu, 31 Oct 2019 16:24:18 +0530 Subject: [PATCH 198/306] worked on implementing loader popup functionality on account switching --- src/bitmessagekivy/main.kv | 17 ++++++- src/bitmessagekivy/mpybit.py | 95 +++++++++++++++++++++-------------- src/buildozer.spec | 2 +- src/images/3.zip | Bin 0 -> 3043 bytes src/images/loader.gif | Bin 0 -> 13527 bytes src/images/loader.zip | Bin 0 -> 15918 bytes 6 files changed, 75 insertions(+), 39 deletions(-) create mode 100644 src/images/3.zip create mode 100644 src/images/loader.gif create mode 100644 src/images/loader.zip diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 759bd71c..48c7d889 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -14,6 +14,7 @@ #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory #:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout +#:import MDSpinner kivymd.spinner.MDSpinner #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -29,7 +30,7 @@ color: color_font : - drawer_logo: app.address_identicon() + drawer_logo: './images/drawer_logo1.png' NavigationDrawerDivider: NavigationDrawerSubheader: text: "Accounts" @@ -1204,3 +1205,17 @@ NavigationLayout: id: search_field hint_text: 'Search' on_text: app.searchQuery(self) + + +: + separator_color: 1, 1, 1, 1 + background: "White.png" + Button: + id: btn + disabled: True + background_disabled_normal: "White.png" + Image: + source: './images/loader.zip' + anim_delay: 0 + #mipmap: True + size: root.size \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 7270514b..14ea7e8f 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1026,10 +1026,25 @@ class NavigateApp(App): self.root_window.children[1].ids.toolbar.title = address_label state.association = text state.searcing_text = '' + LoadingPopup().open() 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[1].children[1].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.scr_mngr.current = 'inbox' - msg_counter_objs = self.root_window.children[1].children[2].children[0].ids + msg_counter_objs = self.root_window.children[2].children[2].children[0].ids state.sent_count = str( sqlQuery( "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" @@ -1224,37 +1239,37 @@ class NavigateApp(App): def refreshScreen(self, instance): """Method show search button only on inbox or sent screen.""" state.searcing_text = '' - if instance.text == 'Sent': - self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' - self.root.ids.sc4.loadSent(state.association) - elif instance.text == 'Inbox': - self.root.ids.sc1.ids.ml.clear_widgets() - try: - self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc1.children[1].children[1].ids.search_field.text = '' - self.root.ids.sc1.loadMessagelist(state.association) - elif instance.text == 'Draft': - self.root.ids.sc16.clear_widgets() - self.root.ids.sc16.add_widget(Draft()) - elif instance.text == 'Trash': - self.root.ids.sc5.clear_widgets() - self.root.ids.sc5.add_widget(Trash()) - elif instance.text == 'All Mails': - self.root.ids.sc17.clear_widgets() - self.root.ids.sc17.add_widget(Allmails()) - elif instance.text == 'Address Book': - self.root.ids.sc11.ids.ml.clear_widgets() - self.root.ids.sc11.children[1].children[1].ids.search_field.text = '' - self.root.ids.sc11.loadAddresslist(None, 'All', '') - elif instance.text == 'My Addresses': - self.root.ids.sc10.ids.ml.clear_widgets() - try: - self.root.ids.sc10.children[1].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' - self.root.ids.sc10.init_ui() + # if instance.text == 'Sent': + # self.root.ids.sc4.ids.ml.clear_widgets() + # self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' + # self.root.ids.sc4.loadSent(state.association) + # elif instance.text == 'Inbox': + # self.root.ids.sc1.ids.ml.clear_widgets() + # try: + # self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' + # except Exception: + # self.root.ids.sc1.children[1].children[1].ids.search_field.text = '' + # self.root.ids.sc1.loadMessagelist(state.association) + # elif instance.text == 'Draft': + # self.root.ids.sc16.clear_widgets() + # self.root.ids.sc16.add_widget(Draft()) + # elif instance.text == 'Trash': + # self.root.ids.sc5.clear_widgets() + # self.root.ids.sc5.add_widget(Trash()) + # elif instance.text == 'All Mails': + # self.root.ids.sc17.clear_widgets() + # self.root.ids.sc17.add_widget(Allmails()) + # elif instance.text == 'Address Book': + # self.root.ids.sc11.ids.ml.clear_widgets() + # self.root.ids.sc11.children[1].children[1].ids.search_field.text = '' + # self.root.ids.sc11.loadAddresslist(None, 'All', '') + # elif instance.text == 'My Addresses': + # self.root.ids.sc10.ids.ml.clear_widgets() + # try: + # self.root.ids.sc10.children[1].children[1].ids.search_field.text = '' + # except Exception: + # self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' + # self.root.ids.sc10.init_ui() return def set_identicon(self, text): @@ -1262,11 +1277,6 @@ class NavigateApp(App): img = identiconGeneration.generate(text) self.root.children[2].children[0].ids.btn.children[1].texture = img.texture - @staticmethod - def address_identicon(): - """Address identicon""" - return './images/drawer_logo1.png' - def set_mail_detail_header(self): """Method is used for setting the details of the page""" toolbar_obj = self.root.ids.toolbar @@ -1966,3 +1976,14 @@ class Spam(Screen): """Spam Screen show widgets of page.""" pass + + +class LoadingPopup(Popup): + + 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, dt): + self.dismiss() \ No newline at end of file diff --git a/src/buildozer.spec b/src/buildozer.spec index 444bf8ca..0dfeb191 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -13,7 +13,7 @@ package.domain = org.test source.dir = . # (list) Source files to include (let empty to include all the files) -source.include_exts = py,png,jpg,kv,atlas +source.include_exts = py,png,jpg,kv,atlas,gif,zip # (list) List of inclusions using pattern matching #source.include_patterns = assets/*,images/*.png diff --git a/src/images/3.zip b/src/images/3.zip new file mode 100644 index 0000000000000000000000000000000000000000..34d555fed251e96b6493497f61d8078c8cb68b5c GIT binary patch literal 3043 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 literal 0 HcmV?d00001 diff --git a/src/images/loader.gif b/src/images/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..29064d5795d97c6c88cf5ef5332461e8e2b312dc GIT binary patch literal 13527 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

da1Z@@=)C#bc5oIsGy)A7 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%0Axy_!V``!*DX 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 BLgN4c literal 0 HcmV?d00001 diff --git a/src/images/loader.zip b/src/images/loader.zip new file mode 100644 index 0000000000000000000000000000000000000000..c80a3a17e22d05832db089959679ec1c995e0cb9 GIT binary patch literal 15918 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 K`X3bl!2bc@Mkc@j literal 0 HcmV?d00001 From fc347c3731eb6d5b764d2d4ce55445803e7f3b74 Mon Sep 17 00:00:00 2001 From: navjot Date: Mon, 4 Nov 2019 21:57:53 +0530 Subject: [PATCH 199/306] worked on new address creation time loader functionality --- src/bitmessagekivy/main.kv | 31 ++++------ src/bitmessagekivy/mpybit.py | 114 +++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 65 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 48c7d889..63a7e009 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -58,52 +58,44 @@ text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: draft_cnt icon: 'message-draw' text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Starred" icon:'star' on_release: app.root.ids.scr_mngr.current = 'starred' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: icon: 'archive' text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'archieve' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: icon: 'email-open-outline' text: "Spam" on_release: app.root.ids.scr_mngr.current = 'spam' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerIconButton: id: allmail_cnt text: "All Mails" icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'allmails' badge_text: "0" - on_press: app.refreshScreen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -111,37 +103,30 @@ text: "Address Book" icon:'book-multiple' on_release: app.root.ids.scr_mngr.current = 'addressbook' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Settings" icon:'settings' on_release: app.root.ids.scr_mngr.current = 'set' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Subscriptions/Payment" icon:'bell' on_release: app.root.ids.scr_mngr.current = 'payment' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Credits" icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'credits' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "new address" icon:'account-plus' on_release: app.root.ids.scr_mngr.current = 'login' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "Network Status" icon:'server-network' on_release: app.root.ids.scr_mngr.current = 'networkstat' - on_press: app.refreshScreen(self) NavigationDrawerIconButton: text: "My Addresses" icon:'account-multiple' on_release: app.root.ids.scr_mngr.current = 'myaddress' - on_press: app.refreshScreen(self) NavigationLayout: id: nav_layout @@ -179,7 +164,7 @@ NavigationLayout: id:sc6 Random: id:sc7 - AddressSuccessful: + Spam: id:sc8 Setting: id:sc9 @@ -205,8 +190,6 @@ NavigationLayout: id:sc19 Archieve: id:sc20 - Spam: - id:sc21 : name: 'inbox' @@ -221,6 +204,7 @@ NavigationLayout: root_layout: root MDList: id: ml + Loader: ComposerButton: : @@ -626,6 +610,7 @@ NavigationLayout: root_layout: root MDList: id: ml + Loader: ComposerButton: : @@ -1218,4 +1203,12 @@ NavigationLayout: source: './images/loader.zip' anim_delay: 0 #mipmap: True - size: root.size \ No newline at end of file + size: root.size + + +: + id: spinner + size_hint: None, None + size: dp(46), dp(46) + pos_hint: {'center_x': 0.5, 'center_y': 0.5} + active: False \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 14ea7e8f..ec2a9f74 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -228,7 +228,7 @@ class Inbox(Screen): def refresh_callback(interval): """Method used for loading the inbox screen data.""" state.searcing_text = '' - self.children[2].children[1].ids.search_field.text = '' + self.children[3].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() self.loadMessagelist(state.association) self.ids.refresh_layout.refresh_done() @@ -301,7 +301,8 @@ class MyAddress(Screen): def refresh_callback(interval): """Method used for loading the myaddress screen data.""" state.searcing_text = '' - self.children[2].children[1].ids.search_field.text = '' + state.kivyapp.root.ids.sc10.children[2].active = False + self.children[3].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() self.init_ui() self.ids.refresh_layout.refresh_done() @@ -462,6 +463,7 @@ class DropDownWidget(BoxLayout): sendMessageToPeople = True if sendMessageToPeople: if toAddress != '' and subject and message: + # navApp.root.ids.sc1.children[1].active = True from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) if status == 'success': @@ -527,6 +529,7 @@ class DropDownWidget(BoxLayout): queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" self.parent.parent.current = 'inbox' + # navApp.root.ids.sc1.children[1].active = False state.in_composer = True navApp.back_press() toast('send') @@ -689,6 +692,7 @@ class Random(Screen): nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 if str(self.ids.label.text).strip(): + toast('Address Creating...') queues.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, @@ -699,16 +703,15 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False self.parent.parent.parent.parent.ids.sc10.ids.ml.clear_widgets() + self.parent.parent.parent.parent.ids.sc10.children[1].active = True self.manager.current = 'myaddress' - self.parent.parent.parent.parent.ids.sc10.init_ui() - self.manager.current = 'myaddress' - toast('New address created') + Clock.schedule_once(self.address_created_callback, 10) - -class AddressSuccessful(Screen): - """Getting Address Detail.""" - - pass + def address_created_callback(self, dt=0): + state.kivyapp.root.ids.sc10.children[1].active = False + state.kivyapp.root.ids.sc10.init_ui() + self.manager.current = 'myaddress' + toast('New address created') class Sent(Screen): @@ -1147,6 +1150,20 @@ class NavigateApp(App): 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 platform == 'android': + if state.search_screen == 'inbox': + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) + elif state.search_screen == 'addressbook': + self.root.ids.sc11.ids.ml.clear_widgets() + self.root.ids.sc11.loadAddresslist(None, 'All', '') + elif state.search_screen == 'myaddress': + self.root.ids.sc10.ids.ml.clear_widgets() + self.root.ids.sc10.init_ui() + else: + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.loadSent(state.association) + self.root.ids.scr_mngr.current = state.search_screen def reset(self, *args): """Method used to set transition direction.""" @@ -1222,54 +1239,59 @@ class NavigateApp(App): """Method used for 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 = [['close', lambda x: self.closeSearchScreen()]] + toolbar_obj.right_action_items = [] + self.root.ids.toolbar.title = '' + if platform == 'linux': + if state.search_screen == 'inbox': + self.root.ids.sc1.ids.ml.clear_widgets() + self.root.ids.sc1.loadMessagelist(state.association) + elif state.search_screen == 'addressbook': + self.root.ids.sc11.ids.ml.clear_widgets() + self.root.ids.sc11.loadAddresslist(None, 'All', '') + elif state.search_screen == 'myaddress': + self.root.ids.sc10.ids.ml.clear_widgets() + self.root.ids.sc10.init_ui() + else: + self.root.ids.sc4.ids.ml.clear_widgets() + self.root.ids.sc4.loadSent(state.association) + self.root.ids.scr_mngr.current = state.search_screen + + def closeSearchScreen(self): + 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()]] + address_label = self.current_address_label( + BMConfigParser().get(state.association, 'label'), state.association) + self.root.ids.toolbar.title = address_label + self.refreshScreen() + + def refreshScreen(self): + """Method show search button only on inbox or sent screen.""" + state.searcing_text = '' if state.search_screen == 'inbox': + try: + self.root.ids.sc1.children[3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' self.root.ids.sc1.ids.ml.clear_widgets() self.root.ids.sc1.loadMessagelist(state.association) elif state.search_screen == 'addressbook': + self.root.ids.sc11.children[1].children[1].ids.search_field.text = '' self.root.ids.sc11.ids.ml.clear_widgets() self.root.ids.sc11.loadAddresslist(None, 'All', '') elif state.search_screen == 'myaddress': + try: + self.root.ids.sc10.children[3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' self.root.ids.sc10.ids.ml.clear_widgets() self.root.ids.sc10.init_ui() else: + self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' self.root.ids.sc4.ids.ml.clear_widgets() self.root.ids.sc4.loadSent(state.association) - self.root.ids.scr_mngr.current = state.search_screen - - def refreshScreen(self, instance): - """Method show search button only on inbox or sent screen.""" - state.searcing_text = '' - # if instance.text == 'Sent': - # self.root.ids.sc4.ids.ml.clear_widgets() - # self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' - # self.root.ids.sc4.loadSent(state.association) - # elif instance.text == 'Inbox': - # self.root.ids.sc1.ids.ml.clear_widgets() - # try: - # self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' - # except Exception: - # self.root.ids.sc1.children[1].children[1].ids.search_field.text = '' - # self.root.ids.sc1.loadMessagelist(state.association) - # elif instance.text == 'Draft': - # self.root.ids.sc16.clear_widgets() - # self.root.ids.sc16.add_widget(Draft()) - # elif instance.text == 'Trash': - # self.root.ids.sc5.clear_widgets() - # self.root.ids.sc5.add_widget(Trash()) - # elif instance.text == 'All Mails': - # self.root.ids.sc17.clear_widgets() - # self.root.ids.sc17.add_widget(Allmails()) - # elif instance.text == 'Address Book': - # self.root.ids.sc11.ids.ml.clear_widgets() - # self.root.ids.sc11.children[1].children[1].ids.search_field.text = '' - # self.root.ids.sc11.loadAddresslist(None, 'All', '') - # elif instance.text == 'My Addresses': - # self.root.ids.sc10.ids.ml.clear_widgets() - # try: - # self.root.ids.sc10.children[1].children[1].ids.search_field.text = '' - # except Exception: - # self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' - # self.root.ids.sc10.init_ui() return def set_identicon(self, text): From d22c241d70f3c1fc33f0f867122ca9d514550fb0 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 6 Nov 2019 19:34:22 +0530 Subject: [PATCH 200/306] mpybit quality fix --- src/bitmessagekivy/mpybit.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ec2a9f74..71059bd0 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -36,6 +36,7 @@ from kivy.uix.screenmanager import Screen from kivy.uix.spinner import Spinner from kivy.uix.textinput import TextInput from kivy.utils import platform + import kivy_helper_search from kivymd.button import MDIconButton from kivymd.dialog import MDDialog @@ -53,8 +54,10 @@ from kivymd.navigationdrawer import ( ) from kivymd.selectioncontrols import MDCheckbox from kivymd.theming import ThemeManager + import queues from semaphores import kivyuisignaler + import state from uikivysignaler import UIkivySignaler @@ -708,6 +711,7 @@ class Random(Screen): Clock.schedule_once(self.address_created_callback, 10) def address_created_callback(self, dt=0): + """New address created""" state.kivyapp.root.ids.sc10.children[1].active = False state.kivyapp.root.ids.sc10.init_ui() self.manager.current = 'myaddress' @@ -1260,6 +1264,7 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = state.search_screen def closeSearchScreen(self): + """Function for close search screen""" 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()]] address_label = self.current_address_label( @@ -2001,11 +2006,12 @@ class Spam(Screen): class LoadingPopup(Popup): - + """Load Popup""" 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, dt): - self.dismiss() \ No newline at end of file + """Dismissing popup""" + self.dismiss() From 63a7f1024401cf05b3e5ad7202a89226828c2594 Mon Sep 17 00:00:00 2001 From: navjot Date: Fri, 8 Nov 2019 17:38:26 +0530 Subject: [PATCH 201/306] worked on fixing kivy app crashing issues --- src/bitmessagekivy/kivy_helper_search.py | 2 +- src/bitmessagekivy/main.kv | 119 ++++++++++++----------- src/bitmessagekivy/mpybit.py | 118 +++++++++++++--------- src/state.py | 2 + 4 files changed, 138 insertions(+), 103 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index a1fe4a99..16767fce 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -58,7 +58,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementParts.append("read = 0") if sqlStatementParts: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) - if folder == "sent": + if folder == "sent" or folder == "draft": sqlStatementBase += " ORDER BY lastactiontime DESC" elif folder == "inbox": sqlStatementBase += " ORDER BY received DESC" diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 63a7e009..050caf52 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -134,62 +134,64 @@ NavigationLayout: ContentNavigationDrawer: id: nav_drawer - BoxLayout: - id: box_layout - orientation: 'vertical' - Toolbar: - id: toolbar - title: app.current_address_label() - opacity: 1 if app.addressexist() else 0 - disabled: False if app.addressexist() else True - md_bg_color: app.theme_cls.primary_color - background_palette: 'Primary' - background_hue: '500' - left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] - right_action_items: [['account-plus', lambda x: app.addingtoaddressbook()]] + FloatLayout: + id: float_box + BoxLayout: + id: box_layout + orientation: 'vertical' + Toolbar: + id: toolbar + title: app.current_address_label() + opacity: 1 if app.addressexist() else 0 + disabled: False if app.addressexist() else True + md_bg_color: app.theme_cls.primary_color + background_palette: 'Primary' + background_hue: '500' + left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] + right_action_items: [['account-plus', lambda x: app.addingtoaddressbook()]] - ScreenManager: - id: scr_mngr - 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 + ScreenManager: + id: scr_mngr + 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 : name: 'inbox' @@ -201,7 +203,7 @@ NavigationLayout: MDScrollViewRefreshLayout: id: refresh_layout refresh_callback: root.refresh_callback - root_layout: root + root_layout: root.set_root_layout() MDList: id: ml Loader: @@ -266,7 +268,7 @@ NavigationLayout: MDScrollViewRefreshLayout: id: refresh_layout refresh_callback: root.refresh_callback - root_layout: root + root_layout: root.set_root_layout() MDList: id: ml ComposerButton: @@ -285,6 +287,7 @@ NavigationLayout: : name: 'create' + Loader: : name: 'credits' @@ -607,7 +610,7 @@ NavigationLayout: MDScrollViewRefreshLayout: id: refresh_layout refresh_callback: root.refresh_callback - root_layout: root + root_layout: root.set_root_layout() MDList: id: ml Loader: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 71059bd0..f861971a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -231,7 +231,7 @@ class Inbox(Screen): def refresh_callback(interval): """Method used for loading the inbox screen data.""" state.searcing_text = '' - self.children[3].children[1].ids.search_field.text = '' + self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() self.loadMessagelist(state.association) self.ids.refresh_layout.refresh_done() @@ -239,6 +239,9 @@ class Inbox(Screen): Clock.schedule_once(refresh_callback, 1) + def set_root_layout(self): + return self.parent.parent.parent + class MyAddress(Screen): """MyAddress Screen uses screen to show widgets of screens.""" @@ -305,7 +308,7 @@ class MyAddress(Screen): """Method used for loading the myaddress screen data.""" state.searcing_text = '' state.kivyapp.root.ids.sc10.children[2].active = False - self.children[3].children[1].ids.search_field.text = '' + self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() self.init_ui() self.ids.refresh_layout.refresh_done() @@ -322,6 +325,9 @@ class MyAddress(Screen): return True return False + def set_root_layout(self): + return self.manager.parent.parent + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -466,10 +472,10 @@ class DropDownWidget(BoxLayout): sendMessageToPeople = True if sendMessageToPeople: if toAddress != '' and subject and message: - # navApp.root.ids.sc1.children[1].active = True from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) if status == 'success': + navApp.root.ids.sc3.children[0].active = True if state.detailPageType == 'draft' and state.send_draft_mail: sqlExecute( "UPDATE sent SET toaddress = ?" @@ -521,22 +527,23 @@ class DropDownWidget(BoxLayout): BMConfigParser().getint( 'bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress + # state.msg_counter_objs = self.parent.parent.parent.parent\ + # .parent.parent.children[0].children[2].children[0].ids state.msg_counter_objs = self.parent.parent.parent.parent\ - .parent.parent.children[0].children[2].children[0].ids + .parent.parent.children[2].children[0].ids + self.parent.parent.screens[0].ids.ml.clear_widgets() + self.parent.parent.screens[0].loadMessagelist(state.association) self.parent.parent.screens[3].ids.ml.clear_widgets() self.parent.parent.screens[3].loadSent(state.association) self.parent.parent.screens[16].clear_widgets() self.parent.parent.screens[16].add_widget(Allmails()) + toast('sending...') + Clock.schedule_once(self.callback_for_msgsend, 6) toLabel = '' - queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" - self.parent.parent.current = 'inbox' - # navApp.root.ids.sc1.children[1].active = False state.in_composer = True - navApp.back_press() - toast('send') - return None + return else: msg = 'Enter a valid recipients address' elif not toAddress: @@ -545,6 +552,12 @@ class DropDownWidget(BoxLayout): msg = 'Please fill the form' self.address_error_message(msg) + def callback_for_msgsend(self, dt=0): + state.kivyapp.root.ids.sc3.children[0].active = False + state.in_sent_method = True + state.kivyapp.back_press() + toast('sent') + # pylint: disable=attribute-defined-outside-init def address_error_message(self, msg): """Show Error Message.""" @@ -703,16 +716,16 @@ class Random(Screen): nonceTrialsPerByte, payloadLengthExtraBytes)) self.ids.label.text = '' - self.parent.parent.parent.parent.ids.toolbar.opacity = 1 - self.parent.parent.parent.parent.ids.toolbar.disabled = False - self.parent.parent.parent.parent.ids.sc10.ids.ml.clear_widgets() - self.parent.parent.parent.parent.ids.sc10.children[1].active = True + self.parent.parent.children[1].opacity = 1 + self.parent.parent.children[1].disabled = False + state.kivyapp.root.ids.sc10.children[1].active = True self.manager.current = 'myaddress' - Clock.schedule_once(self.address_created_callback, 10) + Clock.schedule_once(self.address_created_callback, 6) def address_created_callback(self, dt=0): """New address created""" state.kivyapp.root.ids.sc10.children[1].active = False + state.kivyapp.root.ids.sc10.ids.ml.clear_widgets() state.kivyapp.root.ids.sc10.init_ui() self.manager.current = 'myaddress' toast('New address created') @@ -1138,13 +1151,10 @@ class NavigateApp(App): if state.detailPageType == 'inbox' else 'draft' self.back_press() elif self.root.ids.scr_mngr.current == "create": - composer_objs = self.root - from_addr = str(self.root.ids.sc3.children[0].ids.ti.text) - to_addr = str(self.root.ids.sc3.children[0].ids.txt_input.text) - if from_addr and to_addr and state.detailPageType != 'draft': - Draft().draft_msg(composer_objs) + self.save_draft() + self.set_common_header() + state.in_composer = False self.root.ids.scr_mngr.current = 'inbox' - self.back_press() elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' elif self.root.ids.scr_mngr.current == "random": @@ -1169,6 +1179,14 @@ class NavigateApp(App): self.root.ids.sc4.loadSent(state.association) self.root.ids.scr_mngr.current = state.search_screen + def save_draft(self): + 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 to_addr and state.detailPageType != 'draft' and not state.in_sent_method: + Draft().draft_msg(composer_objs) + return + def reset(self, *args): """Method used to set transition direction.""" self.root.ids.scr_mngr.transition.direction = 'left' @@ -1185,26 +1203,32 @@ class NavigateApp(App): """If slow down the nwe will make new composer edit screen.""" self.set_navbar_for_composer() # self.root.ids.search_bar.clear_widgets() - composer_obj = self.root.ids.sc3.children[0].ids + 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): """This method is used for 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[0].reset_composer()], - ['send', lambda x: self.root.ids.sc3.children[0].send(self)]] + ['refresh', lambda x: self.root.ids.sc3.children[1].reset_composer()], + ['send', lambda x: self.root.ids.sc3.children[1].send(self)]] + + def set_common_header(self): + 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()]] + return def back_press(self): """Method used for going back from composer to previous page.""" - 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.save_draft() + self.set_common_header() self.root.ids.scr_mngr.current = 'inbox' \ if state.in_composer else 'allmails'\ if state.is_allmail else state.detailPageType\ @@ -1265,8 +1289,7 @@ class NavigateApp(App): def closeSearchScreen(self): """Function for close search screen""" - 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.set_common_header() address_label = self.current_address_label( BMConfigParser().get(state.association, 'label'), state.association) self.root.ids.toolbar.title = address_label @@ -1538,13 +1561,13 @@ class MailDetail(Screen): data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where" " msgid = ?;", str(state.mail_id)) - composer_obj = self.parent.screens[2].children[0].ids + composer_obj = self.parent.screens[2].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] composer_obj.subject.text = data[0][2] composer_obj.body.text = '' - state.kivyapp.root.ids.sc3.children[0].ids.rv.data = '' + state.kivyapp.root.ids.sc3.children[1].ids.rv.data = '' self.parent.current = 'create' state.kivyapp.set_navbar_for_composer() @@ -1555,11 +1578,11 @@ class MailDetail(Screen): def write_msg(self, navApp): """Method used to write on draft mail.""" state.send_draft_mail = state.mail_id - composer_ids = self.parent.parent.parent.parent.ids.sc3.children[0].ids + composer_ids = self.parent.parent.parent.parent.parent.ids.sc3.children[1].ids composer_ids.ti.text = state.write_msg['from_addr'] composer_ids.btn.text = state.write_msg['from_addr'] composer_ids.txt_input.text = state.write_msg['to_addr'] - composer_ids.subject.text = state.write_msg['subject'] + composer_ids.subject.text = state.write_msg['subject'] if state.write_msg['subject'] != '(no subject)' else '' composer_ids.body.text = state.write_msg['message'] self.parent.current = 'create' navApp.set_navbar_for_composer() @@ -1593,12 +1616,13 @@ class MyaddDetailPopup(Popup): def send_message_from(self): """Method used to fill from address of composer autofield.""" + state.kivyapp.set_navbar_for_composer() window_obj = self.parent.children[1].ids - window_obj.sc3.children[0].ids.ti.text = self.address - window_obj.sc3.children[0].ids.btn.text = self.address - window_obj.sc3.children[0].ids.txt_input.text = '' - window_obj.sc3.children[0].ids.subject.text = '' - window_obj.sc3.children[0].ids.body.text = '' + 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.dismiss() @@ -1637,12 +1661,13 @@ class AddbookDetailPopup(Popup): def send_message_to(self): """Method used to fill to_address of composer autofield.""" + state.kivyapp.set_navbar_for_composer() window_obj = self.parent.children[1].ids - window_obj.sc3.children[0].ids.txt_input.text = self.address - window_obj.sc3.children[0].ids.ti.text = '' - window_obj.sc3.children[0].ids.btn.text = 'Select' - window_obj.sc3.children[0].ids.subject.text = '' - window_obj.sc3.children[0].ids.body.text = '' + 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.dismiss() @@ -1776,8 +1801,7 @@ class Draft(Screen): def draft_msg(src_object): """Method used for saving draft mails.""" # pylint: disable=too-many-locals - composer_object = src_object.children[1].children[0].children[ - 0].children[0].children[0].ids + composer_object = state.kivyapp.root.ids.sc3.children[1].ids fromAddress = str(composer_object.ti.text) toAddress = str(composer_object.txt_input.text) subject = str(composer_object.subject.text) @@ -1974,6 +1998,12 @@ class Allmails(Screen): self.tick = 0 Clock.schedule_once(refresh_callback, 1) + def set_root_layout(self): + try: + return self.manager.parent.parent + except Exception as e: + return state.kivyapp.root.ids.float_box + def avatarImageFirstLetter(letter_string): """This method is used to the first letter for the avatar image""" diff --git a/src/state.py b/src/state.py index 4baf5614..1a55b248 100644 --- a/src/state.py +++ b/src/state.py @@ -106,3 +106,5 @@ in_composer = False write_msg = {} availabe_credit = 0 + +in_sent_method = False \ No newline at end of file From 061a9ef973c09ceffd5b98a9f3945f54af8de263 Mon Sep 17 00:00:00 2001 From: bug Lady Date: Sun, 10 Nov 2019 04:07:50 +0100 Subject: [PATCH 202/306] fix typos and flesh out placeholder --- docs/contribute.dir/processes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/contribute.dir/processes.rst b/docs/contribute.dir/processes.rst index 8f0385d4..eb913325 100644 --- a/docs/contribute.dir/processes.rst +++ b/docs/contribute.dir/processes.rst @@ -1,8 +1,8 @@ Processes ========= -In other to keep the Bitmessage project running the team run a number of systems and accounts that form the -development pipeline and continuous delivery process. We are always striving to improve the process. Towards +In order to keep the Bitmessage project running, the team runs a number of systems and accounts that form the +development pipeline and continuous delivery process. We are always striving to improve this process. Towards that end it is documented here. @@ -20,7 +20,7 @@ Our official Github_ account is Bitmessage. Our issue tracker is here as well. BitMessage ---------- -We eat our own dog food! You can send us bug reports via the Bitmessage chan at xxx +We eat our own dog food! You can send us bug reports via the [chan] bitmessage BM-2cWy7cvHoq3f1rYMerRJp8PT653jjSuEdY .. _website: https://bitmessage.org From 341651973a1ebbffed9e6ae2c133c25675848428 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 27 Oct 2019 15:15:45 +0200 Subject: [PATCH 203/306] Reduced imports: - exported from network package all objects used outside; - made all threads available in threads module. Wrote some module docstrings. --- src/bitmessagemain.py | 34 ++++++++--------------- src/bitmessageqt/networkstatus.py | 2 +- src/class_addressGenerator.py | 6 +++- src/class_objectProcessor.py | 9 +++--- src/class_singleCleaner.py | 3 +- src/class_singleWorker.py | 2 +- src/class_sqlThread.py | 6 ++++ src/helper_sql.py | 30 +++++++++++++++++--- src/helper_threading.py | 21 -------------- src/network/__init__.py | 17 ++++++++++++ src/network/receivequeuethread.py | 6 ++-- src/shutdown.py | 2 +- src/threads.py | 46 +++++++++++++++++++++++++++++++ src/upnp.py | 3 +- 14 files changed, 123 insertions(+), 64 deletions(-) delete mode 100644 src/helper_threading.py create mode 100644 src/threads.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 4ad9311f..81702783 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -41,30 +41,18 @@ import shared import knownnodes import state import shutdown -from debug import logger # this should go before any threads - -# Classes -from class_sqlThread import sqlThread -from class_singleCleaner import singleCleaner -from class_objectProcessor import objectProcessor -from class_singleWorker import singleWorker -from class_addressGenerator import addressGenerator from bmconfigparser import BMConfigParser - +from debug import logger # this should go before any threads from inventory import Inventory - -from network.connectionpool import BMConnectionPool -from network.dandelion import Dandelion -from network.networkthread import BMNetworkThread -from network.receivequeuethread import ReceiveQueueThread -from network.announcethread import AnnounceThread -from network.invthread import InvThread -from network.addrthread import AddrThread -from network.downloadthread import DownloadThread -from network.uploadthread import UploadThread - -# Helper Functions -import helper_threading +# Network objects and threads +from network import ( + BMConnectionPool, Dandelion, + AddrThread, AnnounceThread, BMNetworkThread, InvThread, ReceiveQueueThread, + DownloadThread, UploadThread) +# Synchronous threads +from threads import ( + set_thread_name, + addressGenerator, objectProcessor, singleCleaner, singleWorker, sqlThread) def connectToStream(streamNumber): @@ -275,7 +263,7 @@ class Main: self.setSignalHandler() - helper_threading.set_thread_name("PyBitmessage") + set_thread_name("PyBitmessage") state.dandelion = config.safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 5f014563..6fbf5df6 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -14,7 +14,7 @@ import network.stats import shared import widgets from inventory import Inventory -from network.connectionpool import BMConnectionPool +from network import BMConnectionPool from retranslateui import RetranslateMixin from tr import _translate from uisignaler import UISignaler diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index fa268377..c7c7e261 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -14,7 +14,7 @@ import highlevelcrypto from bmconfigparser import BMConfigParser from addresses import decodeAddress, encodeAddress, encodeVarint from fallback import RIPEMD160Hash -from network.threads import StoppableThread +from network import StoppableThread class addressGenerator(StoppableThread): @@ -29,6 +29,10 @@ class addressGenerator(StoppableThread): super(addressGenerator, self).stopThread() def run(self): + """ + Process the requests for addresses generation + from `.queues.addressGeneratorQueue` + """ while state.shutdown == 0: queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 6ae46658..e2b95447 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -57,6 +57,7 @@ class objectProcessor(threading.Thread): self.successfullyDecryptMessageTimings = [] def run(self): + """Process the objects from `.queues.objectProcessorQueue`""" while True: objectType, data = queues.objectProcessorQueue.get() @@ -1051,7 +1052,8 @@ class objectProcessor(threading.Thread): # for it. elif addressVersion >= 4: tag = hashlib.sha512(hashlib.sha512( - encodeVarint(addressVersion) + encodeVarint(streamNumber) + ripe + encodeVarint(addressVersion) + encodeVarint(streamNumber) + + ripe ).digest()).digest()[32:] if tag in state.neededPubkeys: del state.neededPubkeys[tag] @@ -1059,9 +1061,8 @@ class objectProcessor(threading.Thread): def sendMessages(self, address): """ - This function is called by the possibleNewPubkey function when - that function sees that we now have the necessary pubkey - to send one or more messages. + This method is called by the `possibleNewPubkey` when it sees + that we now have the necessary pubkey to send one or more messages. """ logger.info('We have been awaiting the arrival of this pubkey.') sqlExecute( diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index fc53a5b0..4717c3cb 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -31,8 +31,7 @@ import tr from bmconfigparser import BMConfigParser from helper_sql import sqlQuery, sqlExecute from inventory import Inventory -from network.connectionpool import BMConnectionPool -from network.threads import StoppableThread +from network import BMConnectionPool, StoppableThread class singleCleaner(StoppableThread): diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 77fa18c0..60eabe2e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -28,7 +28,7 @@ from addresses import calculateInventoryHash, decodeAddress, decodeVarint, encod from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlQuery from inventory import Inventory -from network.threads import StoppableThread +from network import StoppableThread def sizeof_fmt(num, suffix='h/s'): diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index a45571e0..bcb56303 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,3 +1,7 @@ +""" +sqlThread is defined here +""" + import threading from bmconfigparser import BMConfigParser import sqlite3 @@ -19,11 +23,13 @@ import tr class sqlThread(threading.Thread): + """A thread for all SQL operations""" def __init__(self): threading.Thread.__init__(self, name="SQL") def run(self): + """Process SQL queries from `.helper_sql.sqlSubmitQueue`""" self.conn = sqlite3.connect(state.appdata + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() diff --git a/src/helper_sql.py b/src/helper_sql.py index 2b558f62..138a9f50 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -1,17 +1,39 @@ -"""Helper Sql performs sql operations.""" +""" +SQL-related functions defined here are really pass the queries (or other SQL +commands) to :class:`.threads.sqlThread` through `sqlSubmitQueue` queue and check +or return the result got from `sqlReturnQueue`. + +This is done that way because :mod:`sqlite3` is so thread-unsafe that they +won't even let you call it from different threads using your own locks. +SQLite objects can only be used from one thread. + +.. note:: This actually only applies for certain deployments, and/or + really old version of sqlite. I haven't actually seen it anywhere. + Current versions do have support for threading and multiprocessing. + I don't see an urgent reason to refactor this, but it should be noted + in the comment that the problem is mostly not valid. Sadly, last time + I checked, there is no reliable way to check whether the library is + or isn't thread-safe. +""" import threading import Queue sqlSubmitQueue = Queue.Queue() -# SQLITE3 is so thread-unsafe that they won't even let you call it from different threads using your own locks. -# SQL objects #can only be called from one thread. +"""the queue for SQL""" sqlReturnQueue = Queue.Queue() +"""the queue for results""" sqlLock = threading.Lock() def sqlQuery(sqlStatement, *args): - """SQLLITE execute statement and return query.""" + """ + Query sqlite and return results + + :param str sqlStatement: SQL statement string + :param list args: SQL query parameters + :rtype: list + """ sqlLock.acquire() sqlSubmitQueue.put(sqlStatement) diff --git a/src/helper_threading.py b/src/helper_threading.py deleted file mode 100644 index 56dd7063..00000000 --- a/src/helper_threading.py +++ /dev/null @@ -1,21 +0,0 @@ -"""set_thread_name for threads that don't use StoppableThread""" - -import threading - -try: - import prctl -except ImportError: - def set_thread_name(name): - """Set the thread name for external use (visible from the OS).""" - threading.current_thread().name = name -else: - def set_thread_name(name): - """Set a name for the thread for python internal use.""" - prctl.set_name(name) - - def _thread_name_hack(self): - set_thread_name(self.name) - threading.Thread.__bootstrap_original__(self) - # pylint: disable=protected-access - threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap - threading.Thread._Thread__bootstrap = _thread_name_hack diff --git a/src/network/__init__.py b/src/network/__init__.py index e69de29b..51c4c4da 100644 --- a/src/network/__init__.py +++ b/src/network/__init__.py @@ -0,0 +1,17 @@ +from addrthread import AddrThread +from announcethread import AnnounceThread +from connectionpool import BMConnectionPool +from dandelion import Dandelion +from downloadthread import DownloadThread +from invthread import InvThread +from networkthread import BMNetworkThread +from receivequeuethread import ReceiveQueueThread +from threads import StoppableThread +from uploadthread import UploadThread + + +__all__ = [ + "BMConnectionPool", "Dandelion", + "AddrThread", "AnnounceThread", "BMNetworkThread", "DownloadThread", + "InvThread", "ReceiveQueueThread", "UploadThread", "StoppableThread" +] diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 13c12ce2..cd904065 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -32,14 +32,12 @@ class ReceiveQueueThread(StoppableThread): try: connection = BMConnectionPool().getConnectionByAddr(dest) - # KeyError = connection object not found - except KeyError: + except KeyError: # connection object not found receiveDataQueue.task_done() continue try: connection.process() - # UnknownStateError = state isn't implemented - except UnknownStateError: + except UnknownStateError: # state isn't implemented pass except socket.error as err: if err.errno == errno.EBADF: diff --git a/src/shutdown.py b/src/shutdown.py index 1d40a90f..c81a519a 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -10,7 +10,7 @@ from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure from inventory import Inventory from knownnodes import saveKnownNodes -from network.threads import StoppableThread +from network import StoppableThread from queues import ( addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue) diff --git a/src/threads.py b/src/threads.py new file mode 100644 index 00000000..08d61196 --- /dev/null +++ b/src/threads.py @@ -0,0 +1,46 @@ +""" +PyBitmessage does various tasks in separate threads. Most of them inherit +from `.network.StoppableThread`. There are `addressGenerator` for +addresses generation, `objectProcessor` for processing the network objects +passed minimal validation, `singleCleaner` to periodically clean various +internal storages (like inventory and knownnodes) and do forced garbage +collection, `singleWorker` for doing PoW, `sqlThread` for querying sqlite +database. + +There are also other threads in the `.network` package. + +:func:`set_thread_name` is defined here for the threads that don't inherit from +:class:`.network.StoppableThread` +""" + +import threading + +try: + import prctl +except ImportError: + def set_thread_name(name): + """Set a name for the thread for python internal use.""" + threading.current_thread().name = name +else: + def set_thread_name(name): + """Set the thread name for external use (visible from the OS).""" + prctl.set_name(name) + + def _thread_name_hack(self): + set_thread_name(self.name) + threading.Thread.__bootstrap_original__(self) + # pylint: disable=protected-access + threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap + threading.Thread._Thread__bootstrap = _thread_name_hack + +from class_addressGenerator import addressGenerator +from class_objectProcessor import objectProcessor +from class_singleCleaner import singleCleaner +from class_singleWorker import singleWorker +from class_sqlThread import sqlThread + + +__all__ = [ + "addressGenerator", "objectProcessor", "singleCleaner", "singleWorker", + "sqlThread" +] diff --git a/src/upnp.py b/src/upnp.py index b1ee2e7b..979b4186 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -21,8 +21,7 @@ import state import tr from bmconfigparser import BMConfigParser from debug import logger -from network.connectionpool import BMConnectionPool -from network.threads import StoppableThread +from network import BMConnectionPool, StoppableThread def createRequestXML(service, action, arguments=None): From 4d8d9b169f7326b189928f5b485aa7d88207245c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 31 Oct 2019 14:13:36 +0200 Subject: [PATCH 204/306] Moved ObjectProcessorQueue to queues, added some doc --- docs/conf.py | 2 +- src/class_objectProcessorQueue.py | 24 ----------------- src/queues.py | 45 ++++++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 32 deletions(-) delete mode 100644 src/class_objectProcessorQueue.py diff --git a/docs/conf.py b/docs/conf.py index b6e75cc1..f9283f38 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -229,7 +229,7 @@ apidoc_excluded_paths = [ 'bitmessageqt/newaddresswizard.py', 'class_objectProcessor.py', 'defaults.py', 'helper_startup.py', 'kivymd', 'main.py', 'navigationdrawer', 'network/http*', - 'pybitmessage', 'queues.py', 'tests', 'version.py' + 'pybitmessage', 'tests', 'version.py' ] apidoc_module_first = True apidoc_separate_modules = True diff --git a/src/class_objectProcessorQueue.py b/src/class_objectProcessorQueue.py deleted file mode 100644 index b6628816..00000000 --- a/src/class_objectProcessorQueue.py +++ /dev/null @@ -1,24 +0,0 @@ -import Queue -import threading -import time - -class ObjectProcessorQueue(Queue.Queue): - maxSize = 32000000 - - def __init__(self): - Queue.Queue.__init__(self) - self.sizeLock = threading.Lock() - self.curSize = 0 # in Bytes. We maintain this to prevent nodes from flooing us with objects which take up too much memory. If this gets too big we'll sleep before asking for further objects. - - 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 diff --git a/src/queues.py b/src/queues.py index 7b6bbade..d0ac77d0 100644 --- a/src/queues.py +++ b/src/queues.py @@ -1,20 +1,51 @@ -import Queue +"""Most of the queues used by bitmessage threads are defined here.""" + +import Queue +import threading +import time -from class_objectProcessorQueue import ObjectProcessorQueue from multiqueue import MultiQueue + +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() -# receiveDataThreads dump objects they hear on the network into this -# queue to be processed. +#: receiveDataThreads dump objects they hear on the network into this +#: queue to be processed. objectProcessorQueue = ObjectProcessorQueue() invQueue = MultiQueue() addrQueue = MultiQueue() portCheckerQueue = Queue.Queue() receiveDataQueue = Queue.Queue() -# The address generator thread uses this queue to get information back -# to the API thread. +#: The address generator thread uses this queue to get information back +#: to the API thread. apiAddressGeneratorReturnQueue = Queue.Queue() -# Exceptions +#: for exceptions excQueue = Queue.Queue() From 7a1f803c92667d9a21f41a8d3341b0f46477ffa9 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 3 Nov 2019 14:09:00 +0200 Subject: [PATCH 205/306] network.BMConnectionPool: added shortcuts connections() and establishedConnections(), some formatting fixes --- src/class_singleCleaner.py | 18 ++++---- src/network/bmproto.py | 5 +- src/network/connectionpool.py | 87 ++++++++++++++++++----------------- src/network/downloadthread.py | 20 ++++---- src/network/invthread.py | 19 +++----- src/network/objectracker.py | 3 +- src/network/stats.py | 17 +------ src/network/uploadthread.py | 12 ++--- 8 files changed, 77 insertions(+), 104 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 4717c3cb..9ffc1607 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -1,5 +1,5 @@ """ -The singleCleaner class is a timer-driven thread that cleans data structures +The `singleCleaner` class is a timer-driven thread that cleans data structures to free memory, resends messages when a remote node doesn't respond, and sends pong messages to keep connections alive if the network isn't busy. @@ -45,12 +45,12 @@ class singleCleaner(StoppableThread): try: shared.maximumLengthOfTimeToBotherResendingMessages = ( float(BMConfigParser().get( - 'bitmessagesettings', 'stopresendingafterxdays')) * - 24 * 60 * 60 + 'bitmessagesettings', 'stopresendingafterxdays')) + * 24 * 60 * 60 ) + ( float(BMConfigParser().get( - 'bitmessagesettings', 'stopresendingafterxmonths')) * - (60 * 60 * 24 * 365) / 12) + 'bitmessagesettings', 'stopresendingafterxmonths')) + * (60 * 60 * 24 * 365) / 12) except: # Either the user hasn't set stopresendingafterxdays and # stopresendingafterxmonths yet or the options are missing @@ -92,8 +92,8 @@ class singleCleaner(StoppableThread): "SELECT toaddress, ackdata, status FROM sent" " WHERE ((status='awaitingpubkey' OR status='msgsent')" " AND folder='sent' AND sleeptill?)", - int(time.time()), int(time.time()) - - shared.maximumLengthOfTimeToBotherResendingMessages + int(time.time()), int(time.time()) + - shared.maximumLengthOfTimeToBotherResendingMessages ) for row in queryreturn: if len(row) < 2: @@ -139,9 +139,7 @@ class singleCleaner(StoppableThread): # thread.downloadQueue.clear() # inv/object tracking - for connection in \ - BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): + for connection in BMConnectionPool().connections(): connection.clean() # discovery tracking diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 6375f393..86295b87 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -645,10 +645,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): @staticmethod def stopDownloadingObject(hashId, forwardAnyway=False): """Stop downloading an object""" - for connection in ( - connectionpool.BMConnectionPool().inboundConnections.values() + - connectionpool.BMConnectionPool().outboundConnections.values() - ): + for connection in connectionpool.BMConnectionPool().connections(): try: del connection.objectsNewToMe[hashId] except KeyError: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1267522a..8f959356 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -1,6 +1,5 @@ """ -src/network/connectionpool.py -================================== +`BMConnectionPool` class definition """ import errno import logging @@ -26,9 +25,10 @@ logger = logging.getLogger('default') @Singleton -# pylint: disable=too-many-instance-attributes class BMConnectionPool(object): """Pool of all existing connections""" + # pylint: disable=too-many-instance-attributes + def __init__(self): asyncore.set_rates( BMConfigParser().safeGetInt( @@ -41,9 +41,21 @@ class BMConnectionPool(object): self.listeningSockets = {} self.udpSockets = {} self.streams = [] - self.lastSpawned = 0 - self.spawnWait = 2 - self.bootstrapped = False + self._lastSpawned = 0 + self._spawnWait = 2 + self._bootstrapped = False + + def connections(self): + """ + Shortcut for combined list of connections from + `inboundConnections` and `outboundConnections` dicts + """ + return self.inboundConnections.values() + self.outboundConnections.values() + + def establishedConnections(self): + """Shortcut for list of connections having fullyEstablished == True""" + return [ + x for x in self.connections() if x.fullyEstablished] def connectToStream(self, streamNumber): """Connect to a bitmessage stream""" @@ -74,10 +86,7 @@ class BMConnectionPool(object): def isAlreadyConnected(self, nodeid): """Check if we're already connected to this peer""" - for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() - ): + for i in self.connections(): try: if nodeid == i.nodeid: return True @@ -129,10 +138,11 @@ class BMConnectionPool(object): "bitmessagesettings", "onionbindip") else: host = '127.0.0.1' - if (BMConfigParser().safeGetBoolean( - "bitmessagesettings", "sockslisten") or - BMConfigParser().safeGet( - "bitmessagesettings", "socksproxytype") == "none"): + if ( + BMConfigParser().safeGetBoolean("bitmessagesettings", "sockslisten") + or BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") + == "none" + ): # python doesn't like bind + INADDR_ANY? # host = socket.INADDR_ANY host = BMConfigParser().get("network", "bind") @@ -205,11 +215,13 @@ class BMConnectionPool(object): 'bitmessagesettings', 'socksproxytype', '') onionsocksproxytype = BMConfigParser().safeGet( 'bitmessagesettings', 'onionsocksproxytype', '') - if (socksproxytype[:5] == 'SOCKS' and - not BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'sockslisten') and - '.onion' not in BMConfigParser().safeGet( - 'bitmessagesettings', 'onionhostname', '')): + if ( + socksproxytype[:5] == 'SOCKS' + and not BMConfigParser().safeGetBoolean( + 'bitmessagesettings', 'sockslisten') + and '.onion' not in BMConfigParser().safeGet( + 'bitmessagesettings', 'onionhostname', '') + ): acceptConnections = False # pylint: disable=too-many-nested-blocks @@ -217,8 +229,8 @@ class BMConnectionPool(object): if not knownnodes.knownNodesActual: self.startBootstrappers() knownnodes.knownNodesActual = True - if not self.bootstrapped: - self.bootstrapped = True + if not self._bootstrapped: + self._bootstrapped = True Proxy.proxy = ( BMConfigParser().safeGet( 'bitmessagesettings', 'sockshostname'), @@ -260,8 +272,7 @@ class BMConnectionPool(object): continue try: - if (chosen.host.endswith(".onion") and - Proxy.onion_proxy is not None): + if chosen.host.endswith(".onion") and Proxy.onion_proxy: if onionsocksproxytype == "SOCKS5": self.addConnection(Socks5BMConnection(chosen)) elif onionsocksproxytype == "SOCKS4a": @@ -276,12 +287,9 @@ class BMConnectionPool(object): if e.errno == errno.ENETUNREACH: continue - self.lastSpawned = time.time() + self._lastSpawned = time.time() else: - for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() - ): + for i in self.connections(): # FIXME: rating will be increased after next connection i.handle_close() @@ -291,8 +299,8 @@ class BMConnectionPool(object): self.startListening() else: for bind in re.sub( - '[^\w.]+', ' ', # pylint: disable=anomalous-backslash-in-string - BMConfigParser().safeGet('network', 'bind') + r'[^\w.]+', ' ', + BMConfigParser().safeGet('network', 'bind') ).split(): self.startListening(bind) logger.info('Listening for incoming connections.') @@ -301,8 +309,8 @@ class BMConnectionPool(object): self.startUDPSocket() else: for bind in re.sub( - '[^\w.]+', ' ', # pylint: disable=anomalous-backslash-in-string - BMConfigParser().safeGet('network', 'bind') + r'[^\w.]+', ' ', + BMConfigParser().safeGet('network', 'bind') ).split(): self.startUDPSocket(bind) self.startUDPSocket(False) @@ -319,16 +327,13 @@ class BMConnectionPool(object): i.accepting = i.connecting = i.connected = False logger.info('Stopped udp sockets.') - loopTime = float(self.spawnWait) - if self.lastSpawned < time.time() - self.spawnWait: + loopTime = float(self._spawnWait) + if self._lastSpawned < time.time() - self._spawnWait: loopTime = 2.0 asyncore.loop(timeout=loopTime, count=1000) reaper = [] - for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() - ): + for i in self.connections(): minTx = time.time() - 20 if i.fullyEstablished: minTx -= 300 - 20 @@ -340,10 +345,8 @@ class BMConnectionPool(object): time.time() - i.lastTx) i.set_state("close") for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() + - self.listeningSockets.values() + - self.udpSockets.values() + self.connections() + + self.listeningSockets.values() + self.udpSockets.values() ): if not (i.accepting or i.connecting or i.connected): reaper.append(i) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 472b32c0..e882f6de 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,6 +1,5 @@ """ -src/network/downloadthread.py -============================= +`DownloadThread` class definition """ import time @@ -29,7 +28,7 @@ class DownloadThread(StoppableThread): def cleanPending(self): """Expire pending downloads eventually""" - deadline = time.time() - DownloadThread.requestExpires + deadline = time.time() - self.requestExpires try: toDelete = [k for k, v in missingObjects.iteritems() if v < deadline] except RuntimeError: @@ -43,15 +42,12 @@ class DownloadThread(StoppableThread): while not self._stopped: requested = 0 # Choose downloading peers randomly - connections = [ - x for x in - BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() - if x.fullyEstablished] + connections = BMConnectionPool().establishedConnections() helper_random.randomshuffle(connections) - try: - requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) - except ZeroDivisionError: - requestChunk = 1 + requestChunk = max(int( + min(self.maxRequestChunk, len(missingObjects)) + / len(connections)), 1) if connections else 1 + for i in connections: now = time.time() # avoid unnecessary delay @@ -81,7 +77,7 @@ class DownloadThread(StoppableThread): '%s:%i Requesting %i objects', i.destination.host, i.destination.port, chunkCount) requested += chunkCount - if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: + if time.time() >= self.lastCleaned + self.cleanInterval: self.cleanPending() if not requested: self.stop.wait(1) diff --git a/src/network/invthread.py b/src/network/invthread.py index bffa6ecb..d5690486 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -20,9 +20,7 @@ def handleExpiredDandelion(expired): the object""" if not expired: return - for i in \ - BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): + for i in BMConnectionPool().connections(): if not i.fullyEstablished: continue for x in expired: @@ -44,9 +42,7 @@ class InvThread(StoppableThread): def handleLocallyGenerated(stream, hashId): """Locally generated inventory items require special handling""" Dandelion().addHash(hashId, stream=stream) - for connection in \ - BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): + for connection in BMConnectionPool().connections(): if state.dandelion and connection != Dandelion().objectChildStem(hashId): continue connection.objectsNewToThem[hashId] = time() @@ -67,8 +63,7 @@ class InvThread(StoppableThread): break if chunk: - for connection in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): + for connection in BMConnectionPool().connections(): fluffs = [] stems = [] for inv in chunk: @@ -96,13 +91,13 @@ class InvThread(StoppableThread): if fluffs: random.shuffle(fluffs) connection.append_write_buf(protocol.CreatePacket( - 'inv', addresses.encodeVarint(len(fluffs)) + - "".join(fluffs))) + 'inv', + addresses.encodeVarint(len(fluffs)) + ''.join(fluffs))) if stems: random.shuffle(stems) connection.append_write_buf(protocol.CreatePacket( - 'dinv', addresses.encodeVarint(len(stems)) + - "".join(stems))) + 'dinv', + addresses.encodeVarint(len(stems)) + ''.join(stems))) invQueue.iterate() for i in range(len(chunk)): diff --git a/src/network/objectracker.py b/src/network/objectracker.py index a8e3292a..b97aee46 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -95,8 +95,7 @@ class ObjectTracker(object): def handleReceivedObject(self, streamNumber, hashid): """Handling received object""" - for i in network.connectionpool.BMConnectionPool().inboundConnections.values( - ) + network.connectionpool.BMConnectionPool().outboundConnections.values(): + for i in network.connectionpool.BMConnectionPool().connections(): if not i.fullyEstablished: continue try: diff --git a/src/network/stats.py b/src/network/stats.py index fedfbbc1..d760ace2 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -19,16 +19,7 @@ currentSentSpeed = 0 def connectedHostsList(): """List of all the connected hosts""" - retval = [] - for i in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): - if not i.fullyEstablished: - continue - try: - retval.append(i) - except AttributeError: - pass - return retval + return BMConnectionPool().establishedConnections() def sentBytes(): @@ -71,12 +62,6 @@ def downloadSpeed(): def pendingDownload(): """Getting pending downloads""" return len(missingObjects) - # tmp = {} - # for connection in BMConnectionPool().inboundConnections.values() + \ - # BMConnectionPool().outboundConnections.values(): - # for k in connection.objectsNewToMe.keys(): - # tmp[k] = True - # return len(tmp) def pendingUpload(): diff --git a/src/network/uploadthread.py b/src/network/uploadthread.py index 1b57bd9a..7d80d789 100644 --- a/src/network/uploadthread.py +++ b/src/network/uploadthread.py @@ -1,5 +1,5 @@ """ -src/network/uploadthread.py +`UploadThread` class definition """ import time @@ -22,19 +22,19 @@ class UploadThread(StoppableThread): def run(self): while not self._stopped: uploaded = 0 - # Choose downloading peers randomly - connections = [x for x in BMConnectionPool().inboundConnections.values() + - BMConnectionPool().outboundConnections.values() if x.fullyEstablished] + # Choose uploading peers randomly + connections = BMConnectionPool().establishedConnections() helper_random.randomshuffle(connections) for i in connections: now = time.time() # avoid unnecessary delay if i.skipUntil >= now: continue - if len(i.write_buf) > UploadThread.maxBufSize: + if len(i.write_buf) > self.maxBufSize: continue try: - request = i.pendingUpload.randomKeys(RandomTrackingDict.maxPending) + request = i.pendingUpload.randomKeys( + RandomTrackingDict.maxPending) except KeyError: continue payload = bytearray() From 0967f03b40a920e6e33453c04c4c0ea583131cb3 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 3 Nov 2019 14:10:21 +0200 Subject: [PATCH 206/306] addresses: raise varintEncodeError in encodeVarint() instead of SystemExit (looks like a bug) --- src/addresses.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index 533ec169..b83f3f6e 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -54,11 +54,20 @@ def decodeBase58(string, alphabet=ALPHABET): return num +class varintEncodeError(Exception): + """Exception class for encoding varint""" + pass + + +class varintDecodeError(Exception): + """Exception class for decoding varint data""" + pass + + def encodeVarint(integer): """Convert integer into varint bytes""" if integer < 0: - logger.error('varint cannot be < 0') - raise SystemExit + raise varintEncodeError('varint cannot be < 0') if integer < 253: return pack('>B', integer) if integer >= 253 and integer < 65536: @@ -68,13 +77,7 @@ def encodeVarint(integer): if integer >= 4294967296 and integer < 18446744073709551616: return pack('>B', 255) + pack('>Q', integer) if integer >= 18446744073709551616: - logger.error('varint cannot be >= 18446744073709551616') - raise SystemExit - - -class varintDecodeError(Exception): - """Exception class for decoding varint data""" - pass + raise varintEncodeError('varint cannot be >= 18446744073709551616') def decodeVarint(data): From 388de9649568a06aa709193338856006e1165683 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 3 Nov 2019 14:13:18 +0200 Subject: [PATCH 207/306] Alphabetical internal import order in bitmessagemain --- src/bitmessagemain.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 81702783..c70eb0bf 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -7,8 +7,6 @@ # Right now, PyBitmessage only support connecting to stream 1. It doesn't # yet contain logic to expand into further streams. -# The software version variable is now held in shared.py - import os import sys @@ -31,24 +29,23 @@ import time import traceback from struct import pack -from helper_startup import ( - isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections -) -from singleinstance import singleinstance - import defaults import shared -import knownnodes import state import shutdown from bmconfigparser import BMConfigParser from debug import logger # this should go before any threads +from helper_startup import ( + isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections +) from inventory import Inventory +from knownnodes import readKnownNodes # Network objects and threads from network import ( BMConnectionPool, Dandelion, AddrThread, AnnounceThread, BMNetworkThread, InvThread, ReceiveQueueThread, DownloadThread, UploadThread) +from singleinstance import singleinstance # Synchronous threads from threads import ( set_thread_name, @@ -72,14 +69,6 @@ def connectToStream(streamNumber): except: pass - with knownnodes.knownNodesLock: - if streamNumber not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber] = {} - if streamNumber * 2 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber * 2] = {} - if streamNumber * 2 + 1 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber * 2 + 1] = {} - BMConnectionPool().connectToStream(streamNumber) @@ -279,7 +268,7 @@ class Main: defaults.networkDefaultPayloadLengthExtraBytes = int( defaults.networkDefaultPayloadLengthExtraBytes / 100) - knownnodes.readKnownNodes() + readKnownNodes() # Not needed if objproc is disabled if state.enableObjProc: From d6c1845b711e763efa382432ec6d2a92438eb22f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 3 Nov 2019 17:11:52 +0200 Subject: [PATCH 208/306] Moved Peer from state to network.node and trustedPeer to network.connectionpool.BMConnectionPool attribute --- src/class_objectProcessor.py | 3 ++- src/helper_startup.py | 26 ++---------------- src/knownnodes.py | 46 +++++++++++++++++--------------- src/network/announcethread.py | 5 +++- src/network/bmproto.py | 24 +++++++++-------- src/network/connectionchooser.py | 2 -- src/network/connectionpool.py | 31 +++++++++++++++++++-- src/network/node.py | 4 +-- src/network/proxy.py | 11 ++++---- src/network/socks5.py | 4 +-- src/network/tcp.py | 9 ++++--- src/network/udp.py | 9 ++++--- src/state.py | 17 ------------ src/tests/core.py | 7 ++--- src/upnp.py | 8 +++--- 15 files changed, 102 insertions(+), 104 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index e2b95447..b22876e8 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -21,6 +21,7 @@ import helper_sent from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery from helper_ackPayload import genAckPayload from network import bmproto +from network.node import Peer import protocol import queues import state @@ -161,7 +162,7 @@ class objectProcessor(threading.Thread): if not host: return - peer = state.Peer(host, port) + peer = Peer(host, port) with knownnodes.knownNodesLock: knownnodes.addKnownNode( stream, peer, is_self=state.ownAddresses.get(peer)) diff --git a/src/helper_startup.py b/src/helper_startup.py index 1a1119f5..9aaad5ef 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,13 +1,9 @@ """ -src/helper_startup.py -===================== - -Helper Start performs all the startup operations. +Startup operations. """ # pylint: disable=too-many-branches,too-many-statements from __future__ import print_function -import ConfigParser import os import platform import sys @@ -19,28 +15,12 @@ import paths import state from bmconfigparser import BMConfigParser + # The user may de-select Portable Mode in the settings if they want # the config files to stay in the application data folder. StoreConfigFilesInSameDirectoryAsProgramByDefault = False -def _loadTrustedPeer(): - try: - trustedPeer = BMConfigParser().get('bitmessagesettings', 'trustedpeer') - except ConfigParser.Error: - # This probably means the trusted peer wasn't specified so we - # can just leave it as None - return - try: - host, port = trustedPeer.split(':') - except ValueError: - sys.exit( - 'Bad trustedpeer config setting! It should be set as' - ' trustedpeer=:' - ) - state.trustedPeer = state.Peer(host, int(port)) - - def loadConfig(): """Load the config""" config = BMConfigParser() @@ -134,8 +114,6 @@ def loadConfig(): else: updateConfig() - _loadTrustedPeer() - def updateConfig(): """Save the config""" diff --git a/src/knownnodes.py b/src/knownnodes.py index 1d9e6897..bb588fcb 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -3,6 +3,7 @@ Manipulations with knownNodes dictionary. """ import json +import logging import os import pickle import threading @@ -10,28 +11,33 @@ import time import state from bmconfigparser import BMConfigParser -from debug import logger +from network.node import Peer knownNodesLock = threading.Lock() +"""Thread lock for knownnodes modification""" knownNodes = {stream: {} for stream in range(1, 4)} +"""The dict of known nodes for each stream""" knownNodesTrimAmount = 2000 +"""trim stream knownnodes dict to this length""" -# forget a node after rating is this low knownNodesForgetRating = -0.5 +"""forget a node after rating is this low""" knownNodesActual = False +logger = logging.getLogger('default') + DEFAULT_NODES = ( - state.Peer('5.45.99.75', 8444), - state.Peer('75.167.159.54', 8444), - state.Peer('95.165.168.168', 8444), - state.Peer('85.180.139.241', 8444), - state.Peer('158.222.217.190', 8080), - state.Peer('178.62.12.187', 8448), - state.Peer('24.188.198.204', 8111), - state.Peer('109.147.204.113', 1195), - state.Peer('178.11.46.221', 8444) + Peer('5.45.99.75', 8444), + Peer('75.167.159.54', 8444), + Peer('95.165.168.168', 8444), + Peer('85.180.139.241', 8444), + Peer('158.222.217.190', 8080), + Peer('178.62.12.187', 8448), + Peer('24.188.198.204', 8111), + Peer('109.147.204.113', 1195), + Peer('178.11.46.221', 8444) ) @@ -57,19 +63,17 @@ def json_deserialize_knownnodes(source): for node in json.load(source): peer = node['peer'] info = node['info'] - peer = state.Peer(str(peer['host']), peer.get('port', 8444)) + peer = Peer(str(peer['host']), peer.get('port', 8444)) knownNodes[node['stream']][peer] = info - if ( - not (knownNodesActual or info.get('self')) and - peer not in DEFAULT_NODES - ): + if not (knownNodesActual + or info.get('self')) and peer not in DEFAULT_NODES: knownNodesActual = True def pickle_deserialize_old_knownnodes(source): """ - Unpickle source and reorganize knownnodes dict if it's in old format + Unpickle source and reorganize knownnodes dict if it has old format the old format was {Peer:lastseen, ...} the new format is {Peer:{"lastseen":i, "rating":f}} """ @@ -129,7 +133,7 @@ def readKnownNodes(): if onionhostname and ".onion" in onionhostname: onionport = config.safeGetInt('bitmessagesettings', 'onionport') if onionport: - self_peer = state.Peer(onionhostname, onionport) + self_peer = Peer(onionhostname, onionport) addKnownNode(1, self_peer, is_self=True) state.ownAddresses[self_peer] = True @@ -182,7 +186,7 @@ def dns(): """Add DNS names to knownnodes""" for port in [8080, 8444]: addKnownNode( - 1, state.Peer('bootstrap%s.bitmessage.org' % port, port)) + 1, Peer('bootstrap%s.bitmessage.org' % port, port)) def cleanupKnownNodes(): @@ -208,8 +212,8 @@ def cleanupKnownNodes(): del knownNodes[stream][node] continue # scrap old nodes (age > 3 hours) with low rating - if (age > 10800 and knownNodes[stream][node]["rating"] <= - knownNodesForgetRating): + if (age > 10800 and knownNodes[stream][node]["rating"] + <= knownNodesForgetRating): needToWriteKnownNodesToDisk = True del knownNodes[stream][node] continue diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 5cd27ede..f635fc90 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -10,6 +10,7 @@ from bmconfigparser import BMConfigParser from network.bmproto import BMProto from network.connectionpool import BMConnectionPool from network.udp import UDPSocket +from node import Peer from threads import StoppableThread @@ -36,6 +37,8 @@ class AnnounceThread(StoppableThread): for stream in state.streamsInWhichIAmParticipating: addr = ( stream, - state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), + Peer( + '127.0.0.1', + BMConfigParser().safeGetInt('bitmessagesettings', 'port')), time.time()) connection.append_write_buf(BMProto.assembleAddr([addr])) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 86295b87..bf0b5742 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -24,8 +24,8 @@ from network.bmobject import ( BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError) -from network.node import Node from network.proxy import ProxyError +from node import Node, Peer from objectracker import missingObjects, ObjectTracker from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue from randomtrackingdict import RandomTrackingDict @@ -443,7 +443,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): seenTime > time.time() - BMProto.addressAlive and port > 0 ): - peer = state.Peer(decodedIP, port) + peer = Peer(decodedIP, port) try: if knownnodes.knownNodes[stream][peer]["lastseen"] > seenTime: continue @@ -464,7 +464,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def bm_command_portcheck(self): """Incoming port check request, queue it.""" - portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port)) + portCheckerQueue.put(Peer(self.destination, self.peerNode.port)) return True def bm_command_ping(self): @@ -594,12 +594,14 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # incoming from a peer we're connected to as outbound, # or server full report the same error to counter deanonymisation if ( - state.Peer(self.destination.host, self.peerNode.port) in - connectionpool.BMConnectionPool().inboundConnections or - len(connectionpool.BMConnectionPool().inboundConnections) + - len(connectionpool.BMConnectionPool().outboundConnections) > - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") + Peer(self.destination.host, self.peerNode.port) + in connectionpool.BMConnectionPool().inboundConnections + or len(connectionpool.BMConnectionPool().inboundConnections) + + len(connectionpool.BMConnectionPool().outboundConnections) + > BMConfigParser().safeGetInt( + 'bitmessagesettings', 'maxtotalconnections') + + BMConfigParser().safeGetInt( + 'bitmessagesettings', 'maxbootstrapconnections') ): self.append_write_buf(protocol.assembleErrorMessage( errorText="Server full, please try again later.", fatal=2)) @@ -622,7 +624,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): @staticmethod def assembleAddr(peerList): """Build up a packed address""" - if isinstance(peerList, state.Peer): + if isinstance(peerList, Peer): peerList = (peerList) if not peerList: return b'' @@ -686,7 +688,7 @@ class BMStringParser(BMProto): """ def __init__(self): super(BMStringParser, self).__init__() - self.destination = state.Peer('127.0.0.1', 8444) + self.destination = Peer('127.0.0.1', 8444) self.payload = None ObjectTracker.__init__(self) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 838ca45d..9d2f85d6 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -28,8 +28,6 @@ def chooseConnection(stream): "bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' onionOnly = BMConfigParser().safeGetBoolean( "bitmessagesettings", "onionservicesonly") - if state.trustedPeer: - return state.trustedPeer try: retval = portCheckerQueue.get(False) portCheckerQueue.task_done() diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 8f959356..654b74a1 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -5,6 +5,7 @@ import errno import logging import re import socket +import sys import time import asyncore_pollchoose as asyncore @@ -14,6 +15,7 @@ import protocol import state from bmconfigparser import BMConfigParser from connectionchooser import chooseConnection +from node import Peer from proxy import Proxy from singleton import Singleton from tcp import ( @@ -29,6 +31,19 @@ class BMConnectionPool(object): """Pool of all existing connections""" # pylint: disable=too-many-instance-attributes + trustedPeer = None + """ + 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 expected use case is where the user has 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. + """ + def __init__(self): asyncore.set_rates( BMConfigParser().safeGetInt( @@ -45,6 +60,18 @@ class BMConnectionPool(object): self._spawnWait = 2 self._bootstrapped = False + trustedPeer = BMConfigParser().safeGet( + 'bitmessagesettings', 'trustedpeer') + try: + if trustedPeer: + host, port = trustedPeer.split(':') + self.trustedPeer = Peer(host, int(port)) + except ValueError: + sys.exit( + 'Bad trustedpeer config setting! It should be set as' + ' trustedpeer=:' + ) + def connections(self): """ Shortcut for combined list of connections from @@ -112,7 +139,7 @@ class BMConnectionPool(object): if isinstance(connection, UDPSocket): del self.udpSockets[connection.listening.host] elif isinstance(connection, TCPServer): - del self.listeningSockets[state.Peer( + del self.listeningSockets[Peer( connection.destination.host, connection.destination.port)] elif connection.isOutbound: try: @@ -259,7 +286,7 @@ class BMConnectionPool(object): for i in range( state.maximumNumberOfHalfOpenConnections - pending): try: - chosen = chooseConnection( + chosen = self.trustedPeer or chooseConnection( helper_random.randomchoice(self.streams)) except ValueError: continue diff --git a/src/network/node.py b/src/network/node.py index 0bfda653..4c532b81 100644 --- a/src/network/node.py +++ b/src/network/node.py @@ -1,7 +1,7 @@ """ -src/network/node.py -=================== +Named tuples representing the network peers """ import collections +Peer = collections.namedtuple('Peer', ['host', 'port']) Node = collections.namedtuple('Node', ['services', 'host', 'port']) diff --git a/src/network/proxy.py b/src/network/proxy.py index e65ac6a7..e0bb5e78 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -8,9 +8,9 @@ import socket import time import asyncore_pollchoose as asyncore -import state from advanceddispatcher import AdvancedDispatcher from bmconfigparser import BMConfigParser +from node import Peer logger = logging.getLogger('default') @@ -90,9 +90,10 @@ class Proxy(AdvancedDispatcher): def onion_proxy(self, address): """Set onion proxy address""" if address is not None and ( - not isinstance(address, tuple) or len(address) < 2 or - not isinstance(address[0], str) or - not isinstance(address[1], int)): + not isinstance(address, tuple) or len(address) < 2 + or not isinstance(address[0], str) + or not isinstance(address[1], int) + ): raise ValueError self.__class__._onion_proxy = address @@ -107,7 +108,7 @@ class Proxy(AdvancedDispatcher): self.__class__._onion_auth = authTuple def __init__(self, address): - if not isinstance(address, state.Peer): + if not isinstance(address, Peer): raise ValueError AdvancedDispatcher.__init__(self) self.destination = address diff --git a/src/network/socks5.py b/src/network/socks5.py index e0cb7202..f0241744 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -8,7 +8,7 @@ src/network/socks5.py import socket import struct -import state +from node import Peer from proxy import GeneralProxyError, Proxy, ProxyError @@ -200,7 +200,7 @@ class Socks5Resolver(Socks5): def __init__(self, host): self.host = host self.port = 8444 - Socks5.__init__(self, address=state.Peer(self.host, self.port)) + Socks5.__init__(self, address=Peer(self.host, self.port)) def state_auth_done(self): """Perform resolving""" diff --git a/src/network/tcp.py b/src/network/tcp.py index a1691ceb..97b00784 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -28,6 +28,7 @@ from network.objectracker import ObjectTracker from network.socks4a import Socks4aConnection from network.socks5 import Socks5Connection from network.tls import TLSDispatcher +from node import Peer from queues import UISignalQueue, invQueue, receiveDataQueue logger = logging.getLogger('default') @@ -49,7 +50,7 @@ class TCPConnection(BMProto, TLSDispatcher): self.connectedAt = 0 self.skipUntil = 0 if address is None and sock is not None: - self.destination = state.Peer(*sock.getpeername()) + self.destination = Peer(*sock.getpeername()) self.isOutbound = False TLSDispatcher.__init__(self, sock, server_side=True) self.connectedAt = time.time() @@ -334,7 +335,7 @@ def bootstrap(connection_class): _connection_base = connection_class def __init__(self, host, port): - self._connection_base.__init__(self, state.Peer(host, port)) + self._connection_base.__init__(self, Peer(host, port)) self.close_reason = self._succeed = False def bm_command_addr(self): @@ -384,7 +385,7 @@ class TCPServer(AdvancedDispatcher): 'bitmessagesettings', 'port', str(port)) BMConfigParser().save() break - self.destination = state.Peer(host, port) + self.destination = Peer(host, port) self.bound = True self.listen(5) @@ -402,7 +403,7 @@ class TCPServer(AdvancedDispatcher): except (TypeError, IndexError): return - state.ownAddresses[state.Peer(*sock.getsockname())] = True + state.ownAddresses[Peer(*sock.getsockname())] = True if ( len(connectionpool.BMConnectionPool().inboundConnections) + len(connectionpool.BMConnectionPool().outboundConnections) > diff --git a/src/network/udp.py b/src/network/udp.py index 97c6aee5..cf694567 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -9,6 +9,7 @@ import socket import state import protocol from bmproto import BMProto +from node import Peer from objectracker import ObjectTracker from queues import receiveDataQueue @@ -43,8 +44,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes else: self.socket = sock self.set_socket_reuse() - self.listening = state.Peer(*self.socket.getsockname()) - self.destination = state.Peer(*self.socket.getsockname()) + self.listening = Peer(*self.socket.getsockname()) + self.destination = Peer(*self.socket.getsockname()) ObjectTracker.__init__(self) self.connecting = False self.connected = True @@ -96,7 +97,7 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes self.destination.host, self.destination.port, remoteport) if self.local: state.discoveredPeers[ - state.Peer(self.destination.host, remoteport) + Peer(self.destination.host, remoteport) ] = time.time() return True @@ -131,7 +132,7 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes logger.error("socket error: %s", e) return - self.destination = state.Peer(*addr) + self.destination = Peer(*addr) encodedAddr = protocol.encodeHost(addr[0]) self.local = bool(protocol.checkIPAddress(encodedAddr, True)) # overwrite the old buffer to avoid mixing data and so that diff --git a/src/state.py b/src/state.py index a3b930ab..f5526029 100644 --- a/src/state.py +++ b/src/state.py @@ -1,7 +1,6 @@ """ Global runtime variables. """ -import collections neededPubkeys = {} streamsInWhichIAmParticipating = [] @@ -47,24 +46,8 @@ uploadThread = None ownAddresses = {} -trustedPeer = None -""" - 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. -""" - discoveredPeers = {} -Peer = collections.namedtuple('Peer', ['host', 'port']) - dandelion = 0 testmode = False diff --git a/src/tests/core.py b/src/tests/core.py index 8d24a768..3871946d 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -17,6 +17,7 @@ from bmconfigparser import BMConfigParser from helper_msgcoding import MsgEncode, MsgDecode from network import asyncore_pollchoose as asyncore from network.connectionpool import BMConnectionPool +from network.node import Peer from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection from queues import excQueue @@ -30,7 +31,7 @@ def pickle_knownnodes(): with open(knownnodes_file, 'wb') as dst: pickle.dump({ stream: { - state.Peer( + Peer( '%i.%i.%i.%i' % tuple([ random.randint(1, 255) for i in range(4)]), 8444): {'lastseen': now, 'rating': 0.1} @@ -90,7 +91,7 @@ class TestCore(unittest.TestCase): """initial fill script from network.tcp""" BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') try: - for peer in (state.Peer("127.0.0.1", 8448),): + for peer in (Peer("127.0.0.1", 8448),): direct = TCPConnection(peer) while asyncore.socket_map: print("loop, state = %s" % direct.state) @@ -147,7 +148,7 @@ class TestCore(unittest.TestCase): def _initiate_bootstrap(self): BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') self._outdate_knownnodes() - knownnodes.addKnownNode(1, state.Peer('127.0.0.1', 8444), is_self=True) + knownnodes.addKnownNode(1, Peer('127.0.0.1', 8444), is_self=True) knownnodes.cleanupKnownNodes() time.sleep(2) diff --git a/src/upnp.py b/src/upnp.py index 979b4186..99000413 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -1,9 +1,6 @@ # pylint: disable=too-many-statements,too-many-branches,protected-access,no-self-use """ -src/upnp.py -=========== - -A simple upnp module to forward port for BitMessage +Complete UPnP port forwarding implementation in separate thread. Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port """ @@ -22,6 +19,7 @@ import tr from bmconfigparser import BMConfigParser from debug import logger from network import BMConnectionPool, StoppableThread +from network.node import Peer def createRequestXML(service, action, arguments=None): @@ -262,7 +260,7 @@ class uPnPThread(StoppableThread): self.routers.append(newRouter) self.createPortMapping(newRouter) try: - self_peer = state.Peer( + self_peer = Peer( newRouter.GetExternalIPAddress(), self.extPort ) From c40c70f8073ca6fef9b48290da13de7c873a193f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 4 Nov 2019 14:29:57 +0200 Subject: [PATCH 209/306] Marked variables comments in defaults for use in doc. Allowed autodoc in bitmessagemain, class_objectProcessor, defaults: seems safe now. Changed docs conf: don't sort module members, treat any string inside backticks as :obj:. --- docs/conf.py | 9 +++++---- src/defaults.py | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f9283f38..3464e056 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,6 +49,8 @@ extensions = [ 'm2r', ] +default_role = 'obj' + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -199,7 +201,6 @@ epub_exclude_files = ['search.html'] autodoc_mock_imports = [ 'debug', 'pybitmessage.bitmessagekivy', - 'pybitmessage.bitmessagemain', 'pybitmessage.bitmessageqt.addressvalidator', 'pybitmessage.helper_startup', 'pybitmessage.network.httpd', @@ -219,15 +220,15 @@ autodoc_mock_imports = [ 'qrcode', 'stem', ] +autodoc_member_order = 'bysource' # Apidoc settings apidoc_module_dir = '../pybitmessage' apidoc_output_dir = 'autodoc' apidoc_excluded_paths = [ - 'bitmessagekivy', 'bitmessagemain.py', 'build_osx.py', + 'bitmessagekivy', 'build_osx.py', 'bitmessageqt/addressvalidator.py', 'bitmessageqt/migrationwizard.py', - 'bitmessageqt/newaddresswizard.py', - 'class_objectProcessor.py', 'defaults.py', 'helper_startup.py', + 'bitmessageqt/newaddresswizard.py', 'helper_startup.py', 'kivymd', 'main.py', 'navigationdrawer', 'network/http*', 'pybitmessage', 'tests', 'version.py' ] diff --git a/src/defaults.py b/src/defaults.py index d10f9000..32162b56 100644 --- a/src/defaults.py +++ b/src/defaults.py @@ -1,24 +1,24 @@ """ -src/defaults.py -=============== +Common default values """ -# sanity check, prevent doing ridiculous PoW -# 20 million PoWs equals approximately 2 days on dev's dual R9 290 +#: sanity check, prevent doing ridiculous PoW +#: 20 million PoWs equals approximately 2 days on dev's dual R9 290 ridiculousDifficulty = 20000000 -# Remember here the RPC port read from namecoin.conf so we can restore to -# it as default whenever the user changes the "method" selection for -# namecoin integration to "namecoind". +#: Remember here the RPC port read from namecoin.conf so we can restore to +#: it as default whenever the user changes the "method" selection for +#: namecoin integration to "namecoind". namecoinDefaultRpcPort = "8336" # If changed, these values will cause particularly unexpected behavior: # You won't be able to either send or receive messages because the proof # of work you do (or demand) won't match that done or demanded by others. # Don't change them! -# The amount of work that should be performed (and demanded) per byte of the payload. +#: The amount of work that should be performed (and demanded) per byte +#: of the payload. networkDefaultProofOfWorkNonceTrialsPerByte = 1000 -# To make sending short messages a little more difficult, this value is -# added to the payload length for use in calculating the proof of work -# target. +#: To make sending short messages a little more difficult, this value is +#: added to the payload length for use in calculating the proof of work +#: target. networkDefaultPayloadLengthExtraBytes = 1000 From 35a29625526a5485d48a25fe8ad0f6264dd3cc2f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 6 Nov 2019 11:38:42 +0200 Subject: [PATCH 210/306] Fixed misleading comment about receiveDataThreads in queues --- src/queues.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/queues.py b/src/queues.py index d0ac77d0..7d9e284a 100644 --- a/src/queues.py +++ b/src/queues.py @@ -37,8 +37,8 @@ class ObjectProcessorQueue(Queue.Queue): workerQueue = Queue.Queue() UISignalQueue = Queue.Queue() addressGeneratorQueue = Queue.Queue() -#: receiveDataThreads dump objects they hear on the network into this -#: queue to be processed. +#: `.network.ReceiveQueueThread` instances dump objects they hear +#: on the network into this queue to be processed. objectProcessorQueue = ObjectProcessorQueue() invQueue = MultiQueue() addrQueue = MultiQueue() From 7e1f1d2604c333ccc2eb548c07f9cf19051b6592 Mon Sep 17 00:00:00 2001 From: bug Lady Date: Thu, 14 Nov 2019 13:32:15 +0100 Subject: [PATCH 211/306] fix 'true' not True else error --- src/tests/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/core.py b/src/tests/core.py index 3871946d..d2456064 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -176,7 +176,7 @@ class TestCore(unittest.TestCase): def test_onionservicesonly(self): """test onionservicesonly networking mode""" - BMConfigParser().set('bitmessagesettings', 'onionservicesonly', True) + BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true') self._initiate_bootstrap() BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') for _ in range(360): From 2a165380bb7214afdcfd95b74dce83660bad53ff Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 16 Nov 2019 11:52:36 +0100 Subject: [PATCH 212/306] Restrict outbound connections on network groups Logic borrowed from bitcoin, see CNetAddr::GetGroup() in src/netaddress.cpp Simplified, so may not work fully identically but for our purposes it's good enough. Won't connect to more than one host from a /16 subnet on IPv4 and a /32 subnet on IPv6. --- src/network/bmproto.py | 2 ++ src/network/connectionpool.py | 14 ++++++++++++ src/network/tcp.py | 1 + src/protocol.py | 28 ++++++++++++++++++++++++ src/tests/test_networkgroup.py | 39 ++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 src/tests/test_networkgroup.py diff --git a/src/network/bmproto.py b/src/network/bmproto.py index bf0b5742..11e96fd6 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -71,6 +71,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # packet/connection from a local IP self.local = False self.pendingUpload = RandomTrackingDict() + # canonical identifier of network group + self.network_group = None def bm_proto_reset(self): """Reset the bitmessage object parser""" diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 654b74a1..6264191d 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -229,6 +229,7 @@ class BMConnectionPool(object): def loop(self): # pylint: disable=too-many-branches,too-many-statements """Main Connectionpool's loop""" + # pylint: disable=too-many-locals # defaults to empty loop if outbound connections are maxed spawnConnections = False acceptConnections = True @@ -297,6 +298,19 @@ class BMConnectionPool(object): # don't connect to self if chosen in state.ownAddresses: continue + # don't connect to the hosts from the same + # network group, defense against sibyl attacks + host_network_group = protocol.network_group( + chosen.host) + same_group = False + for j in self.outboundConnections.values(): + if host_network_group == j.network_group: + same_group = True + if chosen.host == j.destination.host: + knownnodes.decreaseRating(chosen) + break + if same_group: + continue try: if chosen.host.endswith(".onion") and Proxy.onion_proxy: diff --git a/src/network/tcp.py b/src/network/tcp.py index 97b00784..31d20dea 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -84,6 +84,7 @@ class TCPConnection(BMProto, TLSDispatcher): ) except socket.error: pass # it's probably a hostname + self.network_group = protocol.network_group(self.destination.host) ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called self.bm_proto_reset() self.set_state("bm_header", expectBytes=protocol.Header.size) diff --git a/src/protocol.py b/src/protocol.py index ef101a72..ec8fc9dd 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -105,6 +105,34 @@ def networkType(host): return 'IPv6' +def network_group(host): + """Canonical identifier of network group + simplified, borrowed from + GetGroup() in src/netaddresses.cpp in bitcoin core""" + if not isinstance(host, str): + return None + network_type = networkType(host) + try: + raw_host = encodeHost(host) + except socket.error: + return host + if network_type == 'IPv4': + decoded_host = checkIPv4Address(raw_host[12:], True) + if decoded_host: + # /16 subnet + return raw_host[12:14] + elif network_type == 'IPv6': + decoded_host = checkIPv6Address(raw_host, True) + if decoded_host: + # /32 subnet + return raw_host[0:12] + else: + # just host, e.g. for tor + return host + # global network type group for local, private, unroutable + return network_type + + def checkIPAddress(host, private=False): """Returns hostStandardFormat if it is a valid IP address, otherwise returns False""" if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': diff --git a/src/tests/test_networkgroup.py b/src/tests/test_networkgroup.py new file mode 100644 index 00000000..76cfb033 --- /dev/null +++ b/src/tests/test_networkgroup.py @@ -0,0 +1,39 @@ +""" +Test for network group +""" +import unittest + + +class TestNetworkGroup(unittest.TestCase): + """ + Test case for network group + """ + def test_network_group(self): + """Test various types of network groups""" + from pybitmessage.protocol import network_group + + test_ip = '1.2.3.4' + self.assertEqual('\x01\x02', network_group(test_ip)) + + test_ip = '127.0.0.1' + self.assertEqual('IPv4', network_group(test_ip)) + + test_ip = '0102:0304:0506:0708:090A:0B0C:0D0E:0F10' + self.assertEqual( + '\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C', + network_group(test_ip)) + + test_ip = 'bootstrap8444.bitmessage.org' + self.assertEqual( + 'bootstrap8444.bitmessage.org', + network_group(test_ip)) + + test_ip = 'quzwelsuziwqgpt2.onion' + self.assertEqual( + test_ip, + network_group(test_ip)) + + test_ip = None + self.assertEqual( + None, + network_group(test_ip)) From f18f534c48fe0fb8dbc91d59779f2451d051fd66 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 28 Oct 2019 17:49:57 +0200 Subject: [PATCH 213/306] Formatted protocol and its docstrings --- src/protocol.py | 139 ++++++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 51 deletions(-) diff --git a/src/protocol.py b/src/protocol.py index ec8fc9dd..cdd50dce 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,7 +1,8 @@ -# pylint: disable=too-many-boolean-expressions,too-many-return-statements,too-many-locals,too-many-statements """ Low-level protocol-related functions. """ +# pylint: disable=too-many-boolean-expressions,too-many-return-statements +# pylint: disable=too-many-locals,too-many-statements import base64 import hashlib @@ -9,7 +10,6 @@ import random import socket import sys import time -import traceback from binascii import hexlify from struct import pack, unpack, Struct @@ -24,10 +24,18 @@ from fallback import RIPEMD160Hash from helper_sql import sqlExecute from version import softwareVersion - # Service flags +#: This is a normal network node NODE_NETWORK = 1 +#: This node supports SSL/TLS in the current connect (python < 2.7.9 +#: only supports an SSL client, so in that case it would only have this +#: on when the connection is a client). NODE_SSL = 2 +# (Proposal) This node may do PoW on behalf of some its peers +# (PoW offloading/delegating), but it doesn't have to. Clients may have +# to meet additional requirements (e.g. TLS authentication) +# NODE_POW = 4 +#: Node supports dandelion NODE_DANDELION = 8 # Bitfield flags @@ -89,7 +97,8 @@ def isBitSetWithinBitfield(fourByteString, n): def encodeHost(host): """Encode a given host to be used in low-level socket operations""" if host.find('.onion') > -1: - return '\xfd\x87\xd8\x7e\xeb\x43' + base64.b32decode(host.split(".")[0], True) + return '\xfd\x87\xd8\x7e\xeb\x43' + base64.b32decode( + host.split(".")[0], True) elif host.find(':') == -1: return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ socket.inet_aton(host) @@ -134,7 +143,10 @@ def network_group(host): def checkIPAddress(host, private=False): - """Returns hostStandardFormat if it is a valid IP address, otherwise returns False""" + """ + Returns hostStandardFormat if it is a valid IP address, + otherwise returns False + """ if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:]) return checkIPv4Address(host[12:], hostStandardFormat, private) @@ -150,35 +162,46 @@ def checkIPAddress(host, private=False): except ValueError: return False if hostStandardFormat == "": - # This can happen on Windows systems which are not 64-bit compatible - # so let us drop the IPv6 address. + # This can happen on Windows systems which are + # not 64-bit compatible so let us drop the IPv6 address. return False return checkIPv6Address(host, hostStandardFormat, private) def checkIPv4Address(host, hostStandardFormat, private=False): - """Returns hostStandardFormat if it is an IPv4 address, otherwise returns False""" + """ + Returns hostStandardFormat if it is an IPv4 address, + otherwise returns False + """ if host[0] == '\x7F': # 127/8 if not private: - logger.debug('Ignoring IP address in loopback range: %s', hostStandardFormat) + logger.debug( + 'Ignoring IP address in loopback range: %s', + hostStandardFormat) return hostStandardFormat if private else False if host[0] == '\x0A': # 10/8 if not private: - logger.debug('Ignoring IP address in private range: %s', hostStandardFormat) + logger.debug( + 'Ignoring IP address in private range: %s', hostStandardFormat) return hostStandardFormat if private else False if host[0:2] == '\xC0\xA8': # 192.168/16 if not private: - logger.debug('Ignoring IP address in private range: %s', hostStandardFormat) + logger.debug( + 'Ignoring IP address in private range: %s', hostStandardFormat) return hostStandardFormat if private else False if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 if not private: - logger.debug('Ignoring IP address in private range: %s', hostStandardFormat) + logger.debug( + 'Ignoring IP address in private range: %s', hostStandardFormat) return hostStandardFormat if private else False return False if private else hostStandardFormat def checkIPv6Address(host, hostStandardFormat, private=False): - """Returns hostStandardFormat if it is an IPv6 address, otherwise returns False""" + """ + Returns hostStandardFormat if it is an IPv6 address, + otherwise returns False + """ if host == ('\x00' * 15) + '\x01': if not private: logger.debug('Ignoring loopback address: %s', hostStandardFormat) @@ -189,7 +212,8 @@ def checkIPv6Address(host, hostStandardFormat, private=False): return hostStandardFormat if private else False if (ord(host[0]) & 0xfe) == 0xfc: if not private: - logger.debug('Ignoring unique local address: %s', hostStandardFormat) + logger.debug( + 'Ignoring unique local address: %s', hostStandardFormat) return hostStandardFormat if private else False return False if private else hostStandardFormat @@ -210,31 +234,29 @@ def haveSSL(server=False): def checkSocksIP(host): """Predicate to check if we're using a SOCKS proxy""" + sockshostname = BMConfigParser().safeGet( + 'bitmessagesettings', 'sockshostname') try: - if state.socksIP is None or not state.socksIP: - state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - # uninitialised - except NameError: - state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - # resolving failure - except socket.gaierror: - state.socksIP = BMConfigParser().get("bitmessagesettings", "sockshostname") + if not state.socksIP: + state.socksIP = socket.gethostbyname(sockshostname) + except NameError: # uninitialised + state.socksIP = socket.gethostbyname(sockshostname) + except (TypeError, socket.gaierror): # None, resolving failure + state.socksIP = sockshostname return state.socksIP == host -def isProofOfWorkSufficient(data, - nonceTrialsPerByte=0, - payloadLengthExtraBytes=0, - recvTime=0): +def isProofOfWorkSufficient( + data, nonceTrialsPerByte=0, payloadLengthExtraBytes=0, recvTime=0): """ - Validate an object's Proof of Work using method described in: - https://bitmessage.org/wiki/Proof_of_work + Validate an object's Proof of Work using method described + `here `_ Arguments: - int nonceTrialsPerByte (default: from default.py) - int payloadLengthExtraBytes (default: from default.py) + int nonceTrialsPerByte (default: from `.defaults`) + int payloadLengthExtraBytes (default: from `.defaults`) float recvTime (optional) UNIX epoch time when object was - received from the network (default: current system time) + received from the network (default: current system time) Returns: True if PoW valid and sufficient, False in all other cases """ @@ -246,18 +268,20 @@ def isProofOfWorkSufficient(data, TTL = endOfLifeTime - (int(recvTime) if recvTime else int(time.time())) if TTL < 300: TTL = 300 - POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[ - :8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8]) - return POW <= 2 ** 64 / (nonceTrialsPerByte * - (len(data) + payloadLengthExtraBytes + - ((TTL * (len(data) + payloadLengthExtraBytes)) / (2 ** 16)))) + POW, = unpack('>Q', hashlib.sha512(hashlib.sha512( + data[:8] + hashlib.sha512(data[8:]).digest() + ).digest()).digest()[0:8]) + return POW <= 2 ** 64 / ( + nonceTrialsPerByte * ( + len(data) + payloadLengthExtraBytes + + ((TTL * (len(data) + payloadLengthExtraBytes)) / (2 ** 16)))) # Packet creation def CreatePacket(command, payload=''): - """Construct and return a number of bytes from a payload""" + """Construct and return a packet""" payload_length = len(payload) checksum = hashlib.sha512(payload).digest()[0:4] @@ -267,8 +291,13 @@ def CreatePacket(command, payload=''): return bytes(b) -def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server=False, nodeid=None): - """Construct the payload of a version message, return the resultng bytes of running CreatePacket() on it""" +def assembleVersionMessage( + remoteHost, remotePort, participatingStreams, server=False, nodeid=None +): + """ + Construct the payload of a version message, + return the resulting bytes of running `CreatePacket` on it + """ payload = '' payload += pack('>L', 3) # protocol version. # bitflags of the services I offer. @@ -280,9 +309,10 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server= ) payload += pack('>q', int(time.time())) - payload += pack( - '>q', 1) # boolservices of remote connection; ignored by the remote host. - if checkSocksIP(remoteHost) and server: # prevent leaking of tor outbound IP + # boolservices of remote connection; ignored by the remote host. + payload += pack('>q', 1) + if checkSocksIP(remoteHost) and server: + # prevent leaking of tor outbound IP payload += encodeHost('127.0.0.1') payload += pack('>H', 8444) else: @@ -301,21 +331,25 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server= (NODE_SSL if haveSSL(server) else 0) | (NODE_DANDELION if state.dandelion else 0) ) - # = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used. - payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack('>L', 2130706433) + # = 127.0.0.1. This will be ignored by the remote host. + # The actual remote connected IP will be used. + payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack( + '>L', 2130706433) # we have a separate extPort and incoming over clearnet # or outgoing through clearnet extport = BMConfigParser().safeGetInt('bitmessagesettings', 'extport') if ( extport and ((server and not checkSocksIP(remoteHost)) or ( - BMConfigParser().get('bitmessagesettings', 'socksproxytype') == - 'none' and not server)) + BMConfigParser().get('bitmessagesettings', 'socksproxytype') + == 'none' and not server)) ): payload += pack('>H', extport) elif checkSocksIP(remoteHost) and server: # incoming connection over Tor - payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'onionport')) + payload += pack( + '>H', BMConfigParser().getint('bitmessagesettings', 'onionport')) else: # no extport and not incoming over Tor - payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'port')) + payload += pack( + '>H', BMConfigParser().getint('bitmessagesettings', 'port')) if nodeid is not None: payload += nodeid[0:8] @@ -339,7 +373,10 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server= def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): - """Construct the payload of an error message, return the resultng bytes of running CreatePacket() on it""" + """ + Construct the payload of an error message, + return the resulting bytes of running `CreatePacket` on it + """ payload = encodeVarint(fatal) payload += encodeVarint(banTime) payload += encodeVarint(len(inventoryVector)) @@ -476,7 +513,7 @@ def decryptAndCheckPubkeyPayload(data, address): except Exception: logger.critical( 'Pubkey decryption was UNsuccessful because of' - ' an unhandled exception! This is definitely a bug! \n%s', - traceback.format_exc() + ' an unhandled exception! This is definitely a bug!', + exc_info=True ) return 'failed' From aa7e7dd6583d780e7520330ab3e3fb1e9ee357ff Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 4 Nov 2019 12:27:19 +0200 Subject: [PATCH 214/306] Fixed some docstrings in shared and state --- src/shared.py | 25 ++++++++++++++++++------- src/state.py | 8 ++++---- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/shared.py b/src/shared.py index 1a2add28..90cea89d 100644 --- a/src/shared.py +++ b/src/shared.py @@ -80,7 +80,9 @@ def isAddressInMySubscriptionsList(address): def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): - """Am I subscribed to this address, is it in my addressbook or whitelist?""" + """ + Am I subscribed to this address, is it in my addressbook or whitelist? + """ if isAddressInMyAddressBook(address): return True @@ -100,8 +102,12 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return False -def decodeWalletImportFormat(WIFstring): # pylint: disable=inconsistent-return-statements - """Convert private key from base58 that's used in the config file to 8-bit binary string""" +def decodeWalletImportFormat(WIFstring): + # pylint: disable=inconsistent-return-statements + """ + Convert private key from base58 that's used in the config file to + 8-bit binary string + """ fullString = arithmetic.changebase(WIFstring, 58, 256) privkey = fullString[:-4] if fullString[-4:] != \ @@ -126,14 +132,15 @@ def decodeWalletImportFormat(WIFstring): # pylint: disable=inconsistent-retur def reloadMyAddressHashes(): - """Reinitialise runtime data (e.g. encryption objects, address hashes) from the config file""" + """Reload keys for user's addresses from the config file""" logger.debug('reloading keys from keys.dat file') myECCryptorObjects.clear() myAddressesByHash.clear() myAddressesByTag.clear() # myPrivateKeys.clear() - keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') + keyfileSecure = checkSensitiveFilePermissions(os.path.join( + state.appdata, 'keys.dat')) hasEnabledKeys = False for addressInKeysFile in BMConfigParser().addresses(): isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') @@ -162,11 +169,15 @@ def reloadMyAddressHashes(): ) if not keyfileSecure: - fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + fixSensitiveFilePermissions(os.path.join( + state.appdata, 'keys.dat'), hasEnabledKeys) def reloadBroadcastSendersForWhichImWatching(): - """Reinitialise runtime data for the broadcasts I'm subscribed to from the config file""" + """ + Reinitialize runtime data for the broadcasts I'm subscribed to + from the config file + """ broadcastSendersForWhichImWatching.clear() MyECSubscriptionCryptorObjects.clear() queryreturn = sqlQuery('SELECT address FROM subscriptions where enabled=1') diff --git a/src/state.py b/src/state.py index f5526029..58e1106a 100644 --- a/src/state.py +++ b/src/state.py @@ -16,8 +16,8 @@ appdata = '' shutdown = 0 """ - Set to 1 by the doCleanShutdown function. - Used to tell the proof of work worker threads to exit. +Set to 1 by the `.shutdown.doCleanShutdown` function. +Used to tell the threads to exit. """ # Component control flags - set on startup, do not change during runtime @@ -25,7 +25,7 @@ shutdown = 0 enableNetwork = True """enable network threads""" enableObjProc = True -"""enable object processing threads""" +"""enable object processing thread""" enableAPI = True """enable API (if configured)""" enableGUI = True @@ -35,7 +35,7 @@ enableSTDIO = False curses = False sqlReady = False -"""set to true by sqlTread when ready for processing""" +"""set to true by `.threads.sqlThread` when ready for processing""" maximumNumberOfHalfOpenConnections = 0 From a7da0c0eff1dcbea9b47124d3553f26f1d6f1c7b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 4 Nov 2019 12:42:52 +0200 Subject: [PATCH 215/306] Fixed google style docstrings in addresses --- src/addresses.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index b83f3f6e..bb0c9ec5 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -1,7 +1,5 @@ """ -src/addresses.py -================ - +Operations with addresses """ # pylint: disable=redefined-outer-name,inconsistent-return-statements @@ -18,8 +16,9 @@ ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" def encodeBase58(num, alphabet=ALPHABET): """Encode a number in Base X - `num`: The number to encode - `alphabet`: The alphabet to use for encoding + Args: + num: The number to encode + alphabet: The alphabet to use for encoding """ if num == 0: return alphabet[0] @@ -27,7 +26,6 @@ def encodeBase58(num, alphabet=ALPHABET): base = len(alphabet) while num: rem = num % base - # print 'num is:', num num = num // base arr.append(alphabet[rem]) arr.reverse() @@ -37,9 +35,9 @@ def encodeBase58(num, alphabet=ALPHABET): def decodeBase58(string, alphabet=ALPHABET): """Decode a Base X encoded string into the number - Arguments: - - `string`: The encoded string - - `alphabet`: The alphabet to use for encoding + Args: + string: The encoded string + alphabet: The alphabet to use for encoding """ base = len(alphabet) num = 0 From d9fa6a94f472432df48625e1a61be8c973227414 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 4 Nov 2019 13:30:11 +0200 Subject: [PATCH 216/306] More docstrings and formatting fixes in highlevelcrypto and shutdown --- src/highlevelcrypto.py | 48 +++++++++++++++++++++++++----------------- src/shutdown.py | 12 +++++++---- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 3d894ae8..f392fe4a 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,6 +1,10 @@ """ -src/highlevelcrypto.py -====================== +High level cryptographic functions based on `.pyelliptic` OpenSSL bindings. + +.. note:: + Upstream pyelliptic was upgraded from SHA1 to SHA256 for signing. + We must upgrade PyBitmessage gracefully. + `More discussion. `_ """ from binascii import hexlify @@ -12,12 +16,13 @@ from pyelliptic import arithmetic as a def makeCryptor(privkey): - """Return a private pyelliptic.ECC() instance""" + """Return a private `.pyelliptic.ECC` instance""" private_key = a.changebase(privkey, 16, 256, minlen=32) public_key = pointMult(private_key) privkey_bin = '\x02\xca\x00\x20' + private_key pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:] - cryptor = pyelliptic.ECC(curve='secp256k1', privkey=privkey_bin, pubkey=pubkey_bin) + cryptor = pyelliptic.ECC( + curve='secp256k1', privkey=privkey_bin, pubkey=pubkey_bin) return cryptor @@ -29,7 +34,7 @@ def hexToPubkey(pubkey): def makePubCryptor(pubkey): - """Return a public pyelliptic.ECC() instance""" + """Return a public `.pyelliptic.ECC` instance""" pubkey_bin = hexToPubkey(pubkey) return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin) @@ -43,7 +48,8 @@ def privToPub(privkey): def encrypt(msg, hexPubkey): """Encrypts message with hex public key""" - return pyelliptic.ECC(curve='secp256k1').encrypt(msg, hexToPubkey(hexPubkey)) + return pyelliptic.ECC(curve='secp256k1').encrypt( + msg, hexToPubkey(hexPubkey)) def decrypt(msg, hexPrivkey): @@ -52,36 +58,38 @@ def decrypt(msg, hexPrivkey): def decryptFast(msg, cryptor): - """Decrypts message with an existing pyelliptic.ECC.ECC object""" + """Decrypts message with an existing `.pyelliptic.ECC` object""" return cryptor.decrypt(msg) def sign(msg, hexPrivkey): - """Signs with hex private key""" - # pyelliptic is upgrading from SHA1 to SHA256 for signing. We must - # upgrade PyBitmessage gracefully. - # https://github.com/yann2192/pyelliptic/pull/33 - # More discussion: https://github.com/yann2192/pyelliptic/issues/32 - digestAlg = BMConfigParser().safeGet('bitmessagesettings', 'digestalg', 'sha1') + """ + Signs with hex private key using SHA1 or SHA256 depending on + "digestalg" setting + """ + digestAlg = BMConfigParser().safeGet( + 'bitmessagesettings', 'digestalg', 'sha1') if digestAlg == "sha1": # SHA1, this will eventually be deprecated - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) + return makeCryptor(hexPrivkey).sign( + msg, digest_alg=OpenSSL.digest_ecdsa_sha1) elif digestAlg == "sha256": # SHA256. Eventually this will become the default return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) else: - raise ValueError("Unknown digest algorithm %s" % (digestAlg)) + raise ValueError("Unknown digest algorithm %s" % digestAlg) def verify(msg, sig, hexPubkey): - """Verifies with hex public key""" + """Verifies with hex public key using SHA1 or SHA256""" # As mentioned above, we must upgrade gracefully to use SHA256. So # let us check the signature using both SHA1 and SHA256 and if one # of them passes then we will be satisfied. Eventually this can # be simplified and we'll only check with SHA256. try: # old SHA1 algorithm. - sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1) + sigVerifyPassed = makePubCryptor(hexPubkey).verify( + sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1) except: sigVerifyPassed = False if sigVerifyPassed: @@ -89,7 +97,8 @@ def verify(msg, sig, hexPubkey): return True # The signature check using SHA1 failed. Let us try it with SHA256. try: - return makePubCryptor(hexPubkey).verify(sig, msg, digest_alg=OpenSSL.EVP_sha256) + return makePubCryptor(hexPubkey).verify( + sig, msg, digest_alg=OpenSSL.EVP_sha256) except: return False @@ -106,7 +115,8 @@ def pointMult(secret): """ while True: try: - k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) + k = OpenSSL.EC_KEY_new_by_curve_name( + OpenSSL.get_curve('secp256k1')) priv_key = OpenSSL.BN_bin2bn(secret, 32, None) group = OpenSSL.EC_KEY_get0_group(k) pub_key = OpenSSL.EC_POINT_new(group) diff --git a/src/shutdown.py b/src/shutdown.py index c81a519a..dbc2af04 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -16,7 +16,9 @@ from queues import ( def doCleanShutdown(): - """Used to tell proof of work worker threads and the objectProcessorThread to exit.""" + """ + Used to tell all the treads to finish work and exit. + """ state.shutdown = 1 objectProcessorQueue.put(('checkShutdownVariable', 'no data')) @@ -52,9 +54,11 @@ def doCleanShutdown(): time.sleep(.25) for thread in threading.enumerate(): - if (thread is not threading.currentThread() and - isinstance(thread, StoppableThread) and - thread.name != 'SQL'): + if ( + thread is not threading.currentThread() + and isinstance(thread, StoppableThread) + and thread.name != 'SQL' + ): logger.debug("Waiting for thread %s", thread.name) thread.join() From 49d731c47865d8895df7cbf0e08312bd8aba289e Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 15 Nov 2019 14:10:18 +0200 Subject: [PATCH 217/306] .readthedocs.yml --- .readthedocs.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..474ae9ab --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,9 @@ +version: 2 + +python: + version: 2.7 + install: + - requirements: docs/requirements.txt + - method: setuptools + path: . + system_packages: true From 895a705657aee3cc88edd64b7b25d4aa1dbee0cd Mon Sep 17 00:00:00 2001 From: navjot Date: Tue, 19 Nov 2019 21:28:30 +0530 Subject: [PATCH 218/306] worked on infinite scroller functionality --- src/bitmessagekivy/main.kv | 10 + src/bitmessagekivy/mpybit.py | 854 +++++++++++++++++++++++------------ src/state.py | 4 +- 3 files changed, 570 insertions(+), 298 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 050caf52..5547de61 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -217,14 +217,17 @@ NavigationLayout: BoxLayout: orientation:'vertical' ScrollView: + id: scroll_y do_scroll_x: False MDList: id: ml + Loader: ComposerButton: : name: 'trash' ScrollView: + id: scroll_y do_scroll_x: False MDList: id: ml @@ -233,6 +236,7 @@ NavigationLayout: : name: 'draft' ScrollView: + id: scroll_y do_scroll_x: False MDList: id: ml @@ -510,6 +514,7 @@ NavigationLayout: hint_text: "Label" required: True helper_text_mode: "on_error" + on_text: root.add_validation(self) BoxLayout: AnchorLayout: MDRaisedButton: @@ -624,9 +629,11 @@ NavigationLayout: BoxLayout: orientation:'vertical' ScrollView: + id: scroll_y do_scroll_x: False MDList: id: ml + Loader: ComposerButton: : @@ -799,6 +806,7 @@ NavigationLayout: hint_text: "Label" required: True helper_text_mode: "on_error" + on_text: root.checkLabel_valid(self) MDTextField: id: address hint_text: "Address" @@ -1118,6 +1126,7 @@ NavigationLayout: theme_text_color: 'Primary' required: True helper_text_mode: "on_error" + on_text: root.checkLabel_valid(self) MDLabel: font_style: 'Title' theme_text_color: 'Primary' @@ -1125,6 +1134,7 @@ NavigationLayout: font_size: '17sp' halign: 'left' MDLabel: + id: address font_style: 'Subhead' theme_text_color: 'Primary' text: root.address diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index f861971a..fdcf2da6 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -83,6 +83,8 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" + queryreturn = ListProperty() + has_refreshed = True def __init__(self, *args, **kwargs): """Method Parsing the address.""" @@ -110,15 +112,13 @@ class Inbox(Screen): what = state.searcing_text xAddress = 'toaddress' data = [] - queryreturn = kivy_helper_search.search_sql( + self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "inbox", where, what, False) - if queryreturn: + if self.queryreturn: src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.inbox_cnt.badge_text = str(len(queryreturn)) - state.inbox_count = str(len(queryreturn)) - state.kivyapp.root.ids.sc17.clear_widgets() - state.kivyapp.root.ids.sc17.add_widget(Allmails()) - for mail in queryreturn: + src_mng_obj.inbox_cnt.badge_text = str(len(self.queryreturn)) + state.inbox_count = str(len(self.queryreturn)) + for mail in self.queryreturn[:20]: third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), @@ -126,37 +126,9 @@ class Inbox(Screen): mail[5]) >= 50 else ( mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'msgid': mail[1]}) - for item in data: - meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - avatarImageFirstLetter(item['secondary_text'].strip())))) - meny.bind(on_press=partial( - self.inbox_detail, item['msgid'])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete, item['msgid'])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - ach_btn = Button(text='Achieve') - ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial( - self.archive, item['msgid'])) - carousel.add_widget(ach_btn) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + self.has_refreshed = True + self.set_mdList(data) + self.children[2].children[0].children[0].bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -169,6 +141,64 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdList(self, data): + """This method is used to create the mdList""" + for item in data: + meny = TwoLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) + meny.bind(on_press=partial( + self.inbox_detail, item['msgid'])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete, item['msgid'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0, 1, 0, 1) + ach_btn.bind(on_press=partial( + self.archive, item['msgid'])) + carousel.add_widget(ach_btn) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to load data on scroll""" + if self.children[2].children[0].children[0].scroll_y <= -0.0 and self.has_refreshed: + self.children[2].children[0].children[0].scroll_y = 0.06 + total_message = len(self.ids.ml.children) + if total_message != len(self.queryreturn): + self.update_inbox_screen_on_scroll(total_message) + self.has_refreshed = True if total_message != len(self.queryreturn) else False + else: + pass + + def update_inbox_screen_on_scroll(self, total_message): + """This method is used to load more data on scroll down""" + data = [] + for mail in self.queryreturn[total_message:total_message + 5]: + third_text = mail[3].replace('\n', ' ') + data.append({ + 'text': mail[4].strip(), + 'secondary_text': mail[5][:50] + '........' if len( + mail[5]) >= 50 else ( + mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + 'msgid': mail[1]}) + self.set_mdList(data) + def inbox_detail(self, msg_id, *args): """Load inbox page details.""" state.detailPageType = 'inbox' @@ -234,6 +264,7 @@ class Inbox(Screen): self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() self.loadMessagelist(state.association) + self.has_refreshed = True self.ids.refresh_layout.refresh_done() self.tick = 0 @@ -245,6 +276,8 @@ class Inbox(Screen): class MyAddress(Screen): """MyAddress Screen uses screen to show widgets of screens.""" + addresses_list = ListProperty() + has_refreshed = True def __init__(self, *args, **kwargs): """Clock Schdule for method inbox accounts.""" @@ -254,29 +287,17 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" # pylint: disable=unnecessary-lambda, deprecated-lambda - addresses_list = state.kivyapp.variable_1 + self.addresses_list = state.kivyapp.variable_1 if state.searcing_text: filtered_list = filter( lambda addr: self.filter_address( addr), BMConfigParser().addresses()) - addresses_list = filtered_list - if addresses_list: - data = [] - for address in addresses_list: - data.append({ - 'text': BMConfigParser().get(address, 'label'), - 'secondary_text': address}) - for item in data: - meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['text'].strip())))) - meny.bind(on_press=partial( - self.myadd_detail, item['secondary_text'], item['text'])) - self.ids.ml.add_widget(meny) + self.addresses_list = filtered_list + self.addresses_list = [obj for obj in reversed(self.addresses_list)] + if self.addresses_list: + 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='Body1', @@ -294,6 +315,40 @@ class MyAddress(Screen): except Exception: pass + def set_mdList(self, first_index, last_index): + """This method is used to create 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: + meny = TwoLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['text'].strip())))) + meny.bind(on_press=partial( + self.myadd_detail, item['secondary_text'], item['text'])) + self.ids.ml.add_widget(meny) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to load data on scroll""" + if self.ids.refresh_layout.scroll_y <= -0.0 and self.has_refreshed: + self.ids.refresh_layout.scroll_y = 0.06 + my_addresses = len(self.ids.ml.children) + if my_addresses != len(self.addresses_list): + self.update_addressBook_on_scroll(my_addresses) + self.has_refreshed = True if my_addresses != len(self.addresses_list) else False + else: + pass + + def update_addressBook_on_scroll(self, my_addresses): + """This method is used to load more data on scroll down""" + self.set_mdList(my_addresses,my_addresses + 20) + @staticmethod def myadd_detail(fromaddress, label, *args): """Myaddress Details.""" @@ -309,6 +364,7 @@ class MyAddress(Screen): state.searcing_text = '' state.kivyapp.root.ids.sc10.children[2].active = False self.children[2].children[1].ids.search_field.text = '' + self.has_refreshed = True self.ids.ml.clear_widgets() self.init_ui() self.ids.refresh_layout.refresh_done() @@ -331,6 +387,8 @@ class MyAddress(Screen): class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" + queryreturn = ListProperty() + has_refreshed = True def __init__(self, *args, **kwargs): """Getting AddressBook Details.""" @@ -348,33 +406,13 @@ class AddressBook(Screen): where = ['label', 'address'] what = state.searcing_text xAddress = '' - queryreturn = kivy_helper_search.search_sql( + self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "addressbook", where, what, False) - if queryreturn: - for item in queryreturn: - meny = TwoLineAvatarIconListItem( - text=item[0], - secondary_text=item[1], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[0].strip())))) - meny.bind(on_press=partial( - self.addBook_detail, item[1], item[0])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete_address, item[1])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + self.queryreturn = [obj for obj in reversed(self.queryreturn)] + if self.queryreturn: + self.has_refreshed = True + self.set_mdList(0,20) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -387,6 +425,48 @@ class AddressBook(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdList(self, start_index, end_index): + """This method is used to create the mdList""" + for item in self.queryreturn[start_index:end_index]: + meny = TwoLineAvatarIconListItem( + text=item[0], + secondary_text=item[1], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[0].strip())))) + meny.bind(on_press=partial( + self.addBook_detail, item[1], item[0])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete_address, item[1])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to 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 + exist_addresses = len(self.ids.ml.children) + if exist_addresses != len(self.queryreturn): + self.update_addressBook_on_scroll(exist_addresses) + self.has_refreshed = True if exist_addresses != len(self.queryreturn) else False + else: + pass + + def update_addressBook_on_scroll(self, exist_addresses): + """This method is used to load more data on scroll down""" + self.set_mdList(exist_addresses,exist_addresses + 20) + @staticmethod def refreshs(*args): """Refresh the Widget.""" @@ -531,14 +611,13 @@ class DropDownWidget(BoxLayout): # .parent.parent.children[0].children[2].children[0].ids state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[2].children[0].ids - self.parent.parent.screens[0].ids.ml.clear_widgets() - self.parent.parent.screens[0].loadMessagelist(state.association) - self.parent.parent.screens[3].ids.ml.clear_widgets() - self.parent.parent.screens[3].loadSent(state.association) + # self.parent.parent.screens[0].ids.ml.clear_widgets() + # self.parent.parent.screens[0].loadMessagelist(state.association) + self.parent.parent.screens[3].update_sent_messagelist() self.parent.parent.screens[16].clear_widgets() self.parent.parent.screens[16].add_widget(Allmails()) - toast('sending...') - Clock.schedule_once(self.callback_for_msgsend, 6) + # toast('sending...') + Clock.schedule_once(self.callback_for_msgsend, 3) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" @@ -702,12 +781,14 @@ class Random(Screen): def generateaddress(self, navApp): """Method for Address Generator.""" + entered_label = str(self.ids.label.text).strip() streamNumberForAddress = 1 label = self.ids.label.text eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - if str(self.ids.label.text).strip(): + 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', @@ -730,9 +811,25 @@ class Random(Screen): self.manager.current = 'myaddress' toast('New address created') + def add_validation(self, 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: + self.ids.label.error = True + self.ids.label.helper_text = 'Label name is already exist' + elif entered_label: + self.ids.label.error = False + else: + self.ids.label.error = False + self.ids.label.helper_text = 'This field is required' + class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" + queryreturn = ListProperty() + has_refreshed = True + def __init__(self, *args, **kwargs): """Association with the screen.""" super(Sent, self).__init__(*args, **kwargs) @@ -758,57 +855,27 @@ class Sent(Screen): what = state.searcing_text xAddress = 'fromaddress' data = [] - queryreturn = kivy_helper_search.search_sql( + self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) if state.msg_counter_objs and state.association == state.check_sent_acc: - state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) + state.msg_counter_objs.send_cnt.badge_text = str(len(self.queryreturn)) state.sent_count = str(int(state.sent_count) + 1) state.all_count = str(int(state.all_count) + 1) state.msg_counter_objs.allmail_cnt.badge_text = state.all_count state.check_sent_acc = None - if queryreturn: - src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.send_cnt.badge_text = str(len(queryreturn)) - state.sent_count = str(len(queryreturn)) - for mail in queryreturn: + if self.queryreturn: + self.set_sentCount(len(self.queryreturn)) + for mail in self.queryreturn[0:20]: data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( mail[2]) >= 50 else ( mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'ackdata': mail[5]}) - for item in data: - meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - avatarImageFirstLetter(item['secondary_text'].strip())))) - meny.bind(on_press=partial( - self.sent_detail, item['ackdata'])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete, item['ackdata'])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - ach_btn = Button(text='Achieve') - ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial( - self.archive, item['ackdata'])) - carousel.add_widget(ach_btn) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + self.set_mdlist(data, 0) + self.has_refreshed = True + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -821,6 +888,90 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdlist(self, data, set_index): + """This method is used to create the mdList""" + for item in data: + meny = TwoLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) + meny.bind(on_press=partial( + self.sent_detail, item['ackdata'])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete, item['ackdata'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + ach_btn = Button(text='Achieve') + ach_btn.background_color = (0, 1, 0, 1) + ach_btn.bind(on_press=partial( + self.archive, item['ackdata'])) + carousel.add_widget(ach_btn) + carousel.index = 1 + self.ids.ml.add_widget(carousel, index=set_index) + + def update_sent_messagelist(self): + """This method is used to update screen when new mail is sent""" + if len(self.ids.ml.children) <3: + self.ids.ml.clear_widgets() + self.loadSent(state.association) + else: + account = state.association + data = [] + self.queryreturn = kivy_helper_search.search_sql( + 'fromaddress', account, "sent", '', '', False) + total_sent = len(self.queryreturn) + self.set_sentCount(total_sent) + for mail in self.queryreturn[:1]: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': mail[2][:50] + '........' if len( + mail[2]) >= 50 else ( + mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + 'ackdata': mail[5]}) + self.set_mdlist(data, total_sent-1) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to 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 + total_sent_msg = len(self.ids.ml.children) + if total_sent_msg != len(self.queryreturn): + self.update_sent_screen_on_scroll(total_sent_msg) + self.has_refreshed = True if total_sent_msg != len(self.queryreturn) else False + else: + pass + + def update_sent_screen_on_scroll(self, total_sent_msg): + """This method is used to load more data on scroll down""" + data = [] + for mail in self.queryreturn[total_sent_msg:total_sent_msg + 5]: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': mail[2][:50] + '........' if len( + mail[2]) >= 50 else ( + mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + 'ackdata': mail[5]}) + self.set_mdlist(data, 0) + + def set_sentCount(self, total_sent): + """Set the total no. of sent message count""" + src_mng_obj = state.kivyapp.root.children[2].children[0].ids + src_mng_obj.send_cnt.badge_text = str(total_sent) + state.sent_count = str(total_sent) + def sent_detail(self, ackdata, *args): """Load sent mail details.""" state.detailPageType = 'sent' @@ -882,6 +1033,8 @@ class Sent(Screen): class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" + trash_messages = ListProperty() + has_refreshed = True def __init__(self, *args, **kwargs): """Trash method, delete sent message and add in Trash.""" @@ -893,47 +1046,17 @@ class Trash(Screen): if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, received from" - " inbox WHERE folder = 'trash' and toaddress = '{}';".format( - state.association)) - sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from" - " sent WHERE folder = 'trash' and fromaddress = '{}';".format( - state.association)) - trash_data = inbox + sent - - if trash_data: + self.trash_messages = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime)" + " As actionTime FROM sent WHERE folder = 'trash' UNION" + " SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As" + " actionTime FROM inbox WHERE folder = 'trash' ORDER BY actionTime DESC") + if self.trash_messages: src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.trash_cnt.badge_text = str(len(trash_data)) - state.trash_count = str(len(trash_data)) - for item in trash_data: - meny = TwoLineAvatarIconListItem( - text=item[1], - secondary_text=item[2][:50] + '........' if len( - item[2]) >= 50 else ( - item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/text_images/{}.png'.format( - item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') - meny.add_widget(AvatarSampleWidget(source=img_latter)) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete_permanently, item[5])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + src_mng_obj.trash_cnt.badge_text = str(len(self.trash_messages)) + state.trash_count = str(len(self.trash_messages)) + self.set_mdList(0,20) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -945,6 +1068,51 @@ class Trash(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdList(self, first_index, last_index): + """This method is used to create the mdlist""" + for item in self.trash_messages[first_index:last_index]: + meny = TwoLineAvatarIconListItem( + text=item[1], + secondary_text=item[2][:50] + '........' if len( + item[2]) >= 50 else ( + item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + img_latter = './images/text_images/{}.png'.format( + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget(source=img_latter)) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete_permanently, item[5])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to 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 + total_trash_msg = len(self.ids.ml.children) + if total_trash_msg != len(self.trash_messages): + self.update_trash_screen_on_scroll(total_trash_msg) + self.has_refreshed = True if total_trash_msg != len(self.trash_messages) else False + else: + pass + + def update_trash_screen_on_scroll(self, total_trash_msg): + """This method is used to load more data on scroll down""" + self.set_mdList(total_trash_msg,total_trash_msg+5) + def delete_permanently(self, data_index, instance, *args): """Deleting trash mail permanently.""" pass @@ -1051,7 +1219,7 @@ class NavigateApp(App): self.root.ids.sc1.loadMessagelist(state.association) self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' + self.root.ids.sc4.children[2].children[1].ids.search_field.text = '' self.root.ids.sc4.loadSent(state.association) self.root.ids.sc16.clear_widgets() @@ -1145,7 +1313,9 @@ class NavigateApp(App): def on_key(self, window, key, *args): """Method is used for going on previous screen.""" if key == 27: - if self.root.ids.scr_mngr.current == "mailDetail": + if state.in_search_mode and self.root.ids.scr_mngr.current != "mailDetail": + 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' @@ -1164,20 +1334,39 @@ class NavigateApp(App): 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 platform == 'android': - if state.search_screen == 'inbox': - self.root.ids.sc1.ids.ml.clear_widgets() - self.root.ids.sc1.loadMessagelist(state.association) + elif key == 13: + if state.search_screen == 'inbox' and state.searcing_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.ml.clear_widgets() - self.root.ids.sc11.loadAddresslist(None, 'All', '') + 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.ml.clear_widgets() - self.root.ids.sc10.init_ui() - else: - self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.loadSent(state.association) - self.root.ids.scr_mngr.current = state.search_screen + self.root.ids.sc10.children[1].active = 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): + """This method is used to 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.root.ids.sc10.children[1].active = 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 save_draft(self): composer_objs = self.root @@ -1202,7 +1391,6 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" self.set_navbar_for_composer() - # self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[1].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -1228,7 +1416,13 @@ class NavigateApp(App): def back_press(self): """Method used for going back from composer to previous page.""" self.save_draft() - self.set_common_header() + 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() self.root.ids.scr_mngr.current = 'inbox' \ if state.in_composer else 'allmails'\ if state.is_allmail else state.detailPageType\ @@ -1269,23 +1463,10 @@ class NavigateApp(App): 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 = [['close', lambda x: self.closeSearchScreen()]] + toolbar_obj.left_action_items = [['arrow-left', lambda x: self.closeSearchScreen()]] toolbar_obj.right_action_items = [] self.root.ids.toolbar.title = '' - if platform == 'linux': - if state.search_screen == 'inbox': - self.root.ids.sc1.ids.ml.clear_widgets() - self.root.ids.sc1.loadMessagelist(state.association) - elif state.search_screen == 'addressbook': - self.root.ids.sc11.ids.ml.clear_widgets() - self.root.ids.sc11.loadAddresslist(None, 'All', '') - elif state.search_screen == 'myaddress': - self.root.ids.sc10.ids.ml.clear_widgets() - self.root.ids.sc10.init_ui() - else: - self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.loadSent(state.association) - self.root.ids.scr_mngr.current = state.search_screen + state.in_search_mode = True def closeSearchScreen(self): """Function for close search screen""" @@ -1293,7 +1474,9 @@ class NavigateApp(App): 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.""" @@ -1303,23 +1486,23 @@ class NavigateApp(App): self.root.ids.sc1.children[3].children[1].ids.search_field.text = '' except Exception: self.root.ids.sc1.children[2].children[1].ids.search_field.text = '' - self.root.ids.sc1.ids.ml.clear_widgets() - self.root.ids.sc1.loadMessagelist(state.association) + 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].children[1].ids.search_field.text = '' - self.root.ids.sc11.ids.ml.clear_widgets() - self.root.ids.sc11.loadAddresslist(None, 'All', '') + self.root.ids.sc11.children[2].children[1].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': try: self.root.ids.sc10.children[3].children[1].ids.search_field.text = '' except Exception: self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' - self.root.ids.sc10.ids.ml.clear_widgets() - self.root.ids.sc10.init_ui() + self.root.ids.sc10.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) else: - self.root.ids.sc4.children[1].children[1].ids.search_field.text = '' - self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.loadSent(state.association) + self.root.ids.sc4.children[2].children[1].ids.search_field.text = '' + self.root.ids.sc4.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) return def set_identicon(self, text): @@ -1364,13 +1547,15 @@ class GrashofPopup(Popup): stored_address = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] - if label and address and address not in stored_address: + stored_labels = [labels[0] for labels in kivy_helper_search.search_sql( + folder="addressbook")] + if label and address and address not in stored_address and label not in stored_labels: # state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - state.kivyapp.root.ids.sc11.ids.ml.clear_widgets() - state.kivyapp.root.ids.sc11.loadAddresslist(None, 'All', '') + self.parent.children[1].ids.sc11.ids.ml.clear_widgets() + self.parent.children[1].ids.sc11.loadAddresslist(None, 'All', '') self.parent.children[1].ids.scr_mngr.current = 'addressbook' toast('Saved') @@ -1400,7 +1585,7 @@ class GrashofPopup(Popup): toast('Canceled') def checkAddress_valid(self, instance): - """Checking is address is valid or not""" + """Checking address is valid or not""" my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values add_book = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] @@ -1411,18 +1596,26 @@ class GrashofPopup(Popup): text = 'You can not save your own address.' if entered_text in my_addresses or entered_text in add_book: - if len(self.ids.popup_box.children) <= 2: - err_msg = MDLabel( - id='erro_msg', - font_style='Body2', - text=text, - font_size=5) - err_msg.color = 1, 0, 0, 1 - self.ids.popup_box.add_widget(err_msg) - self.ids.save_addr.disabled = True - elif len(self.ids.popup_box.children) > 2: - self.ids.popup_box.remove_widget(self.ids.popup_box.children[0]) - self.ids.save_addr.disabled = False + self.ids.address.error = True + self.ids.address.helper_text = text + elif entered_text: + self.ids.address.error = False + else: + self.ids.address.error = False + self.ids.address.helper_text = 'This field is required' + + def checkLabel_valid(self, instance): + """Checking address label is unique of not""" + entered_label = instance.text.strip() + addr_labels = [labels[0] for labels in kivy_helper_search.search_sql(folder="addressbook")] + if entered_label in addr_labels: + self.ids.label.error = True + self.ids.label.helper_text = 'label name already exists.' + elif entered_label: + self.ids.label.error = False + else: + self.ids.label.error = False + self.ids.label.helper_text = 'This field is required' class AvatarSampleWidget(ILeftBody, Image): @@ -1519,6 +1712,7 @@ class MailDetail(Screen): def delete_mail(self): """Method for mail delete.""" msg_count_objs = state.kivyapp.root.children[2].children[0].ids + state.searcing_text = '' if state.detailPageType == 'sent': sqlExecute( "UPDATE sent SET folder = 'trash' WHERE" @@ -1650,7 +1844,13 @@ class AddbookDetailPopup(Popup): def update_addbook_label(self, address): """Updating the label of address book address.""" - if str(self.ids.add_label.text): + address_list = kivy_helper_search.search_sql(folder="addressbook") + stored_labels = [labels[0] for labels in address_list] + add_dict = dict(address_list) + label = str(self.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: sqlExecute( "UPDATE addressbook SET label = '{}' WHERE" " address = '{}';".format(str(self.ids.add_label.text), address)) @@ -1676,6 +1876,21 @@ class AddbookDetailPopup(Popup): """Pop is Canceled.""" toast('Canceled') + def checkLabel_valid(self, instance): + """Checking address label is unique of not""" + entered_label = str(instance.text.strip()) + address_list = kivy_helper_search.search_sql(folder="addressbook") + 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 ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" @@ -1694,6 +1909,8 @@ class Draft(Screen): """Draft screen is used to show the list of draft messages.""" data = ListProperty() + queryreturn = ListProperty() + has_refreshed = True def __init__(self, *args, **kwargs): """Method used for storing draft messages.""" @@ -1716,48 +1933,16 @@ class Draft(Screen): def loadDraft(self, account, where="", what=""): """Load draft list for Draft messages.""" xAddress = 'fromaddress' - queryreturn = kivy_helper_search.search_sql( + self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "draft", where, what, False) if state.msg_counter_objs: - state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) - if queryreturn: + state.msg_counter_objs.draft_cnt.badge_text = str(len(self.queryreturn)) + if self.queryreturn: src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.draft_cnt.badge_text = str(len(queryreturn)) - state.draft_count = str(len(queryreturn)) - for mail in queryreturn: - third_text = mail[3].replace('\n', ' ') - self.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]}) - for item in self.data: - meny = TwoLineAvatarIconListItem( - text='Draft', - secondary_text=item['text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/avatar.png')) - meny.bind(on_press=partial( - self.draft_detail, item['ackdata'])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete_draft, item['ackdata'])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + src_mng_obj.draft_cnt.badge_text = str(len(self.queryreturn)) + state.draft_count = str(len(self.queryreturn)) + self.set_mdList(0,20) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -1769,6 +1954,59 @@ class Draft(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdList(self, first_index, last_index): + """This method is used to create mdlist""" + data = [] + for mail in self.queryreturn[first_index:last_index]: + 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]}) + for item in data: + meny = TwoLineAvatarIconListItem( + text='Draft', + secondary_text=item['text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/avatar.png')) + meny.bind(on_press=partial( + self.draft_detail, item['ackdata'])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete_draft, item['ackdata'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """This method is used to 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 + total_draft_msg = len(self.ids.ml.children) + if total_draft_msg != len(self.queryreturn): + self.update_draft_screen_on_scroll(total_draft_msg) + self.has_refreshed = True if total_draft_msg != len(self.queryreturn) else False + else: + pass + + def update_draft_screen_on_scroll(self, total_draft_msg): + """This method is used to load more data on scroll down""" + self.set_mdList(total_draft_msg,total_draft_msg+5) + def draft_detail(self, ackdata, *args): """Method used to show draft Details.""" state.detailPageType = 'draft' @@ -1859,6 +2097,8 @@ class Allmails(Screen): """all mails Screen uses screen to show widgets of screens.""" data = ListProperty() + has_refreshed = True + all_mails = ListProperty() def __init__(self, *args, **kwargs): """Method Parsing the address.""" @@ -1880,42 +2120,16 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" - all_mails = sqlQuery( + self.all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime)" " As actionTime FROM sent WHERE folder = 'sent' UNION" " SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As" " actionTime FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") - if all_mails: - state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(all_mails)) - state.all_count = str(len(all_mails)) - for item in all_mails: - meny = TwoLineAvatarIconListItem( - text=item[1], - secondary_text=item[2][:50] + '........' if len( - item[2]) >= 50 else ( - item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - avatarImageFirstLetter(item[2].strip())))) - meny.bind(on_press=partial( - self.mail_detail, item[5], item[4])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.swipe_delete, item[5], item[4])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) + if self.all_mails: + state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(self.all_mails)) + state.all_count = str(len(self.all_mails)) + self.set_mdlist(0, 20) + self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -1927,6 +2141,52 @@ class Allmails(Screen): valign='top') self.ids.ml.add_widget(content) + def set_mdlist(self, start_pnt, end_pnt): + """This method is used to create mdList for allmaills""" + for item in self.all_mails[start_pnt:end_pnt]: + meny = TwoLineAvatarIconListItem( + text=item[1], + secondary_text=item[2][:50] + '........' if len( + item[2]) >= 50 else ( + item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item[2].strip())))) + meny.bind(on_press=partial( + self.mail_detail, item[5], item[4])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.swipe_delete, item[5], item[4])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """This method is used for scrolling on fixing length""" + if self.ids.refresh_layout.scroll_y <= -0.00 and self.has_refreshed: + self.ids.refresh_layout.scroll_y = .06 + load_more = len(self.ids.ml.children) + self.updating_allmail(load_more) + pass + + def updating_allmail(self, load_more): + """This method is used to update the all mail listing value on the scroll of screen""" + if self.all_mails and load_more != len(self.all_mails): + state.all_count = str(len(self.all_mails)) + self.set_mdlist(load_more, load_more+5) + self.has_refreshed = True if load_more != len(self.all_mails) else False + def mail_detail(self, unique_id, folder, *args): """Load sent and inbox mail details.""" state.detailPageType = folder diff --git a/src/state.py b/src/state.py index 1a55b248..54251270 100644 --- a/src/state.py +++ b/src/state.py @@ -107,4 +107,6 @@ write_msg = {} availabe_credit = 0 -in_sent_method = False \ No newline at end of file +in_sent_method = False + +in_search_mode = False \ No newline at end of file From ccc21b33b0fe4132c8da267e89812a64b0cd08fc Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 21 Nov 2019 15:37:08 +0530 Subject: [PATCH 219/306] identiconGeneration fixes --- src/bitmessagekivy/identiconGeneration.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bitmessagekivy/identiconGeneration.py b/src/bitmessagekivy/identiconGeneration.py index a5dcf3d0..ca8bd3bd 100644 --- a/src/bitmessagekivy/identiconGeneration.py +++ b/src/bitmessagekivy/identiconGeneration.py @@ -1,16 +1,15 @@ """ -src/identiconGeneration.py -================================= +Core classes for loading images and converting them to a Texture. +The raw image data can be keep in memory for further access """ -# pylint: disable=import-error + import hashlib from io import BytesIO from PIL import Image from kivy.core.image import Image as CoreImage from kivy.uix.image import Image as kiImage -""" Core classes for loading images and converting them to a Texture. -The raw image data can be keep in memory for further access """ +# pylint: disable=import-error # constants From 6c9d1a26667e13a08c19de517ed1489c5012a507 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 21 Nov 2019 15:37:22 +0530 Subject: [PATCH 220/306] kivy_helper_search fixes --- src/bitmessagekivy/kivy_helper_search.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 16767fce..390d6fbd 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -1,6 +1,5 @@ """ -src/bitmessagekivy/kivy_helper_search.py -================================= +Sql queries for bitmessagekivy """ from helper_sql import sqlQuery @@ -14,14 +13,15 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w what = None if folder == "sent" or folder == "draft": - sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime - FROM sent ''' + sqlStatementBase = ( + '''SELECT toaddress, fromaddress, subject, message, status, ackdata,''' + ''' lastactiontime FROM sent ''') elif folder == "addressbook": sqlStatementBase = '''SELECT label, address From addressbook ''' else: - sqlStatementBase = '''SELECT folder, msgid, toaddress, message, fromaddress, subject, received, read - FROM inbox ''' + sqlStatementBase = ( + '''SELECT folder, msgid, toaddress, message, fromaddress, subject,''' + ''' received, read FROM inbox ''') sqlStatementParts = [] sqlArguments = [] From c08a49aec23343ef4e956c588e3fb7281f3a5058 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 21 Nov 2019 20:20:14 +0530 Subject: [PATCH 221/306] mpybit fixes --- src/bitmessagekivy/mpybit.py | 280 ++++++++++++++++++++++------------- 1 file changed, 179 insertions(+), 101 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index fdcf2da6..f85831da 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,8 +1,8 @@ """ -src/bitmessagekivy/mpybit.py -================================= +Bitmessage kivy interface """ -# pylint: disable=relative-import, unused-variable, import-error, no-name-in-module, too-many-lines +# pylint: disable=relative-import, unused-variable, import-error +# pylint: disable=no-name-in-module, too-many-lines, unused-argument import os import time from functools import partial @@ -62,7 +62,6 @@ import state from uikivysignaler import UIkivySignaler import identiconGeneration -# pylint: disable=unused-argument, too-few-public-methods def toast(text): @@ -123,12 +122,13 @@ class Inbox(Screen): data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( - mail[5]) >= 50 else ( - mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + mail[5]) >= 50 else (mail[5] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', 'msgid': mail[1]}) self.has_refreshed = True self.set_mdList(data) - self.children[2].children[0].children[0].bind(scroll_y=self.check_scroll_y) + self.children[2].children[0].children[0].bind( + scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -177,12 +177,14 @@ class Inbox(Screen): def check_scroll_y(self, instance, somethingelse): """This method is used to load data on scroll""" - if self.children[2].children[0].children[0].scroll_y <= -0.0 and self.has_refreshed: + if self.children[2].children[0].children[ + 0].scroll_y <= -0.0 and self.has_refreshed: self.children[2].children[0].children[0].scroll_y = 0.06 total_message = len(self.ids.ml.children) if total_message != len(self.queryreturn): self.update_inbox_screen_on_scroll(total_message) - self.has_refreshed = True if total_message != len(self.queryreturn) else False + self.has_refreshed = True if total_message != len( + self.queryreturn) else False else: pass @@ -194,8 +196,8 @@ class Inbox(Screen): data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( - mail[5]) >= 50 else ( - mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + mail[5]) >= 50 else (mail[5] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', 'msgid': mail[1]}) self.set_mdList(data) @@ -217,9 +219,12 @@ class Inbox(Screen): "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) try: - msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = ( + self.parent.parent.parent.parent.children[2].children[0].ids) except Exception: - msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = ( + self.parent.parent.parent.parent.parent.children[ + 2].children[0].ids) if int(state.inbox_count) > 0: msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) @@ -257,7 +262,8 @@ class Inbox(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application, While the spinner remains on the screen.""" + """Method updates the state of application, + While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" state.searcing_text = '' @@ -271,6 +277,7 @@ class Inbox(Screen): Clock.schedule_once(refresh_callback, 1) def set_root_layout(self): + """Setting root layout""" return self.parent.parent.parent @@ -329,7 +336,8 @@ class MyAddress(Screen): theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['text'].strip())))) + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['text'].strip())))) meny.bind(on_press=partial( self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) @@ -341,13 +349,14 @@ class MyAddress(Screen): my_addresses = len(self.ids.ml.children) if my_addresses != len(self.addresses_list): self.update_addressBook_on_scroll(my_addresses) - self.has_refreshed = True if my_addresses != len(self.addresses_list) else False + self.has_refreshed = True if my_addresses != len( + self.addresses_list) else False else: pass def update_addressBook_on_scroll(self, my_addresses): """This method is used to load more data on scroll down""" - self.set_mdList(my_addresses,my_addresses + 20) + self.set_mdList(my_addresses, my_addresses + 20) @staticmethod def myadd_detail(fromaddress, label, *args): @@ -358,7 +367,8 @@ class MyAddress(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application, While the spinner remains on the screen.""" + """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 = '' @@ -382,6 +392,7 @@ class MyAddress(Screen): return False def set_root_layout(self): + """Setting root layout""" return self.manager.parent.parent @@ -411,7 +422,7 @@ class AddressBook(Screen): self.queryreturn = [obj for obj in reversed(self.queryreturn)] if self.queryreturn: self.has_refreshed = True - self.set_mdList(0,20) + self.set_mdList(0, 20) self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -434,7 +445,8 @@ class AddressBook(Screen): theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[0].strip())))) + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item[0].strip())))) meny.bind(on_press=partial( self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') @@ -459,13 +471,14 @@ class AddressBook(Screen): exist_addresses = len(self.ids.ml.children) if exist_addresses != len(self.queryreturn): self.update_addressBook_on_scroll(exist_addresses) - self.has_refreshed = True if exist_addresses != len(self.queryreturn) else False + self.has_refreshed = True if exist_addresses != len( + self.queryreturn) else False else: pass def update_addressBook_on_scroll(self, exist_addresses): """This method is used to load more data on scroll down""" - self.set_mdList(exist_addresses,exist_addresses + 20) + self.set_mdList(exist_addresses, exist_addresses + 20) @staticmethod def refreshs(*args): @@ -488,9 +501,10 @@ class AddressBook(Screen): "DELETE FROM addressbook WHERE address = '{}';".format(address)) -class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, - RecycleBoxLayout): +class SelectableRecycleBoxLayout( + FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view.""" + # pylint: disable = too-many-ancestors pass @@ -536,7 +550,8 @@ class RV(RecycleView): class DropDownWidget(BoxLayout): """Adding Dropdown Widget.""" - # pylint: disable=too-many-statements, inconsistent-return-statements, too-many-locals + # pylint: disable=too-many-statements, too-many-locals + # pylint: disable=inconsistent-return-statements txt_input = ObjectProperty() rv = ObjectProperty() @@ -553,7 +568,8 @@ class DropDownWidget(BoxLayout): if sendMessageToPeople: if toAddress != '' and subject and message: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) + status, addressVersionNumber, streamNumber, ripe = ( + decodeAddress(toAddress)) if status == 'success': navApp.root.ids.sc3.children[0].active = True if state.detailPageType == 'draft' and state.send_draft_mail: @@ -575,9 +591,10 @@ class DropDownWidget(BoxLayout): from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' - if addressVersionNumber > 4 or addressVersionNumber <= 1: - print "addressVersionNumber > 4 \ - or addressVersionNumber <= 1" + if (addressVersionNumber > 4) or ( + addressVersionNumber <= 1): + print "addressVersionNumber > 4"\ + " or addressVersionNumber <= 1" if streamNumber > 1 or streamNumber == 0: print "streamNumber > 1 or streamNumber == 0" if statusIconColor == 'red': @@ -631,7 +648,9 @@ class DropDownWidget(BoxLayout): msg = 'Please fill the form' self.address_error_message(msg) - def callback_for_msgsend(self, dt=0): + @staticmethod + def callback_for_msgsend(dt=0): + """Callback method for messagesend""" state.kivyapp.root.ids.sc3.children[0].active = False state.in_sent_method = True state.kivyapp.back_press() @@ -711,13 +730,18 @@ class Payment(Screen): """Method helps to get the available credits""" # pylint: disable=no-self-use state.availabe_credit = instance.parent.children[1].text - existing_credits = state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text + existing_credits = ( + state.kivyapp.root.ids.sc18.ids.ml.children[0].children[ + 0].children[0].children[0].text) if len(existing_credits.split(' ')) > 1: - toast('We already have added free coins for the subscription to your account!') + toast( + 'We already have added free coins' + ' for the subscription to your account!') else: toast('Coins added to your account!') - state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[ - 0].children[0].text = '{0}'.format(state.availabe_credit) + state.kivyapp.root.ids.sc18.ids.ml.children[0].children[ + 0].children[0].children[0].text = '{0}'.format( + state.availabe_credit) class Credits(Screen): @@ -787,7 +811,8 @@ class Random(Screen): eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - lables = [BMConfigParser().get(obj, 'label') for obj in BMConfigParser().addresses()] + 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(( @@ -814,7 +839,8 @@ class Random(Screen): def add_validation(self, instance): """Checking validation at address creation time.""" entered_label = str(instance.text.strip()) - lables = [BMConfigParser().get(obj, 'label') for obj in BMConfigParser().addresses()] + lables = [BMConfigParser().get(obj, 'label') + for obj in BMConfigParser().addresses()] if entered_label in lables: self.ids.label.error = True self.ids.label.helper_text = 'Label name is already exist' @@ -857,8 +883,10 @@ class Sent(Screen): data = [] self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - if state.msg_counter_objs and state.association == state.check_sent_acc: - state.msg_counter_objs.send_cnt.badge_text = str(len(self.queryreturn)) + if state.msg_counter_objs and state.association == ( + state.check_sent_acc): + state.msg_counter_objs.send_cnt.badge_text = str( + len(self.queryreturn)) state.sent_count = str(int(state.sent_count) + 1) state.all_count = str(int(state.all_count) + 1) state.msg_counter_objs.allmail_cnt.badge_text = state.all_count @@ -870,8 +898,8 @@ class Sent(Screen): data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( - mail[2]) >= 50 else ( - mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', 'ackdata': mail[5]}) self.set_mdlist(data, 0) self.has_refreshed = True @@ -924,7 +952,7 @@ class Sent(Screen): def update_sent_messagelist(self): """This method is used to update screen when new mail is sent""" - if len(self.ids.ml.children) <3: + if len(self.ids.ml.children) < 3: self.ids.ml.clear_widgets() self.loadSent(state.association) else: @@ -938,10 +966,10 @@ class Sent(Screen): data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( - mail[2]) >= 50 else ( - mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', 'ackdata': mail[5]}) - self.set_mdlist(data, total_sent-1) + self.set_mdlist(data, total_sent - 1) def check_scroll_y(self, instance, somethingelse): """This method is used to load data on scroll""" @@ -950,7 +978,8 @@ class Sent(Screen): total_sent_msg = len(self.ids.ml.children) if total_sent_msg != len(self.queryreturn): self.update_sent_screen_on_scroll(total_sent_msg) - self.has_refreshed = True if total_sent_msg != len(self.queryreturn) else False + self.has_refreshed = True if total_sent_msg != len( + self.queryreturn) else False else: pass @@ -961,12 +990,13 @@ class Sent(Screen): data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( - mail[2]) >= 50 else ( - mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', 'ackdata': mail[5]}) self.set_mdlist(data, 0) - def set_sentCount(self, total_sent): + @staticmethod + def set_sentCount(total_sent): """Set the total no. of sent message count""" src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.send_cnt.badge_text = str(total_sent) @@ -1047,15 +1077,16 @@ class Trash(Screen): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime)" - " As actionTime FROM sent WHERE folder = 'trash' UNION" - " SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As" - " actionTime FROM inbox WHERE folder = 'trash' ORDER BY actionTime DESC") + "SELECT toaddress, fromaddress, subject, message, folder, ackdata" + " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" + " folder = 'trash' UNION SELECT toaddress, fromaddress, subject," + " message, folder, msgid As id, DATE(received) As actionTime FROM" + " inbox WHERE folder = 'trash' ORDER BY actionTime DESC") if self.trash_messages: src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.trash_cnt.badge_text = str(len(self.trash_messages)) state.trash_count = str(len(self.trash_messages)) - self.set_mdList(0,20) + self.set_mdList(0, 20) self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -1074,8 +1105,8 @@ class Trash(Screen): meny = TwoLineAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( - item[2]) >= 50 else ( - item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + item[2]) >= 50 else (item[2] + ',' + item[3].replace( + '\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) img_latter = './images/text_images/{}.png'.format( @@ -1105,13 +1136,14 @@ class Trash(Screen): total_trash_msg = len(self.ids.ml.children) if total_trash_msg != len(self.trash_messages): self.update_trash_screen_on_scroll(total_trash_msg) - self.has_refreshed = True if total_trash_msg != len(self.trash_messages) else False + self.has_refreshed = True if total_trash_msg != len( + self.trash_messages) else False else: pass def update_trash_screen_on_scroll(self, total_trash_msg): """This method is used to load more data on scroll down""" - self.set_mdList(total_trash_msg,total_trash_msg+5) + self.set_mdList(total_trash_msg, total_trash_msg + 5) def delete_permanently(self, data_index, instance, *args): """Deleting trash mail permanently.""" @@ -1232,7 +1264,8 @@ class NavigateApp(App): self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' - msg_counter_objs = self.root_window.children[2].children[2].children[0].ids + msg_counter_objs = ( + self.root_window.children[2].children[2].children[0].ids) state.sent_count = str( sqlQuery( "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" @@ -1278,12 +1311,16 @@ class NavigateApp(App): img = identiconGeneration.generate(BMConfigParser().addresses()[0]) self.createFolder('./images/default_identicon/') if platform == 'android': - # android_path = os.path.expanduser("~/user/0/org.test.bitapp/files/app/") - android_path = os.path.join(os.environ['ANDROID_PRIVATE'] + '/app/') + # android_path = os.path.expanduser + # ("~/user/0/org.test.bitapp/files/app/") + android_path = os.path.join( + os.environ['ANDROID_PRIVATE'] + '/app/') img.texture.save('{1}/images/default_identicon/{0}.png'.format( BMConfigParser().addresses()[0], android_path)) else: - img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) + img.texture.save( + './images/default_identicon/{}.png'.format( + BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' @@ -1300,7 +1337,8 @@ class NavigateApp(App): def get_default_image(): """Getting default image on address""" if BMConfigParser().addresses(): - return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + return './images/default_identicon/{}.png'.format( + BMConfigParser().addresses()[0]) return './images/no_identicons.png' @staticmethod @@ -1313,7 +1351,8 @@ class NavigateApp(App): def on_key(self, window, key, *args): """Method is used for going on previous screen.""" if key == 27: - if state.in_search_mode and self.root.ids.scr_mngr.current != "mailDetail": + if state.in_search_mode and self.root.ids.scr_mngr.current != ( + "mailDetail"): self.closeSearchScreen() elif self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = 'sent'\ @@ -1369,6 +1408,7 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = state.search_screen 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) @@ -1405,12 +1445,17 @@ class NavigateApp(App): 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)]] + ['refresh', + lambda x: self.root.ids.sc3.children[1].reset_composer()], + ['send', + lambda x: self.root.ids.sc3.children[1].send(self)]] def set_common_header(self): - 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()]] + """Common 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()]] return def back_press(self): @@ -1418,7 +1463,8 @@ class NavigateApp(App): 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.left_action_items = [ + ['arrow-left', lambda x: self.closeSearchScreen()]] toolbar_obj.right_action_items = [] self.root.ids.toolbar.title = '' else: @@ -1452,7 +1498,8 @@ class NavigateApp(App): addr = BMConfigParser().addresses()[0] first_name = BMConfigParser().get(addr, 'label') f_name = first_name.split() - label = f_name[0][:14].capitalize() + '...' if len(f_name[0]) > 15 else f_name[0].capitalize() + label = f_name[0][:14].capitalize() + '...' if len( + f_name[0]) > 15 else f_name[0].capitalize() address = ' (' + addr + '...)' return label + address return '' @@ -1463,7 +1510,8 @@ class NavigateApp(App): 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.left_action_items = [ + ['arrow-left', lambda x: self.closeSearchScreen()]] toolbar_obj.right_action_items = [] self.root.ids.toolbar.title = '' state.in_search_mode = True @@ -1472,7 +1520,8 @@ class NavigateApp(App): """Function for close search screen""" self.set_common_header() address_label = self.current_address_label( - BMConfigParser().get(state.association, 'label'), state.association) + BMConfigParser().get( + state.association, 'label'), state.association) self.root.ids.toolbar.title = address_label state.searcing_text = '' self.refreshScreen() @@ -1508,20 +1557,27 @@ class NavigateApp(App): def set_identicon(self, text): """This method is use for showing identicon in address spinner""" img = identiconGeneration.generate(text) - self.root.children[2].children[0].ids.btn.children[1].texture = img.texture + self.root.children[2].children[0].ids.btn.children[1].texture = ( + img.texture) def set_mail_detail_header(self): """Method is used for setting the details of the page""" 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()] + 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] + 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] + dynamic_list = [ + ['pencil', lambda x: self.root.ids.sc14.write_msg(self)], + delete_btn] toolbar_obj.right_action_items = dynamic_list @@ -1586,7 +1642,8 @@ class GrashofPopup(Popup): def checkAddress_valid(self, instance): """Checking address is valid or not""" - my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + my_addresses = ( + self.parent.children[1].children[2].children[0].ids.btn.values) add_book = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] entered_text = str(instance.text).strip() @@ -1607,7 +1664,9 @@ class GrashofPopup(Popup): def checkLabel_valid(self, instance): """Checking address label is unique of not""" entered_label = instance.text.strip() - addr_labels = [labels[0] for labels in kivy_helper_search.search_sql(folder="addressbook")] + addr_labels = [labels[0] + for labels in kivy_helper_search.search_sql( + folder="addressbook")] if entered_label in addr_labels: self.ids.label.error = True self.ids.label.helper_text = 'label name already exists.' @@ -1725,22 +1784,26 @@ class MailDetail(Screen): sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE" " msgid = ?;", str(state.mail_id)) - msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + msg_count_objs.inbox_cnt.badge_text = str( + int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( state.mail_id)) - msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) + msg_count_objs.draft_cnt.badge_text = str( + int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) self.parent.screens[15].clear_widgets() self.parent.screens[15].add_widget(Draft()) self.parent.current = 'allmails' if state.is_allmail else state.detailPageType if state.detailPageType != 'draft': - msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) - msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str( + int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) self.parent.screens[4].clear_widgets() @@ -1772,11 +1835,13 @@ class MailDetail(Screen): def write_msg(self, navApp): """Method used to write on draft mail.""" state.send_draft_mail = state.mail_id - composer_ids = self.parent.parent.parent.parent.parent.ids.sc3.children[1].ids + composer_ids = ( + self.parent.parent.parent.parent.parent.ids.sc3.children[1].ids) composer_ids.ti.text = state.write_msg['from_addr'] composer_ids.btn.text = state.write_msg['from_addr'] composer_ids.txt_input.text = state.write_msg['to_addr'] - composer_ids.subject.text = state.write_msg['subject'] if state.write_msg['subject'] != '(no subject)' else '' + composer_ids.subject.text = state.write_msg[ + 'subject'] if state.write_msg['subject'] != '(no subject)' else '' composer_ids.body.text = state.write_msg['message'] self.parent.current = 'create' navApp.set_navbar_for_composer() @@ -1853,7 +1918,8 @@ class AddbookDetailPopup(Popup): if label and label not in stored_labels: sqlExecute( "UPDATE addressbook SET label = '{}' WHERE" - " address = '{}';".format(str(self.ids.add_label.text), address)) + " address = '{}';".format( + str(self.ids.add_label.text), address)) self.parent.children[1].ids.sc11.ids.ml.clear_widgets() self.parent.children[1].ids.sc11.loadAddresslist(None, 'All', '') self.dismiss() @@ -1936,12 +2002,13 @@ class Draft(Screen): self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "draft", where, what, False) if state.msg_counter_objs: - state.msg_counter_objs.draft_cnt.badge_text = str(len(self.queryreturn)) + state.msg_counter_objs.draft_cnt.badge_text = str( + len(self.queryreturn)) if self.queryreturn: src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.draft_cnt.badge_text = str(len(self.queryreturn)) state.draft_count = str(len(self.queryreturn)) - self.set_mdList(0,20) + self.set_mdList(0, 20) self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -1999,13 +2066,14 @@ class Draft(Screen): total_draft_msg = len(self.ids.ml.children) if total_draft_msg != len(self.queryreturn): self.update_draft_screen_on_scroll(total_draft_msg) - self.has_refreshed = True if total_draft_msg != len(self.queryreturn) else False + self.has_refreshed = True if total_draft_msg != len( + self.queryreturn) else False else: pass def update_draft_screen_on_scroll(self, total_draft_msg): """This method is used to load more data on scroll down""" - self.set_mdList(total_draft_msg,total_draft_msg+5) + self.set_mdList(total_draft_msg, total_draft_msg + 5) def draft_detail(self, ackdata, *args): """Method used to show draft Details.""" @@ -2024,7 +2092,8 @@ class Draft(Screen): sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( data_index)) try: - msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = ( + self.parent.parent.parent.parent.children[2].children[0].ids) except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids @@ -2048,7 +2117,8 @@ class Draft(Screen): sendMessageToPeople = True if sendMessageToPeople: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress) from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' @@ -2121,12 +2191,14 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" self.all_mails = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata As id, DATE(lastactiontime)" - " As actionTime FROM sent WHERE folder = 'sent' UNION" - " SELECT toaddress, fromaddress, subject, message, folder, msgid As id, DATE(received) As" - " actionTime FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") + "SELECT toaddress, fromaddress, subject, message, folder, ackdata" + " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" + " folder = 'sent' UNION SELECT toaddress, fromaddress, subject," + " message, folder, msgid As id, DATE(received) As actionTime" + " FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") if self.all_mails: - state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str(len(self.all_mails)) + state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str( + len(self.all_mails)) state.all_count = str(len(self.all_mails)) self.set_mdlist(0, 20) self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) @@ -2148,7 +2220,8 @@ class Allmails(Screen): text=item[1], secondary_text=item[2][:50] + '........' if len( item[2]) >= 50 else ( - item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + item[2] + ',' + item[3].replace( + '\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( @@ -2178,14 +2251,17 @@ class Allmails(Screen): self.ids.refresh_layout.scroll_y = .06 load_more = len(self.ids.ml.children) self.updating_allmail(load_more) - pass + else: + pass def updating_allmail(self, load_more): - """This method is used to update the all mail listing value on the scroll of screen""" + """This method is used to update the all mail + listing value on the scroll of screen""" if self.all_mails and load_more != len(self.all_mails): state.all_count = str(len(self.all_mails)) - self.set_mdlist(load_more, load_more+5) - self.has_refreshed = True if load_more != len(self.all_mails) else False + self.set_mdlist(load_more, load_more + 5) + self.has_refreshed = True if load_more != len( + self.all_mails) else False def mail_detail(self, unique_id, folder, *args): """Load sent and inbox mail details.""" @@ -2259,6 +2335,7 @@ class Allmails(Screen): Clock.schedule_once(refresh_callback, 1) def set_root_layout(self): + """Setting root layout""" try: return self.manager.parent.parent except Exception as e: @@ -2297,6 +2374,7 @@ class Spam(Screen): class LoadingPopup(Popup): """Load Popup""" + def __init__(self, **kwargs): super(LoadingPopup, self).__init__(**kwargs) # call dismiss_popup in 2 seconds From 912a0a0a1e7496501140715f2fb9c1bdb1717f30 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 22 Nov 2019 17:03:20 +0530 Subject: [PATCH 222/306] mpybit quality fixes --- src/bitmessagekivy/mpybit.py | 152 +++++++++++++++++------------------ 1 file changed, 72 insertions(+), 80 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index f85831da..6413c448 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,8 +1,8 @@ """ Bitmessage kivy interface """ -# pylint: disable=relative-import, unused-variable, import-error -# pylint: disable=no-name-in-module, too-many-lines, unused-argument +# pylint: disable=relative-import, import-error, no-name-in-module +# pylint: disable=too-few-public-methods, too-many-lines, unused-argument import os import time from functools import partial @@ -65,7 +65,7 @@ import identiconGeneration def toast(text): - """Method will display the toast message.""" + """Function displays toast message.""" # pylint: disable=redefined-outer-name from kivymd.toast.kivytoast import toast toast(text) @@ -73,8 +73,7 @@ def toast(text): class Navigatorss(MDNavigationDrawer): - """Navigators class contains image, title and logo.""" - + """Navigator class contains image, title and logo.""" image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() @@ -118,7 +117,7 @@ class Inbox(Screen): src_mng_obj.inbox_cnt.badge_text = str(len(self.queryreturn)) state.inbox_count = str(len(self.queryreturn)) for mail in self.queryreturn[:20]: - third_text = mail[3].replace('\n', ' ') + # third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( @@ -192,7 +191,7 @@ class Inbox(Screen): """This method is used to load more data on scroll down""" data = [] for mail in self.queryreturn[total_message:total_message + 5]: - third_text = mail[3].replace('\n', ' ') + # third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( @@ -511,7 +510,6 @@ class SelectableRecycleBoxLayout( class SelectableLabel(RecycleDataViewBehavior, Label): """Add selection support to the Label.""" - index = None selected = BooleanProperty(False) selectable = BooleanProperty(True) @@ -552,7 +550,6 @@ class DropDownWidget(BoxLayout): """Adding Dropdown Widget.""" # pylint: disable=too-many-statements, too-many-locals # pylint: disable=inconsistent-return-statements - txt_input = ObjectProperty() rv = ObjectProperty() @@ -572,7 +569,8 @@ class DropDownWidget(BoxLayout): decodeAddress(toAddress)) if status == 'success': navApp.root.ids.sc3.children[0].active = True - if state.detailPageType == 'draft' and state.send_draft_mail: + if state.detailPageType == 'draft' \ + and state.send_draft_mail: sqlExecute( "UPDATE sent SET toaddress = ?" ", fromaddress = ? , subject = ?" @@ -603,7 +601,7 @@ class DropDownWidget(BoxLayout): 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - t = () + # t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', @@ -635,7 +633,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.screens[16].add_widget(Allmails()) # toast('sending...') Clock.schedule_once(self.callback_for_msgsend, 3) - toLabel = '' + # toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" state.in_composer = True @@ -687,7 +685,6 @@ class DropDownWidget(BoxLayout): class MyTextInput(TextInput): """Takes the text input in the field.""" - txt_input = ObjectProperty() flt_list = ObjectProperty() word_list = ListProperty() @@ -746,19 +743,16 @@ class Payment(Screen): class Credits(Screen): """Credits Method""" - available_credits = StringProperty( - '{0}'.format('0')) + available_credits = StringProperty('{0}'.format('0')) class Login(Screen): """Login Screeen.""" - pass class NetworkStat(Screen): """Method used to show network stat.""" - text_variable_1 = StringProperty( '{0}::{1}'.format('Total Connections', '0')) text_variable_2 = StringProperty( @@ -793,13 +787,11 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): """Navigate Content Drawer.""" - pass class Random(Screen): """Generates Random Address.""" - is_active = BooleanProperty(False) checked = StringProperty("") @@ -1179,7 +1171,6 @@ class Setting(Screen): class NavigateApp(App): """Navigation Layout of class.""" # pylint: disable=too-many-public-methods - theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() @@ -1412,7 +1403,8 @@ class NavigateApp(App): 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 to_addr and state.detailPageType != 'draft' and not state.in_sent_method: + if from_addr and to_addr and state.detailPageType != 'draft' \ + and not state.in_sent_method: Draft().draft_msg(composer_objs) return @@ -1446,9 +1438,9 @@ class NavigateApp(App): ['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()], + lambda x: self.root.ids.sc3.children[1].reset_composer()], ['send', - lambda x: self.root.ids.sc3.children[1].send(self)]] + lambda x: self.root.ids.sc3.children[1].send(self)]] def set_common_header(self): """Common for all window""" @@ -1461,7 +1453,8 @@ class NavigateApp(App): def back_press(self): """Method used for going back from composer to previous page.""" self.save_draft() - if self.root.ids.scr_mngr.current == 'mailDetail' and state.in_search_mode: + 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()]] @@ -1527,32 +1520,39 @@ class NavigateApp(App): self.refreshScreen() state.in_search_mode = False - def refreshScreen(self): - """Method show search button only on inbox or sent screen.""" - state.searcing_text = '' - if state.search_screen == 'inbox': - try: - self.root.ids.sc1.children[3].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc1.children[2].children[1].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.children[2].children[1].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': - try: - self.root.ids.sc10.children[3].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc10.children[2].children[1].ids.search_field.text = '' - self.root.ids.sc10.children[1].active = True - Clock.schedule_once(self.search_callback, 0.5) - else: - self.root.ids.sc4.children[2].children[1].ids.search_field.text = '' - self.root.ids.sc4.children[1].active = True - Clock.schedule_once(self.search_callback, 0.5) - return + def refreshScreen(self): # pylint: disable=unused-variable + """Method show search button only on inbox or sent screen.""" + state.searcing_text = '' + if state.search_screen == 'inbox': + try: + self.root.ids.sc1.children[ + 3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc1.children[ + 2].children[1].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.children[ + 2].children[1].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': + try: + self.root.ids.sc10.children[ + 3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc10.children[ + 2].children[1].ids.search_field.text = '' + self.root.ids.sc10.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + else: + self.root.ids.sc4.children[ + 2].children[1].ids.search_field.text = '' + self.root.ids.sc4.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + return def set_identicon(self, text): """This method is use for showing identicon in address spinner""" @@ -1605,7 +1605,8 @@ class GrashofPopup(Popup): folder="addressbook")] stored_labels = [labels[0] for labels in kivy_helper_search.search_sql( folder="addressbook")] - if label and address and address not in stored_address and label not in stored_labels: + if label and address and address not in stored_address \ + and label not in stored_labels: # state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() @@ -1664,8 +1665,7 @@ class GrashofPopup(Popup): def checkLabel_valid(self, instance): """Checking address label is unique of not""" entered_label = instance.text.strip() - addr_labels = [labels[0] - for labels in kivy_helper_search.search_sql( + addr_labels = [labels[0] for labels in kivy_helper_search.search_sql( folder="addressbook")] if entered_label in addr_labels: self.ids.label.error = True @@ -1679,26 +1679,22 @@ class GrashofPopup(Popup): class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" - pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): """Left icon sample widget.""" - pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): """Right icon sample widget.""" - pass class NavigationDrawerTwoLineListItem( TwoLineListItem, NavigationDrawerHeaderBase): """Navigation Drawer in Listitems.""" - address_property = StringProperty() def __init__(self, **kwargs): @@ -1723,7 +1719,6 @@ class NavigationDrawerTwoLineListItem( class MailDetail(Screen): """MailDetail Screen uses to show the detail of mails.""" - to_addr = StringProperty() from_addr = StringProperty() subject = StringProperty() @@ -1798,7 +1793,8 @@ class MailDetail(Screen): self.parent.screens[15].clear_widgets() self.parent.screens[15].add_widget(Draft()) - self.parent.current = 'allmails' if state.is_allmail else state.detailPageType + self.parent.current = 'allmails' \ + if state.is_allmail else state.detailPageType if state.detailPageType != 'draft': msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) @@ -1859,7 +1855,6 @@ class MailDetail(Screen): class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail.""" - address_label = StringProperty() address = StringProperty() @@ -1893,7 +1888,6 @@ class MyaddDetailPopup(Popup): class AddbookDetailPopup(Popup): """AddbookDetailPopup pop is used for showing my address detail.""" - address_label = StringProperty() address = StringProperty() @@ -1948,7 +1942,8 @@ class AddbookDetailPopup(Popup): address_list = kivy_helper_search.search_sql(folder="addressbook") 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]: + 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: @@ -1973,7 +1968,6 @@ class ShowQRCode(Screen): class Draft(Screen): """Draft screen is used to show the list of draft messages.""" - data = ListProperty() queryreturn = ListProperty() has_refreshed = True @@ -2117,16 +2111,17 @@ class Draft(Screen): sendMessageToPeople = True if sendMessageToPeople: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) + # status, addressVersionNumber, streamNumber, ripe = decodeAddress( + # toAddress) + streamNumber, ripe = decodeAddress(toAddress)[2:] from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) - statusIconColor = 'red' + # statusIconColor = 'red' stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - t = () + # t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', @@ -2165,7 +2160,6 @@ class CustomSpinner(Spinner): class Allmails(Screen): """all mails Screen uses screen to show widgets of screens.""" - data = ListProperty() has_refreshed = True all_mails = ListProperty() @@ -2197,8 +2191,9 @@ class Allmails(Screen): " message, folder, msgid As id, DATE(received) As actionTime" " FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") if self.all_mails: - state.kivyapp.root.children[2].children[0].ids.allmail_cnt.badge_text = str( - len(self.all_mails)) + state.kivyapp.root.children[2].children[ + 0].ids.allmail_cnt.badge_text = str( + len(self.all_mails)) state.all_count = str(len(self.all_mails)) self.set_mdlist(0, 20) self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) @@ -2277,7 +2272,7 @@ class Allmails(Screen): src_mng_obj.current = 'mailDetail' def swipe_delete(self, unique_id, folder, instance, *args): - """Delete inbox mail from all mail listing listing.""" + """Delete inbox mail from all mail listing.""" if folder == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( @@ -2320,7 +2315,8 @@ class Allmails(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application, While the spinner remains on the screen.""" + """Method updates the state of application, + While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the allmails screen data.""" self.ids.ml.clear_widgets() @@ -2338,42 +2334,38 @@ class Allmails(Screen): """Setting root layout""" try: return self.manager.parent.parent - except Exception as e: + except Exception: return state.kivyapp.root.ids.float_box def avatarImageFirstLetter(letter_string): - """This method is used to the first letter for the avatar image""" + """This function is used to the first letter for the avatar image""" 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 = '!' - return img_latter class Starred(Screen): """Starred Screen show widgets of page.""" - pass class Archieve(Screen): """Archieve Screen show widgets of page.""" - pass class Spam(Screen): """Spam Screen show widgets of page.""" - pass class LoadingPopup(Popup): - """Load Popup""" + """Class for loading Popup""" def __init__(self, **kwargs): super(LoadingPopup, self).__init__(**kwargs) @@ -2381,5 +2373,5 @@ class LoadingPopup(Popup): Clock.schedule_once(self.dismiss_popup, 0.5) def dismiss_popup(self, dt): - """Dismissing popup""" + """Dismiss popups""" self.dismiss() From af52d95503cc579035aa8035c0ded2281dc8c5ea Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:14:45 +0530 Subject: [PATCH 223/306] bitmessagemain quality fixes --- src/bitmessagemain.py | 49 ++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c70eb0bf..176125cc 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,7 @@ #!/usr/bin/python2.7 +""" +The PyBitmessage startup script +""" # Copyright (c) 2012-2016 Jonathan Warren # Copyright (c) 2012-2019 The Bitmessage developers # Distributed under the MIT/X11 software license. See the accompanying @@ -53,6 +56,7 @@ from threads import ( def connectToStream(streamNumber): + """Connect to a stream""" state.streamsInWhichIAmParticipating.append(streamNumber) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -85,6 +89,7 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): + """Converting an IP address in packed binary format to string format""" if family == socket.AF_INET: if len(host) != 4: raise ValueError("invalid IPv4 host") @@ -106,6 +111,7 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): + """Converting an IP address in string format to a packed binary format""" buf = "\0" * 28 lengthBuf = pack("I", len(buf)) if stringToAddress(str(host), @@ -160,7 +166,8 @@ def signal_handler(signum, frame): ' because the UI captures the signal.') -class Main: +class Main(object): + """Main PyBitmessage class""" @staticmethod def start_proxyconfig(config): """Check socksproxytype and start any proxy configuration plugin""" @@ -183,14 +190,15 @@ class Main: 'Started proxy config plugin %s in %s sec', proxy_type, time.time() - proxyconfig_start) - def start(self): + def start(self): # pylint: disable=too-many-statements, too-many-branches, too-many-locals + """Start main application""" _fixSocket() config = BMConfigParser() daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') try: - opts, args = getopt.getopt( + opts, _ = getopt.getopt( sys.argv[1:], "hcdt", ["help", "curses", "daemon", "test"]) @@ -198,7 +206,7 @@ class Main: self.usage() sys.exit(2) - for opt, arg in opts: + for opt, _ in opts: if opt in ("-h", "--help"): self.usage() sys.exit() @@ -412,7 +420,9 @@ class Main: else 0 ) - def daemonize(self): + @staticmethod + def daemonize(): + """Running as a daemon. Send signal in end.""" grandfatherPid = os.getpid() parentPid = None try: @@ -422,7 +432,7 @@ class Main: # wait until grandchild ready while True: time.sleep(1) - os._exit(0) + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass @@ -443,7 +453,7 @@ class Main: # wait until child ready while True: time.sleep(1) - os._exit(0) + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass @@ -464,14 +474,18 @@ class Main: os.kill(parentPid, signal.SIGTERM) os.kill(grandfatherPid, signal.SIGTERM) - def setSignalHandler(self): + @staticmethod + def setSignalHandler(): + """Setting the Signal Handler""" signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # signal.signal(signal.SIGINT, signal.SIG_DFL) - def usage(self): - print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' - print ''' + @staticmethod + def usage(): + """Displaying the usages""" + print('Usage: ' + sys.argv[0] + ' [OPTIONS]') + print(''' Options: -h, --help show this help message and exit -c, --curses use curses (text mode) interface @@ -479,15 +493,19 @@ Options: -t, --test dryrun, make testing All parameters are optional. -''' +''') - def stop(self): + @staticmethod + def stop(): + """Stop main application""" with shared.printLock: print('Stopping Bitmessage Deamon.') shutdown.doCleanShutdown() - # TODO: nice function but no one is using this - def getApiAddress(self): + # .. todo:: nice function but no one is using this + @staticmethod + def getApiAddress(): + """This function returns API address and port""" if not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'apienabled'): return None @@ -497,6 +515,7 @@ All parameters are optional. def main(): + """Triggers main module""" mainprogram = Main() mainprogram.start() From 77b8b5aa4236dbd11264797850dc4a1961841f89 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:15:02 +0530 Subject: [PATCH 224/306] bmconfigparser quality fixes --- src/bmconfigparser.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 7f28d1b8..1851144d 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -58,7 +58,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): raise ValueError("Invalid value %s" % value) return ConfigParser.ConfigParser.set(self, section, option, value) - def get(self, section, option, raw=False, variables=None): + def get(self, section, option, raw=False, variables=None): # pylint: disable=arguments-differ try: if section == "bitmessagesettings" and option == "timeformat": return ConfigParser.ConfigParser.get( @@ -86,6 +86,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): self._temp[section] = {option: value} def safeGetBoolean(self, section, field): + """Return value as boolean, False on exceptions""" try: return self.getboolean(section, field) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, @@ -93,6 +94,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return False def safeGetInt(self, section, field, default=0): + """Return value as integer, default on exceptions, 0 if default missing""" try: return self.getint(section, field) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, @@ -100,18 +102,22 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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): + def items(self, section, raw=False, variables=None): # pylint: disable=arguments-differ + """Return section variables as parent, but override the "raw" argument to always True""" return ConfigParser.ConfigParser.items(self, section, True, variables) - def addresses(self): - return filter( - lambda x: x.startswith('BM-'), BMConfigParser().sections()) + @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): ConfigParser.ConfigParser.read(self, filenames) @@ -132,6 +138,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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']) @@ -153,12 +160,15 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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 - def validate_bitmessagesettings_maxoutboundconnections(self, value): + @staticmethod + def validate_bitmessagesettings_maxoutboundconnections(value): + """Reject maxoutboundconnections that are too high or too low""" try: value = int(value) except ValueError: From e534994ee34e3d95908bafbb54289d9b1220259c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:15:18 +0530 Subject: [PATCH 225/306] class_addressGenerator quality fixes --- src/class_addressGenerator.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c7c7e261..9e19cf50 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -1,4 +1,6 @@ - +""" +A thread for creating addresses +""" import time import hashlib from binascii import hexlify @@ -18,6 +20,7 @@ from network import StoppableThread class addressGenerator(StoppableThread): + """A thread for creating addresses""" name = "addressGenerator" @@ -33,6 +36,7 @@ class addressGenerator(StoppableThread): Process the requests for addresses generation from `.queues.addressGeneratorQueue` """ + # pylint: disable=too-many-locals, too-many-branches, protected-access, too-many-statements while state.shutdown == 0: queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 @@ -212,7 +216,7 @@ class addressGenerator(StoppableThread): elif command == 'createDeterministicAddresses' \ or command == 'getDeterministicAddress' \ or command == 'createChan' or command == 'joinChan': - if len(deterministicPassphrase) == 0: + if not deterministicPassphrase: self.logger.warning( 'You are creating deterministic' ' address(es) using a blank passphrase.' @@ -361,7 +365,7 @@ class addressGenerator(StoppableThread): address) shared.myECCryptorObjects[ripe] = \ highlevelcrypto.makeCryptor( - hexlify(potentialPrivEncryptionKey)) + hexlify(potentialPrivEncryptionKey)) shared.myAddressesByHash[ripe] = address tag = hashlib.sha512(hashlib.sha512( encodeVarint(addressVersionNumber) + From 059e82e2a2b1d831e83a274ca2fa10f1dc9b51ff Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:15:36 +0530 Subject: [PATCH 226/306] class_objectProcessor quality fixes --- src/class_objectProcessor.py | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index b22876e8..2c741661 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -1,7 +1,9 @@ +""" +The objectProcessor thread, of which there is only one, processes the network objects +""" import hashlib import logging import random -import shared import threading import time from binascii import hexlify @@ -9,11 +11,13 @@ from subprocess import call # nosec import highlevelcrypto import knownnodes +import shared from addresses import ( calculateInventoryHash, decodeAddress, decodeVarint, encodeAddress, encodeVarint, varintDecodeError ) from bmconfigparser import BMConfigParser + import helper_bitcoin import helper_inbox import helper_msgcoding @@ -22,12 +26,15 @@ from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery from helper_ackPayload import genAckPayload from network import bmproto from network.node import Peer + import protocol import queues import state import tr from fallback import RIPEMD160Hash + import l10n +# pylint: disable=too-many-locals, too-many-return-statements, too-many-branches, too-many-statements logger = logging.getLogger('default') @@ -122,7 +129,10 @@ class objectProcessor(threading.Thread): state.shutdown = 2 break - def checkackdata(self, data): + @staticmethod + def checkackdata(data): + """Checking Acknowledgement of message received or not?""" + # pylint: disable=protected-access # Let's check whether this is a message acknowledgement bound for us. if len(data) < 32: return @@ -272,6 +282,7 @@ class objectProcessor(threading.Thread): queues.workerQueue.put(('sendOutOrStoreMyV4Pubkey', myAddress)) def processpubkey(self, data): + """Process a pubkey object""" pubkeyProcessingStartTime = time.time() shared.numberOfPubkeysProcessed += 1 queues.UISignalQueue.put(( @@ -444,6 +455,7 @@ class objectProcessor(threading.Thread): timeRequiredToProcessPubkey) def processmsg(self, data): + """Process a message object""" messageProcessingStartTime = time.time() shared.numberOfMessagesProcessed += 1 queues.UISignalQueue.put(( @@ -739,7 +751,7 @@ class objectProcessor(threading.Thread): # We really should have a discussion about how to # set the TTL for mailing list broadcasts. This is obviously # hard-coded. - TTL = 2*7*24*60*60 # 2 weeks + TTL = 2 * 7 * 24 * 60 * 60 # 2 weeks t = ('', toAddress, ripe, @@ -791,6 +803,7 @@ class objectProcessor(threading.Thread): ) def processbroadcast(self, data): + """Process a broadcast object""" messageProcessingStartTime = time.time() shared.numberOfBroadcastsProcessed += 1 queues.UISignalQueue.put(( @@ -975,7 +988,7 @@ class objectProcessor(threading.Thread): fromAddress = encodeAddress( sendersAddressVersion, sendersStream, calculatedRipe) - logger.info('fromAddress: %s' % fromAddress) + logger.info('fromAddress: %s', fromAddress) # Let's store the public key in case we want to reply to this person. sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', @@ -992,7 +1005,7 @@ class objectProcessor(threading.Thread): fromAddress = encodeAddress( sendersAddressVersion, sendersStream, calculatedRipe) - logger.debug('fromAddress: ' + fromAddress) + logger.debug('fromAddress: %s', fromAddress) try: decodedMessage = helper_msgcoding.MsgDecode( @@ -1060,7 +1073,8 @@ class objectProcessor(threading.Thread): del state.neededPubkeys[tag] self.sendMessages(address) - def sendMessages(self, address): + @staticmethod + def sendMessages(address): """ This method is called by the `possibleNewPubkey` when it sees that we now have the necessary pubkey to send one or more messages. @@ -1073,7 +1087,9 @@ class objectProcessor(threading.Thread): " AND folder='sent'", address) queues.workerQueue.put(('sendmessage', '')) - def ackDataHasAValidHeader(self, ackData): + @staticmethod + def ackDataHasAValidHeader(ackData): + """Checking ackData with valid Header, not sending ackData when false""" if len(ackData) < protocol.Header.size: logger.info( 'The length of ackData is unreasonably short. Not sending' @@ -1108,11 +1124,12 @@ class objectProcessor(threading.Thread): return False return True - def addMailingListNameToSubject(self, subject, mailingListName): + @staticmethod + def addMailingListNameToSubject(subject, mailingListName): + """Adding mailingListName to subject""" subject = subject.strip() if subject[:3] == 'Re:' or subject[:3] == 'RE:': subject = subject[3:].strip() if '[' + mailingListName + ']' in subject: return subject - else: - return '[' + mailingListName + '] ' + subject + return '[' + mailingListName + '] ' + subject From 80b2bc1c9a4ae650b7d5ecf099338ac8d2df633c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:17:36 +0530 Subject: [PATCH 227/306] class_singleCleaner.py quality fixes --- src/class_singleCleaner.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 9ffc1607..68a5e727 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -21,11 +21,11 @@ It resends messages when there has been no response: import gc import os -import shared import time import knownnodes import queues +import shared import state import tr from bmconfigparser import BMConfigParser @@ -35,11 +35,12 @@ from network import BMConnectionPool, StoppableThread class singleCleaner(StoppableThread): + """The singleCleaner thread class""" name = "singleCleaner" cycleLength = 300 expireDiscoveredPeers = 300 - def run(self): + def run(self): # pylint: disable=too-many-branches gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 try: @@ -115,6 +116,7 @@ class singleCleaner(StoppableThread): # while writing it to disk knownnodes.cleanupKnownNodes() except Exception as err: + # pylint: disable=protected-access if "Errno 28" in str(err): self.logger.fatal( '(while writing knownnodes to disk)' @@ -127,17 +129,11 @@ class singleCleaner(StoppableThread): "MainWindow", 'Alert: Your disk or data storage volume' ' is full. Bitmessage will now exit.'), - True) + True) )) - # FIXME redundant? - if shared.daemon or not state.enableGUI: + if shared.thisapp.daemon or not state.enableGUI: os._exit(1) -# # clear download queues -# for thread in threading.enumerate(): -# if thread.isAlive() and hasattr(thread, 'downloadQueue'): -# thread.downloadQueue.clear() - # inv/object tracking for connection in BMConnectionPool().connections(): connection.clean() @@ -150,7 +146,7 @@ class singleCleaner(StoppableThread): del state.discoveredPeers[k] except KeyError: pass - # TODO: cleanup pending upload / download + # ..todo:: cleanup pending upload / download gc.collect() From 9923e972797738606235f3817062eed4dd8d8d98 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:21:22 +0530 Subject: [PATCH 228/306] class_singleWorker quality fixes --- src/class_singleWorker.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 60eabe2e..a275b79d 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -1,6 +1,5 @@ """ -src/class_singleWorker.py -========================= +Thread for performing PoW """ # pylint: disable=protected-access,too-many-branches,too-many-statements,no-self-use,too-many-lines,too-many-locals @@ -468,8 +467,8 @@ class singleWorker(StoppableThread): def sendOnionPeerObj(self, peer=None): """Send onionpeer object representing peer""" if not peer: # find own onionhostname - for peer in state.ownAddresses: - if peer.host.endswith('.onion'): + for peer_ in state.ownAddresses: + if peer_.host.endswith('.onion'): break else: return From 4a54c200d42119f36e9e2a4e72b7ef257c4945c9 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 4 Nov 2019 20:21:54 +0530 Subject: [PATCH 229/306] class_smtpServer quality fixes --- src/class_smtpServer.py | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 924333a6..cdf867a9 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -1,3 +1,6 @@ +""" +SMTP server thread +""" import asyncore import base64 import email @@ -22,10 +25,13 @@ SMTPDOMAIN = "bmaddr.lan" LISTENPORT = 8425 logger = logging.getLogger('default') +# pylint: disable=attribute-defined-outside-init class smtpServerChannel(smtpd.SMTPChannel): + """Asyncore channel for SMTP protocol (server)""" def smtp_EHLO(self, arg): + """Process an EHLO""" if not arg: self.push('501 Syntax: HELO hostname') return @@ -33,14 +39,16 @@ class smtpServerChannel(smtpd.SMTPChannel): self.push('250 AUTH PLAIN') def smtp_AUTH(self, arg): + """Process AUTH""" if not arg or arg[0:5] not in ["PLAIN"]: self.push('501 Syntax: AUTH PLAIN') return authstring = arg[6:] try: decoded = base64.b64decode(authstring) - correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \ - "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "") + correctauth = "\x00" + BMConfigParser().safeGet( + "bitmessagesettings", "smtpdusername", "") + "\x00" + BMConfigParser().safeGet( + "bitmessagesettings", "smtpdpassword", "") logger.debug('authstring: %s / %s', correctauth, decoded) if correctauth == decoded: self.auth = True @@ -51,6 +59,7 @@ class smtpServerChannel(smtpd.SMTPChannel): self.push('501 Authentication fail') def smtp_DATA(self, arg): + """Process DATA""" if not hasattr(self, "auth") or not self.auth: self.push('530 Authentication required') return @@ -58,15 +67,18 @@ class smtpServerChannel(smtpd.SMTPChannel): class smtpServerPyBitmessage(smtpd.SMTPServer): + """Asyncore SMTP server class""" def handle_accept(self): + """Accept a connection""" pair = self.accept() if pair is not None: conn, addr = pair # print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr) self.channel = smtpServerChannel(self, conn, addr) - def send(self, fromAddress, toAddress, subject, message): - status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) + def send(self, fromAddress, toAddress, subject, message): # pylint: disable=arguments-differ + """Send a bitmessage""" + streamNumber, ripe = decodeAddress(toAddress)[2:] stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') ackdata = genAckPayload(streamNumber, stealthLevel) sqlExecute( @@ -78,19 +90,21 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): subject, message, ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. 'msgqueued', - 0, # retryNumber - 'sent', # folder - 2, # encodingtype - min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days + 0, # retryNumber + 'sent', # folder + 2, # encodingtype + # not necessary to have a TTL higher than 2 days + min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) ) queues.workerQueue.put(('sendmessage', toAddress)) def decode_header(self, hdr): + """Email header decoding""" ret = [] for h in decode_header(self.msg_headers[hdr]): if h[1]: @@ -100,7 +114,9 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): return ret - def process_message(self, peer, mailfrom, rcpttos, data): + def process_message(self, peer, mailfrom, rcpttos, data): # pylint: disable=too-many-locals, too-many-branches + """Process an email""" + # print 'Receiving message from:', peer p = re.compile(".*<([^>]+)>") if not hasattr(self.channel, "auth") or not self.channel.auth: logger.error('Missing or invalid auth') @@ -158,7 +174,8 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): class smtpServer(StoppableThread): - def __init__(self, parent=None): + """SMTP server thread""" + def __init__(self, _=None): super(smtpServer, self).__init__(name="smtpServerThread") self.server = smtpServerPyBitmessage(('127.0.0.1', LISTENPORT), None) @@ -171,7 +188,8 @@ class smtpServer(StoppableThread): asyncore.loop(1) -def signals(signal, frame): +def signals(_, __): + """Signal handler""" logger.warning('Got signal, terminating') for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): @@ -179,6 +197,7 @@ def signals(signal, frame): def runServer(): + """Run SMTP server as a standalone python process""" logger.warning('Running SMTPd thread') smtpThread = smtpServer() smtpThread.start() From dbbf454c1501cad342282cf38a4ca83f552446ed Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 5 Oct 2019 13:01:48 +0530 Subject: [PATCH 230/306] class_sqlThread flake8 fixes --- src/class_sqlThread.py | 264 ++++++++++++++++++++++++++++++----------- 1 file changed, 196 insertions(+), 68 deletions(-) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index bcb56303..7df75137 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -38,30 +38,38 @@ class sqlThread(threading.Thread): try: self.cur.execute( - '''CREATE TABLE inbox (msgid blob, toaddress text, fromaddress text, subject text, received text, message text, folder text, encodingtype int, read bool, sighash blob, UNIQUE(msgid) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE inbox (msgid blob, toaddress text, fromaddress text, subject text,''' + ''' received text, message text, folder text, encodingtype int, read bool, sighash blob,''' + ''' UNIQUE(msgid) ON CONFLICT REPLACE)''') self.cur.execute( - '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, senttime integer, lastactiontime integer, sleeptill integer, status text, retrynumber integer, folder text, encodingtype int, ttl int)''' ) + '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text,''' + ''' message text, ackdata blob, senttime integer, lastactiontime integer,''' + ''' sleeptill integer, status text, retrynumber integer, folder text, encodingtype int, ttl int)''') self.cur.execute( - '''CREATE TABLE subscriptions (label text, address text, enabled bool)''' ) + '''CREATE TABLE subscriptions (label text, address text, enabled bool)''') self.cur.execute( - '''CREATE TABLE addressbook (label text, address text)''' ) + '''CREATE TABLE addressbook (label text, address text)''') self.cur.execute( - '''CREATE TABLE blacklist (label text, address text, enabled bool)''' ) + '''CREATE TABLE blacklist (label text, address text, enabled bool)''') self.cur.execute( - '''CREATE TABLE whitelist (label text, address text, enabled bool)''' ) + '''CREATE TABLE whitelist (label text, address text, enabled bool)''') self.cur.execute( - '''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int,''' + ''' usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''') self.cur.execute( - '''CREATE TABLE inventory (hash blob, objecttype int, streamnumber int, payload blob, expirestime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE inventory (hash blob, objecttype int, streamnumber int, payload blob,''' + ''' expirestime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''') self.cur.execute( - '''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') + '''INSERT INTO subscriptions VALUES''' + '''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') self.cur.execute( - '''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' ) - self.cur.execute( '''INSERT INTO settings VALUES('version','10')''') - self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( + '''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''') + self.cur.execute('''INSERT INTO settings VALUES('version','10')''') + self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( int(time.time()),)) self.cur.execute( - '''CREATE TABLE objectprocessorqueue (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE objectprocessorqueue''' + ''' (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''') self.conn.commit() logger.info('Created messages database file') except Exception as err: @@ -126,33 +134,38 @@ class sqlThread(threading.Thread): logger.debug( "In messages.dat database, creating new 'settings' table.") self.cur.execute( - '''CREATE TABLE settings (key text, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' ) - self.cur.execute( '''INSERT INTO settings VALUES('version','1')''') - self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( + '''CREATE TABLE settings (key text, value blob, UNIQUE(key) ON CONFLICT REPLACE)''') + self.cur.execute('''INSERT INTO settings VALUES('version','1')''') + self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( int(time.time()),)) logger.debug('In messages.dat database, removing an obsolete field from the pubkeys table.') self.cur.execute( - '''CREATE TEMPORARY TABLE pubkeys_backup(hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE);''') + '''CREATE TEMPORARY TABLE pubkeys_backup(hash blob, transmitdata blob, time int,''' + ''' usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE);''') self.cur.execute( '''INSERT INTO pubkeys_backup SELECT hash, transmitdata, time, usedpersonally FROM pubkeys;''') - self.cur.execute( '''DROP TABLE pubkeys''') + self.cur.execute('''DROP TABLE pubkeys''') self.cur.execute( - '''CREATE TABLE pubkeys (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE pubkeys''' + ''' (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''') self.cur.execute( '''INSERT INTO pubkeys SELECT hash, transmitdata, time, usedpersonally FROM pubkeys_backup;''') - self.cur.execute( '''DROP TABLE pubkeys_backup;''') - logger.debug('Deleting all pubkeys from inventory. They will be redownloaded and then saved with the correct times.') + self.cur.execute('''DROP TABLE pubkeys_backup;''') + logger.debug( + 'Deleting all pubkeys from inventory.' + ' They will be redownloaded and then saved with the correct times.') self.cur.execute( '''delete from inventory where objecttype = 'pubkey';''') logger.debug('replacing Bitmessage announcements mailing list with a new one.') self.cur.execute( '''delete from subscriptions where address='BM-BbkPSZbzPwpVcYZpU4yHwf9ZPEapN5Zx' ''') self.cur.execute( - '''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') + '''INSERT INTO subscriptions VALUES''' + '''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') logger.debug('Commiting.') self.conn.commit() logger.debug('Vacuuming message.dat. You might notice that the file size gets much smaller.') - self.cur.execute( ''' VACUUM ''') + self.cur.execute(''' VACUUM ''') # After code refactoring, the possible status values for sent messages # have changed. @@ -176,15 +189,21 @@ class sqlThread(threading.Thread): 'In messages.dat database, removing an obsolete field from' ' the inventory table.') self.cur.execute( - '''CREATE TEMPORARY TABLE inventory_backup(hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE);''') + '''CREATE TEMPORARY TABLE inventory_backup''' + '''(hash blob, objecttype text, streamnumber int, payload blob,''' + ''' receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE);''') self.cur.execute( - '''INSERT INTO inventory_backup SELECT hash, objecttype, streamnumber, payload, receivedtime FROM inventory;''') - self.cur.execute( '''DROP TABLE inventory''') + '''INSERT INTO inventory_backup SELECT hash, objecttype, streamnumber, payload, receivedtime''' + ''' FROM inventory;''') + self.cur.execute('''DROP TABLE inventory''') self.cur.execute( - '''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE inventory''' + ''' (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer,''' + ''' UNIQUE(hash) ON CONFLICT REPLACE)''') self.cur.execute( - '''INSERT INTO inventory SELECT hash, objecttype, streamnumber, payload, receivedtime FROM inventory_backup;''') - self.cur.execute( '''DROP TABLE inventory_backup;''') + '''INSERT INTO inventory SELECT hash, objecttype, streamnumber, payload, receivedtime''' + ''' FROM inventory_backup;''') + self.cur.execute('''DROP TABLE inventory_backup;''') item = '''update settings set value=? WHERE key='version';''' parameters = (3,) self.cur.execute(item, parameters) @@ -214,7 +233,8 @@ class sqlThread(threading.Thread): if currentVersion == 4: self.cur.execute('''DROP TABLE pubkeys''') self.cur.execute( - '''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''') + '''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int,''' + '''usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''') self.cur.execute( '''delete from inventory where objecttype = 'pubkey';''') item = '''update settings set value=? WHERE key='version';''' @@ -230,7 +250,8 @@ class sqlThread(threading.Thread): if currentVersion == 5: self.cur.execute('''DROP TABLE knownnodes''') self.cur.execute( - '''CREATE TABLE objectprocessorqueue (objecttype text, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''') + '''CREATE TABLE objectprocessorqueue''' + ''' (objecttype text, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''') item = '''update settings set value=? WHERE key='version';''' parameters = (6,) self.cur.execute(item, parameters) @@ -246,10 +267,15 @@ class sqlThread(threading.Thread): logger.debug( 'In messages.dat database, dropping and recreating' ' the inventory table.') - self.cur.execute( '''DROP TABLE inventory''') - self.cur.execute( '''CREATE TABLE inventory (hash blob, objecttype int, streamnumber int, payload blob, expirestime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''' ) - self.cur.execute( '''DROP TABLE objectprocessorqueue''') - self.cur.execute( '''CREATE TABLE objectprocessorqueue (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''' ) + self.cur.execute('''DROP TABLE inventory''') + self.cur.execute( + '''CREATE TABLE inventory''' + ''' (hash blob, objecttype int, streamnumber int, payload blob, expirestime integer,''' + ''' tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''') + self.cur.execute('''DROP TABLE objectprocessorqueue''') + self.cur.execute( + '''CREATE TABLE objectprocessorqueue''' + ''' (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''') item = '''update settings set value=? WHERE key='version';''' parameters = (7,) self.cur.execute(item, parameters) @@ -311,15 +337,24 @@ class sqlThread(threading.Thread): ' fields into the retrynumber field and adding the' ' sleeptill and ttl fields...') self.cur.execute( - '''CREATE TEMPORARY TABLE sent_backup (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, lastactiontime integer, status text, retrynumber integer, folder text, encodingtype int)''' ) + '''CREATE TEMPORARY TABLE sent_backup''' + ''' (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text,''' + ''' ackdata blob, lastactiontime integer, status text, retrynumber integer,''' + ''' folder text, encodingtype int)''') self.cur.execute( - '''INSERT INTO sent_backup SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, 0, folder, encodingtype FROM sent;''') - self.cur.execute( '''DROP TABLE sent''') + '''INSERT INTO sent_backup SELECT msgid, toaddress, toripe, fromaddress,''' + ''' subject, message, ackdata, lastactiontime,''' + ''' status, 0, folder, encodingtype FROM sent;''') + self.cur.execute('''DROP TABLE sent''') self.cur.execute( - '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, senttime integer, lastactiontime integer, sleeptill int, status text, retrynumber integer, folder text, encodingtype int, ttl int)''' ) + '''CREATE TABLE sent''' + ''' (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text,''' + ''' ackdata blob, senttime integer, lastactiontime integer, sleeptill int, status text,''' + ''' retrynumber integer, folder text, encodingtype int, ttl int)''') self.cur.execute( - '''INSERT INTO sent SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, lastactiontime, 0, status, 0, folder, encodingtype, 216000 FROM sent_backup;''') - self.cur.execute( '''DROP TABLE sent_backup''') + '''INSERT INTO sent SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata,''' + ''' lastactiontime, lastactiontime, 0, status, 0, folder, encodingtype, 216000 FROM sent_backup;''') + self.cur.execute('''DROP TABLE sent_backup''') logger.info('In messages.dat database, finished making TTL-related changes.') logger.debug('In messages.dat database, adding address field to the pubkeys table.') # We're going to have to calculate the address for each row in the pubkeys @@ -336,16 +371,24 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) # Now we can remove the hash field from the pubkeys table. self.cur.execute( - '''CREATE TEMPORARY TABLE pubkeys_backup (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) + '''CREATE TEMPORARY TABLE pubkeys_backup''' + ''' (address text, addressversion int, transmitdata blob, time int,''' + ''' usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''') self.cur.execute( - '''INSERT INTO pubkeys_backup SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys;''') - self.cur.execute( '''DROP TABLE pubkeys''') + '''INSERT INTO pubkeys_backup''' + ''' SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys;''') + self.cur.execute('''DROP TABLE pubkeys''') self.cur.execute( - '''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE pubkeys''' + ''' (address text, addressversion int, transmitdata blob, time int, usedpersonally text,''' + ''' UNIQUE(address) ON CONFLICT REPLACE)''') self.cur.execute( - '''INSERT INTO pubkeys SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys_backup;''') - self.cur.execute( '''DROP TABLE pubkeys_backup''') - logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.') + '''INSERT INTO pubkeys SELECT''' + ''' address, addressversion, transmitdata, time, usedpersonally FROM pubkeys_backup;''') + self.cur.execute('''DROP TABLE pubkeys_backup''') + logger.debug( + 'In messages.dat database, done adding address field to the pubkeys table' + ' and removing the hash field.') self.cur.execute('''update settings set value=10 WHERE key='version';''') # Are you hoping to add a new option to the keys.dat file of existing @@ -355,7 +398,7 @@ class sqlThread(threading.Thread): try: testpayload = '\x00\x00' t = ('1234', 1, testpayload, '12345678', 'no') - self.cur.execute( '''INSERT INTO pubkeys VALUES(?,?,?,?,?)''', t) + self.cur.execute('''INSERT INTO pubkeys VALUES(?,?,?,?,?)''', t) self.conn.commit() self.cur.execute( '''SELECT transmitdata FROM pubkeys WHERE address='1234' ''') @@ -365,13 +408,29 @@ class sqlThread(threading.Thread): self.cur.execute('''DELETE FROM pubkeys WHERE address='1234' ''') self.conn.commit() if transmitdata == '': - logger.fatal('Problem: The version of SQLite you have cannot store Null values. Please download and install the latest revision of your version of Python (for example, the latest Python 2.7 revision) and try again.\n') - logger.fatal('PyBitmessage will now exit very abruptly. You may now see threading errors related to this abrupt exit but the problem you need to solve is related to SQLite.\n\n') + logger.fatal( + 'Problem: The version of SQLite you have cannot store Null values.' + ' Please download and install the latest revision of your version of Python' + ' (for example, the latest Python 2.7 revision) and try again.\n') + logger.fatal( + 'PyBitmessage will now exit very abruptly.' + ' You may now see threading errors related to this abrupt exit' + ' but the problem you need to solve is related to SQLite.\n\n') os._exit(0) except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(While null value test) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(While null value test) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) else: logger.error(err) @@ -387,11 +446,21 @@ class sqlThread(threading.Thread): if int(value) < int(time.time()) - 86400: logger.info('It has been a long time since the messages.dat file has been vacuumed. Vacuuming now...') try: - self.cur.execute( ''' VACUUM ''') + self.cur.execute(''' VACUUM ''') except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(While VACUUM) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(While VACUUM) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) item = '''update settings set value=? WHERE key='lastvacuumtime';''' parameters = (int(time.time()),) @@ -406,8 +475,18 @@ class sqlThread(threading.Thread): self.conn.commit() except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(While committing) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(While committing) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) elif item == 'exit': self.conn.close() @@ -421,8 +500,18 @@ class sqlThread(threading.Thread): self.conn.commit() except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(while movemessagstoprog) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(while movemessagstoprog) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) self.conn.close() shutil.move( @@ -437,8 +526,18 @@ class sqlThread(threading.Thread): self.conn.commit() except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(while movemessagstoappdata) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(while movemessagstoappdata) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) self.conn.close() shutil.move( @@ -451,11 +550,21 @@ class sqlThread(threading.Thread): self.cur.execute('''delete from sent where folder='trash' ''') self.conn.commit() try: - self.cur.execute( ''' VACUUM ''') + self.cur.execute(''' VACUUM ''') except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(while deleteandvacuume) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(while deleteandvacuume) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) else: parameters = helper_sql.sqlSubmitQueue.get() @@ -467,11 +576,30 @@ class sqlThread(threading.Thread): rowcount = self.cur.rowcount except Exception as err: if str(err) == 'database or disk is full': - logger.fatal('(while cur.execute) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + logger.fatal( + '(while cur.execute) Alert: Your disk or data storage volume is full.' + ' sqlThread will now exit.') + queues.UISignalQueue.put(( + 'alert', ( + tr._translate( + "MainWindow", + "Disk full"), + tr._translate( + "MainWindow", + 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), + True))) os._exit(0) else: - logger.fatal('Major error occurred when trying to execute a SQL statement within the sqlThread. Please tell Atheros about this error message or post it in the forum! Error occurred while trying to execute statement: "%s" Here are the parameters; you might want to censor this data with asterisks (***) as it can contain private information: %s. Here is the actual error message thrown by the sqlThread: %s', str(item), str(repr(parameters)), str(err)) + logger.fatal( + 'Major error occurred when trying to execute a SQL statement within the sqlThread.' + ' Please tell Atheros about this error message or post it in the forum!' + ' Error occurred while trying to execute statement: "%s" Here are the parameters;' + ' you might want to censor this data with asterisks (***)' + ' as it can contain private information: %s.' + ' Here is the actual error message thrown by the sqlThread: %s', + str(item), + str(repr(parameters)), + str(err)) logger.fatal('This program shall now abruptly exit!') os._exit(0) From a9991a7a5a240aca228e0d655b2e756293a731b3 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 5 Oct 2019 15:22:28 +0530 Subject: [PATCH 231/306] class_sqlThread pylint fixes --- src/class_sqlThread.py | 9 ++++----- src/depends.py | 4 ++-- src/helper_inbox.py | 3 ++- src/helper_search.py | 3 +-- src/helper_sql.py | 1 + 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 7df75137..3d59803c 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -4,22 +4,21 @@ sqlThread is defined here import threading from bmconfigparser import BMConfigParser + import sqlite3 import time import shutil # used for moving the messages.dat file import sys import os from debug import logger + import helper_sql import helper_startup import paths import queues import state import tr - -# This thread exists because SQLITE3 is so un-threadsafe that we must -# submit queries to it and it puts results back in a different queue. They -# won't let us just use locks. +# pylint: disable=attribute-defined-outside-init,protected-access class sqlThread(threading.Thread): @@ -28,7 +27,7 @@ class sqlThread(threading.Thread): def __init__(self): threading.Thread.__init__(self, name="SQL") - def run(self): + def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements """Process SQL queries from `.helper_sql.sqlSubmitQueue`""" self.conn = sqlite3.connect(state.appdata + 'messages.dat') self.conn.text_factory = str diff --git a/src/depends.py b/src/depends.py index 0114ec94..7ae9220e 100755 --- a/src/depends.py +++ b/src/depends.py @@ -316,8 +316,8 @@ def check_curses(): """Do curses dependency check. Here we are checking for curses if available or not with check - as interface requires the pythondialog\ package and the dialog - utility. + as interface requires the pythondialog + package and the dialog utility. """ if sys.hexversion < 0x20600F0: logger.error( diff --git a/src/helper_inbox.py b/src/helper_inbox.py index 95214743..1b1710d6 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -1,10 +1,11 @@ -"""Helper Inbox performs inbox messagese related operations.""" +"""Helper Inbox performs inbox messages related operations.""" from helper_sql import sqlExecute, sqlQuery import queues def insert(t): + """Perform an insert into the "inbox" table""" sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) # shouldn't emit changedInboxUnread and displayNewInboxMessage # at the same time diff --git a/src/helper_search.py b/src/helper_search.py index d6704731..0908ada3 100644 --- a/src/helper_search.py +++ b/src/helper_search.py @@ -1,5 +1,4 @@ -#!/usr/bin/python2.7 - +"""Additional SQL helper for searching messages""" from helper_sql import * try: diff --git a/src/helper_sql.py b/src/helper_sql.py index 138a9f50..ad0a5dc4 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -80,6 +80,7 @@ def sqlExecuteChunked(sqlStatement, idCount, *args): def sqlExecute(sqlStatement, *args): + """Execute SQL statement (optionally with arguments)""" sqlLock.acquire() sqlSubmitQueue.put(sqlStatement) From 21faf52f2f19eeccc383a762e826cd71f66f0d74 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 5 Oct 2019 20:13:08 +0530 Subject: [PATCH 232/306] debug pylint fixes --- src/debug.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debug.py b/src/debug.py index 472b0d02..cab07275 100644 --- a/src/debug.py +++ b/src/debug.py @@ -138,6 +138,7 @@ def configureLogging(): def resetLogging(): """Reconfigure logging in runtime when state.appdata dir changed""" + # pylint: disable=global-statement, used-before-assignment global logger for i in logger.handlers: logger.removeHandler(i) From e97d02ed783f713ebd8e3150cf155277932f2de1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 7 Oct 2019 13:38:26 +0530 Subject: [PATCH 233/306] depends pylint fixes --- src/depends.py | 23 ++++++++++++----------- src/helper_ackPayload.py | 8 +++++--- src/helper_bitcoin.py | 1 + src/helper_inbox.py | 4 ++-- src/helper_random.py | 4 +++- src/helper_sql.py | 3 +-- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/depends.py b/src/depends.py index 7ae9220e..68fba01a 100755 --- a/src/depends.py +++ b/src/depends.py @@ -113,6 +113,7 @@ PACKAGES = { def detectOS(): + """Finding out what Operating System is running""" if detectOS.result is not None: return detectOS.result if sys.platform.startswith('openbsd'): @@ -132,6 +133,7 @@ detectOS.result = None def detectOSRelease(): + """Detecting the release of OS""" with open("/etc/os-release", 'r') as osRelease: version = None for line in osRelease: @@ -148,6 +150,7 @@ def detectOSRelease(): def try_import(module, log_extra=False): + """Try to import the non imported packages""" try: return import_module(module) except ImportError: @@ -208,10 +211,8 @@ def check_sqlite(): ).fetchone()[0] logger.info('SQLite Library Source ID: %s', sqlite_source_id) if sqlite_version_number >= 3006023: - compile_options = ', '.join(map( - lambda row: row[0], - conn.execute('PRAGMA compile_options;') - )) + compile_options = ', '.join( + [row[0] for row in conn.execute('PRAGMA compile_options;')]) logger.info( 'SQLite Library Compile Options: %s', compile_options) # There is no specific version requirement as yet, so we just @@ -230,13 +231,13 @@ def check_sqlite(): conn.close() -def check_openssl(): +def check_openssl(): # pylint: disable=too-many-branches, too-many-return-statements """Do openssl dependency check. Here we are checking for openssl with its all dependent libraries and version checking. """ - + # pylint: disable=protected-access, redefined-outer-name ctypes = try_import('ctypes') if not ctypes: logger.error('Unable to check OpenSSL.') @@ -300,7 +301,7 @@ def check_openssl(): ' ECDH, and ECDSA enabled.') return False matches = cflags_regex.findall(openssl_cflags) - if len(matches) > 0: + if matches: logger.error( 'This OpenSSL library is missing the following required' ' features: %s. PyBitmessage requires OpenSSL 0.9.8b' @@ -311,13 +312,13 @@ def check_openssl(): return False -# TODO: The minimum versions of pythondialog and dialog need to be determined +# ..todo:: The minimum versions of pythondialog and dialog need to be determined def check_curses(): """Do curses dependency check. - Here we are checking for curses if available or not with check - as interface requires the pythondialog - package and the dialog utility. + Here we are checking for curses if available or not with check as interface + requires the `pythondialog `_ package + and the dialog utility. """ if sys.hexversion < 0x20600F0: logger.error( diff --git a/src/helper_ackPayload.py b/src/helper_ackPayload.py index acdbadf7..15ac0058 100644 --- a/src/helper_ackPayload.py +++ b/src/helper_ackPayload.py @@ -1,9 +1,11 @@ -"""This module is for generating ack payload.""" +""" +This module is for generating ack payload +""" +from binascii import hexlify +from struct import pack import highlevelcrypto import helper_random -from binascii import hexlify -from struct import pack from addresses import encodeVarint # This function generates payload objects for message acknowledgements diff --git a/src/helper_bitcoin.py b/src/helper_bitcoin.py index d56e395b..f8146285 100644 --- a/src/helper_bitcoin.py +++ b/src/helper_bitcoin.py @@ -3,6 +3,7 @@ from pyelliptic import arithmetic # This function expects that pubkey begin with \x04 def calculateBitcoinAddressFromPubkey(pubkey): + """This function expects that pubkey begin's with the bitcoin prefix""" if len(pubkey) != 65: print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey), 'bytes long rather than 65.' return "error" diff --git a/src/helper_inbox.py b/src/helper_inbox.py index 1b1710d6..7cb860dc 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -1,11 +1,11 @@ -"""Helper Inbox performs inbox messages related operations.""" +"""Helper Inbox performs inbox messages related operations""" from helper_sql import sqlExecute, sqlQuery import queues def insert(t): - """Perform an insert into the "inbox" table""" + """Perform an insert into the "inbox" table""" sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) # shouldn't emit changedInboxUnread and displayNewInboxMessage # at the same time diff --git a/src/helper_random.py b/src/helper_random.py index 57f0ccb3..edc70a01 100644 --- a/src/helper_random.py +++ b/src/helper_random.py @@ -1,4 +1,6 @@ -"""Convenience functions for random operations. Not suitable for security / cryptography operations.""" +""" +Convenience functions for random operations. Not suitable for security / cryptography operations +""" import os import random diff --git a/src/helper_sql.py b/src/helper_sql.py index ad0a5dc4..16d36637 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -2,11 +2,9 @@ SQL-related functions defined here are really pass the queries (or other SQL commands) to :class:`.threads.sqlThread` through `sqlSubmitQueue` queue and check or return the result got from `sqlReturnQueue`. - This is done that way because :mod:`sqlite3` is so thread-unsafe that they won't even let you call it from different threads using your own locks. SQLite objects can only be used from one thread. - .. note:: This actually only applies for certain deployments, and/or really old version of sqlite. I haven't actually seen it anywhere. Current versions do have support for threading and multiprocessing. @@ -50,6 +48,7 @@ def sqlQuery(sqlStatement, *args): def sqlExecuteChunked(sqlStatement, idCount, *args): + """Execute chunked SQL statement to avoid argument limit""" # SQLITE_MAX_VARIABLE_NUMBER, # unfortunately getting/setting isn't exposed to python sqlExecuteChunked.chunkSize = 999 From 31e3d60fb09a866b5c19ab87eca9ad3508563833 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 7 Oct 2019 19:01:21 +0530 Subject: [PATCH 234/306] helper_ackPayload pylint fixes --- src/helper_ackPayload.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/helper_ackPayload.py b/src/helper_ackPayload.py index 15ac0058..dcce3153 100644 --- a/src/helper_ackPayload.py +++ b/src/helper_ackPayload.py @@ -1,6 +1,7 @@ """ This module is for generating ack payload """ + from binascii import hexlify from struct import pack @@ -8,17 +9,20 @@ import highlevelcrypto import helper_random from addresses import encodeVarint -# This function generates payload objects for message acknowledgements -# Several stealth levels are available depending on the privacy needs; -# a higher level means better stealth, but also higher cost (size+POW) -# - level 0: a random 32-byte sequence with a message header appended -# - level 1: a getpubkey request for a (random) dummy key hash -# - level 2: a standard message, encrypted to a random pubkey - def genAckPayload(streamNumber=1, stealthLevel=0): - """Generate and return payload obj.""" - if (stealthLevel == 2): # Generate privacy-enhanced payload + """ + Generate and return payload obj. + + This function generates payload objects for message acknowledgements + Several stealth levels are available depending on the privacy needs; + a higher level means better stealth, but also higher cost (size+POW) + + - level 0: a random 32-byte sequence with a message header appended + - level 1: a getpubkey request for a (random) dummy key hash + - level 2: a standard message, encrypted to a random pubkey + """ + if stealthLevel == 2: # Generate privacy-enhanced payload # Generate a dummy privkey and derive the pubkey dummyPubKeyHex = highlevelcrypto.privToPub( hexlify(helper_random.randomBytes(32))) @@ -31,7 +35,7 @@ def genAckPayload(streamNumber=1, stealthLevel=0): acktype = 2 # message version = 1 - elif (stealthLevel == 1): # Basic privacy payload (random getpubkey) + elif stealthLevel == 1: # Basic privacy payload (random getpubkey) ackdata = helper_random.randomBytes(32) acktype = 0 # getpubkey version = 4 From 27c58b05f3caa549da8b25b94e35787eb0e4222f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 7 Oct 2019 19:28:12 +0530 Subject: [PATCH 235/306] helper_bitcoin pylint fixes --- src/helper_bitcoin.py | 19 +++++++++++++++---- src/helper_sent.py | 4 ++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/helper_bitcoin.py b/src/helper_bitcoin.py index f8146285..d4f1d105 100644 --- a/src/helper_bitcoin.py +++ b/src/helper_bitcoin.py @@ -1,11 +1,19 @@ +""" +Calculates bitcoin and testnet address from pubkey +""" + import hashlib + +from debug import logger from pyelliptic import arithmetic -# This function expects that pubkey begin with \x04 + def calculateBitcoinAddressFromPubkey(pubkey): - """This function expects that pubkey begin's with the bitcoin prefix""" + """Calculate bitcoin address from given pubkey (65 bytes long hex string)""" if len(pubkey) != 65: - print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey), 'bytes long rather than 65.' + logger.error('Could not calculate Bitcoin address from pubkey because' + ' function was passed a pubkey that was' + ' %i bytes long rather than 65.', len(pubkey)) return "error" ripe = hashlib.new('ripemd160') sha = hashlib.new('sha256') @@ -25,8 +33,11 @@ def calculateBitcoinAddressFromPubkey(pubkey): def calculateTestnetAddressFromPubkey(pubkey): + """This function expects that pubkey begin with the testnet prefix""" if len(pubkey) != 65: - print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey), 'bytes long rather than 65.' + logger.error('Could not calculate Bitcoin address from pubkey because' + ' function was passed a pubkey that was' + ' %i bytes long rather than 65.', len(pubkey)) return "error" ripe = hashlib.new('ripemd160') sha = hashlib.new('sha256') diff --git a/src/helper_sent.py b/src/helper_sent.py index 8dde7215..6b73c8c5 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -1,3 +1,7 @@ +""" +Insert operation into sent table +""" + from helper_sql import * def insert(t): From f4c7ac56047d60beae7c3ed7a01e26da40a02dd4 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 7 Oct 2019 19:47:40 +0530 Subject: [PATCH 236/306] helper_inbox pylint fixes --- src/helper_inbox.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helper_inbox.py b/src/helper_inbox.py index 7cb860dc..654dd59d 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -1,7 +1,7 @@ """Helper Inbox performs inbox messages related operations""" -from helper_sql import sqlExecute, sqlQuery import queues +from helper_sql import sqlExecute, sqlQuery def insert(t): @@ -13,11 +13,13 @@ def insert(t): def trash(msgid): + """Mark a message in the `inbox` as `trash`""" sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) queues.UISignalQueue.put(('removeInboxRowByMsgid', msgid)) def isMessageAlreadyInInbox(sigHash): + """Check for previous instances of this message""" queryReturn = sqlQuery( '''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash) return queryReturn[0][0] != 0 From 05cda087d6e59420aecc1e241fccc96b331a1eeb Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 8 Oct 2019 12:33:48 +0530 Subject: [PATCH 237/306] helper_msgcoding pylint fixes --- src/helper_msgcoding.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index cc632ffa..ae2bf80b 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -25,19 +25,24 @@ BITMESSAGE_ENCODING_EXTENDED = 3 class MsgEncodeException(Exception): + """Exception during message encoding""" pass class MsgDecodeException(Exception): + """Exception during message decoding""" pass class DecompressionSizeException(MsgDecodeException): + # pylint: disable=super-init-not-called + """Decompression resulted in too much data (attack protection)""" def __init__(self, size): self.size = size class MsgEncode(object): + """Message encoder class""" def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): self.data = None self.encoding = encoding @@ -52,6 +57,7 @@ class MsgEncode(object): raise MsgEncodeException("Unknown encoding %i" % (encoding)) def encodeExtended(self, message): + """Handle extended encoding""" try: msgObj = messagetypes.message.Message() self.data = zlib.compress(msgpack.dumps(msgObj.encode(message)), 9) @@ -64,15 +70,18 @@ class MsgEncode(object): self.length = len(self.data) def encodeSimple(self, message): + """Handle simple encoding""" self.data = 'Subject:%(subject)s\nBody:%(body)s' % message self.length = len(self.data) def encodeTrivial(self, message): + """Handle trivial encoding""" self.data = message['body'] self.length = len(self.data) class MsgDecode(object): + """Message decoder class""" def __init__(self, encoding, data): self.encoding = encoding if self.encoding == BITMESSAGE_ENCODING_EXTENDED: @@ -88,6 +97,7 @@ class MsgDecode(object): self.subject = _translate("MsgDecode", "Unknown encoding") def decodeExtended(self, data): + """Handle extended encoding""" dc = zlib.decompressobj() tmp = "" while len(tmp) <= BMConfigParser().safeGetInt("zlib", "maxsize"): @@ -131,6 +141,7 @@ class MsgDecode(object): self.body = msgObj.body def decodeSimple(self, data): + """Handle simple encoding""" bodyPositionIndex = string.find(data, '\nBody:') if bodyPositionIndex > 1: subject = data[8:bodyPositionIndex] From 28cfe78e6721f59f27f3df3a626ef61745143e00 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 8 Oct 2019 15:12:31 +0530 Subject: [PATCH 238/306] helper_random pylint fixes --- src/helper_random.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/helper_random.py b/src/helper_random.py index edc70a01..0785c737 100644 --- a/src/helper_random.py +++ b/src/helper_random.py @@ -1,6 +1,4 @@ -""" -Convenience functions for random operations. Not suitable for security / cryptography operations -""" +"""Convenience functions for random operations. Not suitable for security / cryptography operations.""" import os import random @@ -58,8 +56,7 @@ def randomrandrange(x, y=None): """ if isinstance(y, NoneType): return random.randrange(x) # nosec - else: - return random.randrange(x, y) # nosec + return random.randrange(x, y) # nosec def randomchoice(population): From 9041b8f64431c4047992e0699dba1be80a7f762f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 9 Oct 2019 16:30:12 +0530 Subject: [PATCH 239/306] helper_search flake8 fixes --- src/helper_search.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/helper_search.py b/src/helper_search.py index 0908ada3..8dfc7eb6 100644 --- a/src/helper_search.py +++ b/src/helper_search.py @@ -1,5 +1,6 @@ """Additional SQL helper for searching messages""" -from helper_sql import * + +from helper_sql import sqlQuery try: from PyQt4 import QtGui @@ -7,13 +8,15 @@ try: except ImportError: haveQt = False -def search_translate (context, text): + +def search_translate(context, text): if haveQt: return QtGui.QApplication.translate(context, text) else: return text.lower() -def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = None, what = None, unreadOnly = False): + +def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False): if what is not None and what != "": what = "%" + what + "%" if where == search_translate("MainWindow", "To"): @@ -31,7 +34,7 @@ def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = if folder == "sent": sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime + SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime FROM sent ''' else: sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read @@ -67,7 +70,8 @@ def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = sqlStatementBase += " ORDER BY lastactiontime" return sqlQuery(sqlStatementBase, sqlArguments) -def check_match(toAddress, fromAddress, subject, message, where = None, what = None): + +def check_match(toAddress, fromAddress, subject, message, where=None, what=None): if what is not None and what != "": if where in (search_translate("MainWindow", "To"), search_translate("MainWindow", "All")): if what.lower() not in toAddress.lower(): From d5f541a2abdb2d9411fd11eca1bf12c021445018 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 9 Oct 2019 17:33:51 +0530 Subject: [PATCH 240/306] helper_search pylint fixes --- src/helper_search.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/helper_search.py b/src/helper_search.py index 8dfc7eb6..69acec43 100644 --- a/src/helper_search.py +++ b/src/helper_search.py @@ -10,13 +10,15 @@ except ImportError: def search_translate(context, text): + """Translation wrapper""" if haveQt: return QtGui.QApplication.translate(context, text) - else: - return text.lower() + return text.lower() def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False): + """Perform a search in mailbox tables""" + # pylint: disable=too-many-arguments, too-many-branches if what is not None and what != "": what = "%" + what + "%" if where == search_translate("MainWindow", "To"): @@ -64,7 +66,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlArguments.append(what) if unreadOnly: sqlStatementParts.append("read = 0") - if len(sqlStatementParts) > 0: + if sqlStatementParts: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" @@ -72,6 +74,8 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w def check_match(toAddress, fromAddress, subject, message, where=None, what=None): + """Check if a single message matches a filter (used when new messages are added to messagelists)""" + # pylint: disable=too-many-arguments if what is not None and what != "": if where in (search_translate("MainWindow", "To"), search_translate("MainWindow", "All")): if what.lower() not in toAddress.lower(): From d271996ac14c7b7097b4cbb395166aeb6477df11 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 9 Oct 2019 18:53:36 +0530 Subject: [PATCH 241/306] helper_sent flake8 fixes --- src/helper_sent.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helper_sent.py b/src/helper_sent.py index 6b73c8c5..75682fa9 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -2,7 +2,5 @@ Insert operation into sent table """ -from helper_sql import * - def insert(t): sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) From ece3005f42c7f3595f46ed290a6a6da9191a7a21 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 9 Oct 2019 18:57:51 +0530 Subject: [PATCH 242/306] helper_sent pylint fixes --- src/helper_sent.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/helper_sent.py b/src/helper_sent.py index 75682fa9..5a345fe7 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -1,6 +1,9 @@ """ -Insert operation into sent table +Insert values into sent table """ +from helper_sql import * + def insert(t): + """Perform an insert into the `sent` table""" sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) From e47b573b3eda9c93f56ecdb86b9c6c66fe4698f1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 10 Oct 2019 12:56:39 +0530 Subject: [PATCH 243/306] helper_sql pylint fixes --- src/helper_sql.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helper_sql.py b/src/helper_sql.py index 16d36637..e7f2a60e 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -2,9 +2,11 @@ SQL-related functions defined here are really pass the queries (or other SQL commands) to :class:`.threads.sqlThread` through `sqlSubmitQueue` queue and check or return the result got from `sqlReturnQueue`. + This is done that way because :mod:`sqlite3` is so thread-unsafe that they won't even let you call it from different threads using your own locks. SQLite objects can only be used from one thread. + .. note:: This actually only applies for certain deployments, and/or really old version of sqlite. I haven't actually seen it anywhere. Current versions do have support for threading and multiprocessing. @@ -92,13 +94,15 @@ def sqlExecute(sqlStatement, *args): sqlLock.release() return rowcount + def sqlStoredProcedure(procName): + """Schedule procName to be run""" sqlLock.acquire() sqlSubmitQueue.put(procName) sqlLock.release() -class SqlBulkExecute: +class SqlBulkExecute(object): """This is used when you have to execute the same statement in a cycle.""" def __enter__(self): From 43d63006250b9fe3625b786189f7f4742b94a7ee Mon Sep 17 00:00:00 2001 From: navjot Date: Tue, 26 Nov 2019 18:49:44 +0530 Subject: [PATCH 244/306] worked on trash message permanent delete functionlity --- src/bitmessagekivy/main.kv | 3 + src/bitmessagekivy/mpybit.py | 159 ++++++++++++++++++++++------------- src/class_singleCleaner.py | 13 ++- 3 files changed, 116 insertions(+), 59 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 5547de61..81586f2f 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -74,6 +74,7 @@ text: "Starred" icon:'star' on_release: app.root.ids.scr_mngr.current = 'starred' + badge_text: "0" NavigationDrawerIconButton: icon: 'archive' text: "Archieve" @@ -231,6 +232,7 @@ NavigationLayout: do_scroll_x: False MDList: id: ml + Loader: ComposerButton: : @@ -984,6 +986,7 @@ NavigationLayout: orientation: 'vertical' size_hint_y: None height: dp(100) + self.minimum_height + Loader: : id: cpyButton diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 6413c448..ad20147d 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -106,6 +106,7 @@ class Inbox(Screen): """Load Inbox list for Inbox messages.""" # pylint: disable=too-many-locals if state.searcing_text: + self.children[2].children[0].children[0].scroll_y = 1.0 where = ['subject', 'message'] what = state.searcing_text xAddress = 'toaddress' @@ -295,6 +296,7 @@ class MyAddress(Screen): # pylint: disable=unnecessary-lambda, deprecated-lambda self.addresses_list = state.kivyapp.variable_1 if state.searcing_text: + self.ids.refresh_layout.scroll_y = 1.0 filtered_list = filter( lambda addr: self.filter_address( addr), BMConfigParser().addresses()) @@ -413,6 +415,7 @@ class AddressBook(Screen): def loadAddresslist(self, account, where="", what=""): """Clock Schdule for method AddressBook.""" if state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 where = ['label', 'address'] what = state.searcing_text xAddress = '' @@ -477,7 +480,7 @@ class AddressBook(Screen): def update_addressBook_on_scroll(self, exist_addresses): """This method is used to load more data on scroll down""" - self.set_mdList(exist_addresses, exist_addresses + 20) + self.set_mdList(exist_addresses,exist_addresses + 5) @staticmethod def refreshs(*args): @@ -622,8 +625,6 @@ class DropDownWidget(BoxLayout): BMConfigParser().getint( 'bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress - # state.msg_counter_objs = self.parent.parent.parent.parent\ - # .parent.parent.children[0].children[2].children[0].ids state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[2].children[0].ids # self.parent.parent.screens[0].ids.ml.clear_widgets() @@ -631,9 +632,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.screens[3].update_sent_messagelist() self.parent.parent.screens[16].clear_widgets() self.parent.parent.screens[16].add_widget(Allmails()) - # toast('sending...') Clock.schedule_once(self.callback_for_msgsend, 3) - # toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" state.in_composer = True @@ -869,6 +868,7 @@ class Sent(Screen): def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" if state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 where = ['subject', 'message'] what = state.searcing_text xAddress = 'fromaddress' @@ -1057,6 +1057,8 @@ class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" trash_messages = ListProperty() has_refreshed = True + delete_index = StringProperty() + table_name = StringProperty() def __init__(self, *args, **kwargs): """Trash method, delete sent message and add in Trash.""" @@ -1069,11 +1071,10 @@ class Trash(Screen): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata" - " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" - " folder = 'trash' UNION SELECT toaddress, fromaddress, subject," - " message, folder, msgid As id, DATE(received) As actionTime FROM" - " inbox WHERE folder = 'trash' ORDER BY actionTime DESC") + "SELECT toaddress, fromaddress, subject, message, folder ||',' || 'sent' as folder, ackdata As id, DATE(lastactiontime)" + " As actionTime FROM sent WHERE folder = 'trash' and fromaddress = '{0}' UNION" + " SELECT toaddress, fromaddress, subject, message, folder ||',' || 'inbox' as folder, msgid As id, DATE(received) As" + " actionTime FROM inbox WHERE folder = 'trash' and toaddress = '{0}' ORDER BY actionTime DESC".format(state.association)) if self.trash_messages: src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.trash_cnt.badge_text = str(len(self.trash_messages)) @@ -1115,7 +1116,7 @@ class Trash(Screen): del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( - self.delete_permanently, item[5])) + self.delete_permanently, item[5], item[4])) carousel.add_widget(del_btn) carousel.add_widget(meny) carousel.index = 1 @@ -1137,9 +1138,49 @@ class Trash(Screen): """This method is used to load more data on scroll down""" self.set_mdList(total_trash_msg, total_trash_msg + 5) - def delete_permanently(self, data_index, instance, *args): + def delete_permanently(self, data_index, folder, instance, *args): """Deleting trash mail permanently.""" - pass + self.table_name = folder.split(',')[1] + self.delete_index = data_index + self.delete_confirmation() + + def callback_for_screen_load(self, dt=0): + """This methos is for loading screen""" + self.ids.ml.clear_widgets() + self.init_ui(0) + self.children[1].active = False + toast('Message is permanently deleted') + + def delete_confirmation(self): + """This method is used to show delete confirmation popup""" + delete_msg_dialog = MDDialog( + text='Are you sure you want to delete this message permanently from trash?', + title='', size_hint=(.8, .25), text_button_ok='Yes', + text_button_cancel='No', events_callback=self.callback_for_delete_msg) + delete_msg_dialog.open() + + def callback_for_delete_msg(self, text_item): + """Method is used for getting the callback of alert box""" + if text_item == 'Yes': + self.delete_message_from_trash() + else: + toast(text_item) + + def delete_message_from_trash(self): + """This method is used to delete """ + self.children[1].active = True + if self.table_name == 'inbox': + sqlExecute("DELETE FROM inbox WHERE msgid = ?;", str( + self.delete_index)) + elif self.table_name == 'sent': + sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( + self.delete_index)) + msg_count_objs = state.kivyapp.root.children[2].children[0].ids + if int(state.trash_count) > 0: + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) - 1) + state.trash_count = str(int(state.trash_count) - 1) + Clock.schedule_once(self.callback_for_screen_load, 1) class Page(Screen): @@ -1520,39 +1561,39 @@ class NavigateApp(App): self.refreshScreen() state.in_search_mode = False - def refreshScreen(self): # pylint: disable=unused-variable - """Method show search button only on inbox or sent screen.""" - state.searcing_text = '' - if state.search_screen == 'inbox': - try: - self.root.ids.sc1.children[ - 3].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc1.children[ - 2].children[1].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.children[ + def refreshScreen(self): # pylint: disable=unused-variable + """Method show search button only on inbox or sent screen.""" + state.searcing_text = '' + if state.search_screen == 'inbox': + try: + self.root.ids.sc1.children[ + 3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc1.children[ 2].children[1].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': - try: - self.root.ids.sc10.children[ - 3].children[1].ids.search_field.text = '' - except Exception: - self.root.ids.sc10.children[ - 2].children[1].ids.search_field.text = '' - self.root.ids.sc10.children[1].active = True - Clock.schedule_once(self.search_callback, 0.5) - else: - self.root.ids.sc4.children[ + 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[ + 2].children[1].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': + try: + self.root.ids.sc10.children[ + 3].children[1].ids.search_field.text = '' + except Exception: + self.root.ids.sc10.children[ 2].children[1].ids.search_field.text = '' - self.root.ids.sc4.children[1].active = True - Clock.schedule_once(self.search_callback, 0.5) - return + self.root.ids.sc10.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + else: + self.root.ids.sc4.children[ + 2].children[1].ids.search_field.text = '' + self.root.ids.sc4.children[1].active = True + Clock.schedule_once(self.search_callback, 0.5) + return def set_identicon(self, text): """This method is use for showing identicon in address spinner""" @@ -1768,6 +1809,7 @@ class MailDetail(Screen): msg_count_objs = state.kivyapp.root.children[2].children[0].ids state.searcing_text = '' if state.detailPageType == 'sent': + state.kivyapp.root.ids.sc4.children[2].children[1].ids.search_field.text = '' sqlExecute( "UPDATE sent SET folder = 'trash' WHERE" " ackdata = ?;", str(state.mail_id)) @@ -1776,6 +1818,8 @@ class MailDetail(Screen): self.parent.screens[3].ids.ml.clear_widgets() self.parent.screens[3].loadSent(state.association) elif state.detailPageType == 'inbox': + state.kivyapp.root.ids.sc1.children[2].children[1].ids.search_field.text = '' + self.parent.screens[0].children[2].children[1].ids.search_field.text = '' sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE" " msgid = ?;", str(state.mail_id)) @@ -1784,6 +1828,7 @@ class MailDetail(Screen): state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) + elif state.detailPageType == 'draft': sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( state.mail_id)) @@ -1793,8 +1838,8 @@ class MailDetail(Screen): self.parent.screens[15].clear_widgets() self.parent.screens[15].add_widget(Draft()) - self.parent.current = 'allmails' \ - if state.is_allmail else state.detailPageType + # self.parent.current = 'allmails' \ + # if state.is_allmail else state.detailPageType if state.detailPageType != 'draft': msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) @@ -1806,7 +1851,15 @@ class MailDetail(Screen): self.parent.screens[4].add_widget(Trash()) self.parent.screens[16].clear_widgets() self.parent.screens[16].add_widget(Allmails()) - state.kivyapp.back_press() + self.children[0].children[0].active = True + Clock.schedule_once(self.callback_for_delete, 3) + + def callback_for_delete(self, dt=0): + self.children[0].children[0].active = False + state.kivyapp.set_common_header() + self.parent.current = 'allmails' \ + if state.is_allmail else state.detailPageType + state.detailPageType = '' toast('Deleted') def inbox_reply(self): @@ -1824,10 +1877,6 @@ class MailDetail(Screen): self.parent.current = 'create' state.kivyapp.set_navbar_for_composer() - def copy_sent_mail(self): - """Method used for copying sent mail to the composer.""" - pass - def write_msg(self, navApp): """Method used to write on draft mail.""" state.send_draft_mail = state.mail_id @@ -2111,17 +2160,13 @@ class Draft(Screen): sendMessageToPeople = True if sendMessageToPeople: from addresses import decodeAddress - # status, addressVersionNumber, streamNumber, ripe = decodeAddress( - # toAddress) streamNumber, ripe = decodeAddress(toAddress)[2:] from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) - # statusIconColor = 'red' stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - # t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', @@ -2187,9 +2232,9 @@ class Allmails(Screen): self.all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata" " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" - " folder = 'sent' UNION SELECT toaddress, fromaddress, subject," + " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress, fromaddress, subject," " message, folder, msgid As id, DATE(received) As actionTime" - " FROM inbox WHERE folder = 'inbox' ORDER BY actionTime DESC") + " FROM inbox WHERE folder = 'inbox' and toaddress = '{0}' ORDER BY actionTime DESC".format(account)) if self.all_mails: state.kivyapp.root.children[2].children[ 0].ids.allmail_cnt.badge_text = str( diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 9a2916c7..2556f813 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -30,11 +30,11 @@ from helper_threading import StoppableThread from inventory import Inventory from network.connectionpool import BMConnectionPool from debug import logger +from datetime import datetime, timedelta import knownnodes import queues import state - class singleCleaner(StoppableThread): """Base method that Cleanup knownnodes and handle possible severe exception""" name = "singleCleaner" @@ -111,7 +111,7 @@ class singleCleaner(StoppableThread): resendPubkeyRequest(toAddress) elif status == 'msgsent': resendMsg(ackData) - + deleteTrashMsgPermonantly() try: # Cleanup knownnodes and handle possible severe exception # while writing it to disk @@ -202,3 +202,12 @@ def resendMsg(ackdata): 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...' )) + + +def deleteTrashMsgPermonantly(): + """This method is used to delete old messages""" + ndays_before_time = datetime.now() - timedelta(days=30) + old_messages = time.mktime(ndays_before_time.timetuple()) + sqlExecute("delete from sent where folder = 'trash' and lastactiontime <= ?;", int(old_messages)) + sqlExecute("delete from inbox where folder = 'trash' and received <= ?;", int(old_messages)) + return From 3053239a1b29b675c094545085b2aa84ba9d98d6 Mon Sep 17 00:00:00 2001 From: navjot Date: Fri, 29 Nov 2019 20:27:39 +0530 Subject: [PATCH 245/306] worked on suggestion text functionality on address creation --- src/bitmessagekivy/main.kv | 34 +++++++++++++++++++--------------- src/bitmessagekivy/mpybit.py | 31 ++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 81586f2f..1c2e3c6a 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -15,6 +15,7 @@ #:import Factory kivy.factory.Factory #:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout #:import MDSpinner kivymd.spinner.MDSpinner +#:import NoTransition kivy.uix.screenmanager.NoTransition #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -58,6 +59,7 @@ text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "0" + on_press: app.load_screen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' @@ -70,21 +72,21 @@ text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' badge_text: "0" - NavigationDrawerIconButton: - text: "Starred" - icon:'star' - on_release: app.root.ids.scr_mngr.current = 'starred' - badge_text: "0" - NavigationDrawerIconButton: - icon: 'archive' - text: "Archieve" - on_release: app.root.ids.scr_mngr.current = 'archieve' - badge_text: "0" - NavigationDrawerIconButton: - icon: 'email-open-outline' - text: "Spam" - on_release: app.root.ids.scr_mngr.current = 'spam' - badge_text: "0" + #NavigationDrawerIconButton: + #text: "Starred" + #icon:'star' + #on_release: app.root.ids.scr_mngr.current = 'starred' + #badge_text: "0" + #NavigationDrawerIconButton: + #icon: 'archive' + #text: "Archieve" + #on_release: app.root.ids.scr_mngr.current = 'archieve' + #badge_text: "0" + #NavigationDrawerIconButton: + #icon: 'email-open-outline' + #text: "Spam" + #on_release: app.root.ids.scr_mngr.current = 'spam' + #badge_text: "0" NavigationDrawerIconButton: id: trash_cnt icon: 'delete' @@ -196,6 +198,7 @@ NavigationLayout: : name: 'inbox' + transition: NoTransition() BoxLayout: orientation: 'vertical' spacing: dp(10) @@ -478,6 +481,7 @@ NavigationLayout: size_hint: .5, .35 height: dp(40) on_press: app.root.ids.scr_mngr.current = 'random' + on_press: app.root.ids.sc7.reset_address_label() MDLabel: font_style: 'Title' text: 'proceed' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ad20147d..2cce497d 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -834,13 +834,16 @@ class Random(Screen): for obj in BMConfigParser().addresses()] if entered_label in lables: self.ids.label.error = True - self.ids.label.helper_text = 'Label name is already exist' + self.ids.label.helper_text = 'Label name is already exist you can try this Ex. ( {0}_1, {0}_2 )'.format(entered_label) elif entered_label: self.ids.label.error = False else: self.ids.label.error = False self.ids.label.helper_text = 'This field is required' + def reset_address_label(self): + self.ids.label.text = '' + class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" @@ -1621,6 +1624,20 @@ class NavigateApp(App): 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 + self.root.ids.sc1.ids.ml.clear_widgets() + Clock.schedule_once(partial(self.load_screen_callback, instance), 0.5) + + def load_screen_callback(self, instance, dt=0): + """This method is rotating loader for few seconds""" + if instance.text == 'Inbox': + self.root.ids.sc1.loadMessagelist(state.association) + self.root.ids.sc1.children[1].active = False + class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1808,6 +1825,7 @@ class MailDetail(Screen): """Method for mail delete.""" msg_count_objs = state.kivyapp.root.children[2].children[0].ids state.searcing_text = '' + self.children[0].children[0].active = True if state.detailPageType == 'sent': state.kivyapp.root.ids.sc4.children[2].children[1].ids.search_field.text = '' sqlExecute( @@ -1847,12 +1865,11 @@ class MailDetail(Screen): int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) - self.parent.screens[4].clear_widgets() - self.parent.screens[4].add_widget(Trash()) - self.parent.screens[16].clear_widgets() - self.parent.screens[16].add_widget(Allmails()) - self.children[0].children[0].active = True - Clock.schedule_once(self.callback_for_delete, 3) + self.parent.screens[4].ids.ml.clear_widgets() + self.parent.screens[4].init_ui(dt=0) + self.parent.screens[16].ids.ml.clear_widgets() + self.parent.screens[16].init_ui(dt=0) + Clock.schedule_once(self.callback_for_delete, 4) def callback_for_delete(self, dt=0): self.children[0].children[0].active = False From a69732f060608428ddfebf608bdb3c8751e296ce Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 27 Nov 2019 06:47:04 +0100 Subject: [PATCH 246/306] Addrthread finish - addrthread is supposed to spread addresses as they appear. This was never finished during migration to asyncore - conservative to prevent flood and loops - randomises order - move protocol constants into a separate file - move addr packet creation into a separate file - see #1575 --- src/network/addrthread.py | 28 +++++++++++++---- src/network/announcethread.py | 5 +-- src/network/assemble.py | 32 +++++++++++++++++++ src/network/bmproto.py | 58 ++++++++++------------------------- src/network/constants.py | 11 +++++++ src/network/tcp.py | 6 ++-- 6 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 src/network/assemble.py create mode 100644 src/network/constants.py diff --git a/src/network/addrthread.py b/src/network/addrthread.py index d5d21599..8a0396f8 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -1,6 +1,11 @@ +""" +Announce addresses as they are received from other hosts +""" import Queue import state +from helper_random import randomshuffle +from network.assemble import assemble_addr from network.connectionpool import BMConnectionPool from queues import addrQueue from threads import StoppableThread @@ -15,15 +20,26 @@ class AddrThread(StoppableThread): while True: try: data = addrQueue.get(False) - chunk.append((data[0], data[1])) - if len(data) > 2: - source = BMConnectionPool().getConnectionByAddr(data[2]) + chunk.append(data) except Queue.Empty: break - except KeyError: - continue - # finish + if chunk: + # Choose peers randomly + connections = BMConnectionPool().establishedConnections() + randomshuffle(connections) + for i in connections: + randomshuffle(chunk) + filtered = [] + for stream, peer, seen, destination in chunk: + # peer's own address or address received from peer + if i.destination in (peer, destination): + continue + if stream not in i.streams: + continue + filtered.append((stream, peer, seen)) + if filtered: + i.append_write_buf(assemble_addr(filtered)) addrQueue.iterate() for i in range(len(chunk)): diff --git a/src/network/announcethread.py b/src/network/announcethread.py index f635fc90..c11a2cc6 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -6,8 +6,9 @@ src/network/announcethread.py import time import state + from bmconfigparser import BMConfigParser -from network.bmproto import BMProto +from network.assemble import assemble_addr from network.connectionpool import BMConnectionPool from network.udp import UDPSocket from node import Peer @@ -41,4 +42,4 @@ class AnnounceThread(StoppableThread): '127.0.0.1', BMConfigParser().safeGetInt('bitmessagesettings', 'port')), time.time()) - connection.append_write_buf(BMProto.assembleAddr([addr])) + connection.append_write_buf(assemble_addr([addr])) diff --git a/src/network/assemble.py b/src/network/assemble.py new file mode 100644 index 00000000..2d31914c --- /dev/null +++ b/src/network/assemble.py @@ -0,0 +1,32 @@ +""" +Create bitmessage protocol command packets +""" + +import struct + +import addresses +from network.constants import MAX_ADDR_COUNT +from network.node import Peer +from protocol import CreatePacket, encodeHost + + +def assemble_addr(peerList): + """Create address command""" + if isinstance(peerList, Peer): + peerList = (peerList) + if not peerList: + return b'' + retval = b'' + for i in range(0, len(peerList), MAX_ADDR_COUNT): + payload = addresses.encodeVarint( + len(peerList[i:i + MAX_ADDR_COUNT])) + for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]: + payload += struct.pack( + '>Q', timestamp) # 64-bit time + payload += struct.pack('>I', stream) + payload += struct.pack( + '>q', 1) # service bit flags offered by this node + payload += encodeHost(peer.host) + payload += struct.pack('>H', peer.port) # remote port + retval += CreatePacket('addr', payload) + return retval diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 11e96fd6..d620daa3 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -19,6 +19,12 @@ import state from bmconfigparser import BMConfigParser from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher +from network.constants import ( + ADDRESS_ALIVE, + MAX_MESSAGE_SIZE, + MAX_OBJECT_COUNT, + MAX_OBJECT_PAYLOAD_SIZE, + MAX_TIME_OFFSET) from network.dandelion import Dandelion from network.bmobject import ( BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, @@ -51,18 +57,6 @@ class BMProtoExcessiveDataError(BMProtoError): class BMProto(AdvancedDispatcher, ObjectTracker): """A parser for the Bitmessage Protocol""" # pylint: disable=too-many-instance-attributes, too-many-public-methods - # ~1.6 MB which is the maximum possible size of an inv message. - maxMessageSize = 1600100 - # 2**18 = 256kB is the maximum size of an object payload - maxObjectPayloadSize = 2**18 - # protocol specification says max 1000 addresses in one addr command - maxAddrCount = 1000 - # protocol specification says max 50000 objects in one inv command - maxObjectCount = 50000 - # address is online if online less than this many seconds ago - addressAlive = 10800 - # maximum time offset - maxTimeOffset = 3600 timeOffsetWrongCount = 0 def __init__(self, address=None, sock=None): # pylint: disable=unused-argument, super-init-not-called @@ -100,7 +94,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.close_reason = "Bad magic" self.set_state("close") return False - if self.payloadLength > BMProto.maxMessageSize: + if self.payloadLength > MAX_MESSAGE_SIZE: self.invalid = True self.set_state( "bm_command", @@ -343,7 +337,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def _command_inv(self, dandelion=False): items = self.decode_payload_content("l32s") - if len(items) > BMProto.maxObjectCount: + if len(items) > MAX_OBJECT_COUNT: logger.error( 'Too many items in %sinv message!', 'd' if dandelion else '') raise BMProtoExcessiveDataError() @@ -378,7 +372,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): nonce, expiresTime, objectType, version, streamNumber, self.payload, self.payloadOffset) - if len(self.payload) - self.payloadOffset > BMProto.maxObjectPayloadSize: + if len(self.payload) - self.payloadOffset > MAX_OBJECT_PAYLOAD_SIZE: logger.info( 'The payload length of this object is too large (%d bytes).' ' Ignoring it.', len(self.payload) - self.payloadOffset) @@ -442,7 +436,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): continue if ( decodedIP and time.time() - seenTime > 0 and - seenTime > time.time() - BMProto.addressAlive and + seenTime > time.time() - ADDRESS_ALIVE and port > 0 ): peer = Peer(decodedIP, port) @@ -461,7 +455,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): "rating": 0, "self": False, } - addrQueue.put((stream, peer, self.destination)) + # since we don't track peers outside of knownnodes, + # only spread if in knownnodes to prevent flood + addrQueue.put((stream, peer, seenTime, + self.destination)) return True def bm_command_portcheck(self): @@ -552,7 +549,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 'Closing connection to old protocol version %s, node: %s', self.remoteProtocolVersion, self.destination) return False - if self.timeOffset > BMProto.maxTimeOffset: + if self.timeOffset > MAX_TIME_OFFSET: self.append_write_buf(protocol.assembleErrorMessage( errorText="Your time is too far in the future compared to mine." " Closing connection.", fatal=2)) @@ -561,7 +558,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): " Closing connection to it.", self.destination, self.timeOffset) BMProto.timeOffsetWrongCount += 1 return False - elif self.timeOffset < -BMProto.maxTimeOffset: + elif self.timeOffset < -MAX_TIME_OFFSET: self.append_write_buf(protocol.assembleErrorMessage( errorText="Your time is too far in the past compared to mine." " Closing connection.", fatal=2)) @@ -623,29 +620,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True - @staticmethod - def assembleAddr(peerList): - """Build up a packed address""" - if isinstance(peerList, Peer): - peerList = (peerList) - if not peerList: - return b'' - retval = b'' - for i in range(0, len(peerList), BMProto.maxAddrCount): - payload = addresses.encodeVarint( - len(peerList[i:i + BMProto.maxAddrCount])) - for address in peerList[i:i + BMProto.maxAddrCount]: - stream, peer, timestamp = address - payload += struct.pack( - '>Q', timestamp) # 64-bit time - payload += struct.pack('>I', stream) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(peer.host) - payload += struct.pack('>H', peer.port) # remote port - retval += protocol.CreatePacket('addr', payload) - return retval - @staticmethod def stopDownloadingObject(hashId, forwardAnyway=False): """Stop downloading an object""" diff --git a/src/network/constants.py b/src/network/constants.py new file mode 100644 index 00000000..a3414ef3 --- /dev/null +++ b/src/network/constants.py @@ -0,0 +1,11 @@ +""" +Network protocol constants +""" + + +ADDRESS_ALIVE = 10800 #: address is online if online less than this many seconds ago +MAX_ADDR_COUNT = 1000 #: protocol specification says max 1000 addresses in one addr command +MAX_MESSAGE_SIZE = 1600100 #: ~1.6 MB which is the maximum possible size of an inv message. +MAX_OBJECT_PAYLOAD_SIZE = 2**18 #: 2**18 = 256kB is the maximum size of an object payload +MAX_OBJECT_COUNT = 50000 #: protocol specification says max 50000 objects in one inv command +MAX_TIME_OFFSET = 3600 #: maximum time offset diff --git a/src/network/tcp.py b/src/network/tcp.py index 31d20dea..3097765f 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -22,7 +22,9 @@ from bmconfigparser import BMConfigParser from helper_random import randomBytes from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher +from network.assemble import assemble_addr from network.bmproto import BMProto +from network.constants import MAX_OBJECT_COUNT from network.dandelion import Dandelion from network.objectracker import ObjectTracker from network.socks4a import Socks4aConnection @@ -183,7 +185,7 @@ class TCPConnection(BMProto, TLSDispatcher): for peer, params in addrs[substream]: templist.append((substream, peer, params["lastseen"])) if templist: - self.append_write_buf(BMProto.assembleAddr(templist)) + self.append_write_buf(assemble_addr(templist)) def sendBigInv(self): """ @@ -222,7 +224,7 @@ class TCPConnection(BMProto, TLSDispatcher): # Remove -1 below when sufficient time has passed for users to # upgrade to versions of PyBitmessage that accept inv with 50,000 # items - if objectCount >= BMProto.maxObjectCount - 1: + if objectCount >= MAX_OBJECT_COUNT - 1: sendChunk() payload = b'' objectCount = 0 From b90c9da0a419dfa6c919a3080364a0ca4f345df8 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 28 Nov 2019 20:20:00 +0530 Subject: [PATCH 247/306] mpybit fixes --- src/bitmessagekivy/mpybit.py | 47 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 2cce497d..2d54516f 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -480,7 +480,7 @@ class AddressBook(Screen): def update_addressBook_on_scroll(self, exist_addresses): """This method is used to load more data on scroll down""" - self.set_mdList(exist_addresses,exist_addresses + 5) + self.set_mdList(exist_addresses, exist_addresses + 5) @staticmethod def refreshs(*args): @@ -1074,10 +1074,15 @@ class Trash(Screen): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder ||',' || 'sent' as folder, ackdata As id, DATE(lastactiontime)" - " As actionTime FROM sent WHERE folder = 'trash' and fromaddress = '{0}' UNION" - " SELECT toaddress, fromaddress, subject, message, folder ||',' || 'inbox' as folder, msgid As id, DATE(received) As" - " actionTime FROM inbox WHERE folder = 'trash' and toaddress = '{0}' ORDER BY actionTime DESC".format(state.association)) + "SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'sent' as folder, ackdata As id," + " DATE(lastactiontime) As actionTime FROM sent" + " WHERE folder = 'trash' and fromaddress = '{0}' UNION" + " SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'inbox' as folder, msgid As id," + " DATE(received) As actionTime FROM inbox WHERE" + " folder = 'trash' and toaddress = '{0}'" + " ORDER BY actionTime DESC".format(state.association)) if self.trash_messages: src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.trash_cnt.badge_text = str(len(self.trash_messages)) @@ -1157,9 +1162,13 @@ class Trash(Screen): def delete_confirmation(self): """This method is used to show delete confirmation popup""" delete_msg_dialog = MDDialog( - text='Are you sure you want to delete this message permanently from trash?', - title='', size_hint=(.8, .25), text_button_ok='Yes', - text_button_cancel='No', events_callback=self.callback_for_delete_msg) + text='Are you sure you want to delete this' / + ' message permanently from trash?', + title='', + size_hint=(.8, .25), + text_button_ok='Yes', + text_button_cancel='No', + events_callback=self.callback_for_delete_msg) delete_msg_dialog.open() def callback_for_delete_msg(self, text_item): @@ -1181,7 +1190,7 @@ class Trash(Screen): msg_count_objs = state.kivyapp.root.children[2].children[0].ids if int(state.trash_count) > 0: msg_count_objs.trash_cnt.badge_text = str( - int(state.trash_count) - 1) + int(state.trash_count) - 1) state.trash_count = str(int(state.trash_count) - 1) Clock.schedule_once(self.callback_for_screen_load, 1) @@ -1827,7 +1836,8 @@ class MailDetail(Screen): state.searcing_text = '' self.children[0].children[0].active = True if state.detailPageType == 'sent': - state.kivyapp.root.ids.sc4.children[2].children[1].ids.search_field.text = '' + state.kivyapp.root.ids.sc4.children[ + 2].children[1].ids.search_field.text = '' sqlExecute( "UPDATE sent SET folder = 'trash' WHERE" " ackdata = ?;", str(state.mail_id)) @@ -1836,8 +1846,10 @@ class MailDetail(Screen): self.parent.screens[3].ids.ml.clear_widgets() self.parent.screens[3].loadSent(state.association) elif state.detailPageType == 'inbox': - state.kivyapp.root.ids.sc1.children[2].children[1].ids.search_field.text = '' - self.parent.screens[0].children[2].children[1].ids.search_field.text = '' + state.kivyapp.root.ids.sc1.children[ + 2].children[1].ids.search_field.text = '' + self.parent.screens[0].children[2].children[ + 1].ids.search_field.text = '' sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE" " msgid = ?;", str(state.mail_id)) @@ -1846,7 +1858,7 @@ class MailDetail(Screen): state.inbox_count = str(int(state.inbox_count) - 1) self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) - + elif state.detailPageType == 'draft': sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( state.mail_id)) @@ -1872,6 +1884,7 @@ class MailDetail(Screen): Clock.schedule_once(self.callback_for_delete, 4) def callback_for_delete(self, dt=0): + """Delete method from allmails""" self.children[0].children[0].active = False state.kivyapp.set_common_header() self.parent.current = 'allmails' \ @@ -2249,9 +2262,11 @@ class Allmails(Screen): self.all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata" " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" - " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress, fromaddress, subject," - " message, folder, msgid As id, DATE(received) As actionTime" - " FROM inbox WHERE folder = 'inbox' and toaddress = '{0}' ORDER BY actionTime DESC".format(account)) + " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress," + " fromaddress, subject, message, folder, msgid As id," + " DATE(received) As actionTime FROM inbox WHERE" + " folder = 'inbox' and toaddress = '{0}'" + " ORDER BY actionTime DESC".format(account)) if self.all_mails: state.kivyapp.root.children[2].children[ 0].ids.allmail_cnt.badge_text = str( From e0536e7497a58bbefe5fc16868e97e6a290107eb Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 29 Nov 2019 17:42:38 +0530 Subject: [PATCH 248/306] docstring and formatting mpybit --- src/bitmessagekivy/mpybit.py | 412 +++++++++++++++++------------------ 1 file changed, 202 insertions(+), 210 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 2d54516f..1a8dabac 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,12 +1,12 @@ """ -Bitmessage kivy interface +Bitmessage android(mobile) interface """ # pylint: disable=relative-import, import-error, no-name-in-module # pylint: disable=too-few-public-methods, too-many-lines, unused-argument import os import time -from functools import partial from bmconfigparser import BMConfigParser +from functools import partial from helper_sql import sqlExecute, sqlQuery from kivy.app import App from kivy.clock import Clock @@ -65,7 +65,7 @@ import identiconGeneration def toast(text): - """Function displays toast message.""" + """Function displays toast message""" # pylint: disable=redefined-outer-name from kivymd.toast.kivytoast import toast toast(text) @@ -73,19 +73,19 @@ def toast(text): class Navigatorss(MDNavigationDrawer): - """Navigator class contains image, title and logo.""" + """Navigator class (image, title and logo)""" image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() class Inbox(Screen): - """Inbox Screen uses screen to show widgets of screens.""" + """Inbox Screen uses screen to show widgets of screens""" queryreturn = ListProperty() has_refreshed = True def __init__(self, *args, **kwargs): - """Method Parsing the address.""" + """Method Parsing the address""" super(Inbox, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -93,17 +93,17 @@ class Inbox(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts.""" + """Clock schdule for method inbox accounts""" self.inboxaccounts() print dt def inboxaccounts(self): - """Load inbox accounts.""" + """Load all inbox accounts""" account = state.association self.loadMessagelist(account, 'All', '') def loadMessagelist(self, account, where="", what=""): - """Load Inbox list for Inbox messages.""" + """Load inbox list for inbox messages""" # pylint: disable=too-many-locals if state.searcing_text: self.children[2].children[0].children[0].scroll_y = 1.0 @@ -149,11 +149,14 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - avatarImageFirstLetter(item['secondary_text'].strip())))) - meny.bind(on_press=partial( - self.inbox_detail, item['msgid'])) + meny.add_widget( + AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter( + item['secondary_text'].strip())))) + meny.bind( + on_press=partial( + self.inbox_detail, item['msgid'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -163,14 +166,16 @@ class Inbox(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete, item['msgid'])) + del_btn.bind( + on_press=partial( + self.delete, item['msgid'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial( - self.archive, item['msgid'])) + ach_btn.bind( + on_press=partial( + self.archive, item['msgid'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) @@ -192,7 +197,6 @@ class Inbox(Screen): """This method is used to load more data on scroll down""" data = [] for mail in self.queryreturn[total_message:total_message + 5]: - # third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( @@ -202,7 +206,7 @@ class Inbox(Screen): self.set_mdList(data) def inbox_detail(self, msg_id, *args): - """Load inbox page details.""" + """Load inbox page details""" state.detailPageType = 'inbox' state.mail_id = msg_id if self.manager: @@ -214,7 +218,7 @@ class Inbox(Screen): src_mng_obj.current = 'mailDetail' def delete(self, data_index, instance, *args): - """Delete inbox mail from inbox listing.""" + """Delete inbox mail from inbox listing""" sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) @@ -244,7 +248,7 @@ class Inbox(Screen): self.update_trash() def archive(self, data_index, instance, *args): - """Archive inbox mail from inbox listing.""" + """Archive inbox mail from inbox listing""" sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( data_index)) @@ -252,7 +256,7 @@ class Inbox(Screen): self.update_trash() def update_trash(self): - """Update trash screen mails which is deleted from inbox.""" + """Update trash screen mails which is deleted from inbox""" try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) @@ -263,9 +267,9 @@ class Inbox(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): """Method updates the state of application, - While the spinner remains on the screen.""" + While the spinner remains on the screen""" def refresh_callback(interval): - """Method used for loading the inbox screen data.""" + """Method used for loading the inbox screen data""" state.searcing_text = '' self.children[2].children[1].ids.search_field.text = '' self.ids.ml.clear_widgets() @@ -282,17 +286,17 @@ class Inbox(Screen): class MyAddress(Screen): - """MyAddress Screen uses screen to show widgets of screens.""" + """MyAddress screen uses screen to show widgets of screens""" addresses_list = ListProperty() has_refreshed = True def __init__(self, *args, **kwargs): - """Clock Schdule for method inbox accounts.""" + """Clock schdule for method inbox accounts""" super(MyAddress, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts.""" + """Clock schdule for method inbox accounts""" # pylint: disable=unnecessary-lambda, deprecated-lambda self.addresses_list = state.kivyapp.variable_1 if state.searcing_text: @@ -324,7 +328,7 @@ class MyAddress(Screen): pass def set_mdList(self, first_index, last_index): - """This method is used to create the mdlist""" + """Creating the mdlist""" data = [] for address in self.addresses_list[first_index:last_index]: data.append({ @@ -344,7 +348,7 @@ class MyAddress(Screen): self.ids.ml.add_widget(meny) def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """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 my_addresses = len(self.ids.ml.children) @@ -356,12 +360,12 @@ class MyAddress(Screen): pass def update_addressBook_on_scroll(self, my_addresses): - """This method is used to load more data on scroll down""" + """Loads more data on scroll down""" self.set_mdList(my_addresses, my_addresses + 20) @staticmethod def myadd_detail(fromaddress, label, *args): - """Myaddress Details.""" + """Load myaddresses details""" p = MyaddDetailPopup() p.open() p.set_address(fromaddress, label) @@ -369,9 +373,9 @@ class MyAddress(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): """Method updates the state of application, - While the spinner remains on the screen.""" + While the spinner remains on the screen""" def refresh_callback(interval): - """Method used for loading the myaddress screen data.""" + """Method used for loading the myaddress screen data""" state.searcing_text = '' state.kivyapp.root.ids.sc10.children[2].active = False self.children[2].children[1].ids.search_field.text = '' @@ -384,11 +388,11 @@ class MyAddress(Screen): @staticmethod def filter_address(address): - """Method will filter the my address list data.""" - # pylint: disable=deprecated-lambda - if filter(lambda x: (state.searcing_text).lower() in x, [ - BMConfigParser().get( - address, 'label').lower(), address.lower()]): + """Method will filter the my address list data""" + # if filter(lambda x: (state.searcing_text).lower() in x, [ + # BMConfigParser().get( + # address, 'label').lower(), address.lower()]): + if [x for x in [BMConfigParser().get(address, 'label').lower(), address.lower()]]: return True return False @@ -398,22 +402,22 @@ class MyAddress(Screen): class AddressBook(Screen): - """AddressBook Screen uses screen to show widgets of screens.""" + """AddressBook Screen uses screen to show widgets of screens""" queryreturn = ListProperty() has_refreshed = True def __init__(self, *args, **kwargs): - """Getting AddressBook Details.""" + """Getting AddressBook Details""" super(AddressBook, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method AddressBook.""" + """Clock Schdule for method AddressBook""" self.loadAddresslist(None, 'All', '') print dt def loadAddresslist(self, account, where="", what=""): - """Clock Schdule for method AddressBook.""" + """Clock Schdule for method AddressBook""" if state.searcing_text: self.ids.scroll_y.scroll_y = 1.0 where = ['label', 'address'] @@ -439,7 +443,7 @@ class AddressBook(Screen): self.ids.ml.add_widget(content) def set_mdList(self, start_index, end_index): - """This method is used to create the mdList""" + """Creating the mdList""" for item in self.queryreturn[start_index:end_index]: meny = TwoLineAvatarIconListItem( text=item[0], @@ -467,7 +471,7 @@ class AddressBook(Screen): self.ids.ml.add_widget(carousel) def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """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 exist_addresses = len(self.ids.ml.children) @@ -479,25 +483,25 @@ class AddressBook(Screen): pass def update_addressBook_on_scroll(self, exist_addresses): - """This method is used to load more data on scroll down""" + """Load more data on scroll down""" self.set_mdList(exist_addresses, exist_addresses + 5) @staticmethod def refreshs(*args): - """Refresh the Widget.""" + """Refresh the Widget""" # state.navinstance.ids.sc11.ids.ml.clear_widgets() # state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') pass @staticmethod def addBook_detail(address, label, *args): - """Addressbook Details.""" + """Addressbook details""" p = AddbookDetailPopup() p.open() p.set_addbook_data(address, label) def delete_address(self, address, instance, *args): - """Delete inbox mail from inbox listing.""" + """Delete inbox mail from inbox listing""" self.ids.ml.remove_widget(instance.parent.parent) sqlExecute( "DELETE FROM addressbook WHERE address = '{}';".format(address)) @@ -505,34 +509,33 @@ class AddressBook(Screen): class SelectableRecycleBoxLayout( FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): - """Adds selection and focus behaviour to the view.""" + """Adds selection and focus behaviour to the view""" # pylint: disable = too-many-ancestors - pass class SelectableLabel(RecycleDataViewBehavior, Label): - """Add selection support to the 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.""" + """Catch and handle the view changes""" self.index = index return super(SelectableLabel, self).refresh_view_attrs( rv, index, data) # pylint: disable=inconsistent-return-statements def on_touch_down(self, touch): - """Add selection on touch down.""" + """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.""" + """Respond to the selection of items in the view""" self.selected = is_selected if is_selected: print "selection changed to {0}".format(rv.data[index]) @@ -541,23 +544,22 @@ class SelectableLabel(RecycleDataViewBehavior, Label): class RV(RecycleView): - """Recycling View.""" + """Recycling View""" - def __init__(self, **kwargs): - """Recycling Method.""" - # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + """Recycling Method""" super(RV, self).__init__(**kwargs) class DropDownWidget(BoxLayout): - """Adding Dropdown Widget.""" + """Adding Dropdown Widget""" # pylint: disable=too-many-statements, too-many-locals # pylint: disable=inconsistent-return-statements txt_input = ObjectProperty() rv = ObjectProperty() def send(self, navApp): - """Send message from one address to another.""" + """Send message from one address to another""" fromAddress = str(self.ids.ti.text) toAddress = str(self.ids.txt_input.text) subject = self.ids.subject.text.encode('utf-8').strip() @@ -655,7 +657,7 @@ class DropDownWidget(BoxLayout): # pylint: disable=attribute-defined-outside-init def address_error_message(self, msg): - """Show Error Message.""" + """Generates error message""" msg_dialog = MDDialog( text=msg, title='', size_hint=(.8, .25), text_button_ok='Ok', @@ -664,11 +666,11 @@ class DropDownWidget(BoxLayout): @staticmethod def callback_for_menu_items(text_item): - """Method is used for getting the callback of alert box""" + """Callback of alert box""" toast(text_item) def reset_composer(self): - """Method will reset composer.""" + """Method will reset composer""" self.ids.ti.text = '' self.ids.btn.text = 'Select' self.ids.txt_input.text = '' @@ -677,26 +679,25 @@ class DropDownWidget(BoxLayout): toast("Reset message") def auto_fill_fromaddr(self): - """Mehtod used to fill the text automatically From Address.""" + """Fill the text automatically From Address""" self.ids.ti.text = self.ids.btn.text self.ids.ti.focus = True class MyTextInput(TextInput): - """Takes the text input in the field.""" + """Takes the text input in the field""" txt_input = ObjectProperty() flt_list = ObjectProperty() word_list = ListProperty() starting_no = NumericProperty(3) suggestion_text = '' - def __init__(self, **kwargs): - """Getting Text Input.""" - # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + """Getting Text Input""" super(MyTextInput, self).__init__(**kwargs) def on_text(self, instance, value): - """Find all the occurrence of the word.""" + """Find all the occurrence of the word""" self.parent.parent.parent.parent.ids.rv.data = [] matches = [self.word_list[i] for i in range( len(self.word_list)) if self.word_list[ @@ -711,7 +712,7 @@ class MyTextInput(TextInput): self.parent.height = 400 def keyboard_on_key_down(self, window, keycode, text, modifiers): - """Key Down.""" + """Key Down""" if self.suggestion_text and keycode[1] == 'tab': self.insert_text(self.suggestion_text + ' ') return True @@ -720,11 +721,10 @@ class MyTextInput(TextInput): class Payment(Screen): - """Payment Method.""" + """Payment module""" - def get_available_credits(self, instance): - """Method helps to get the available credits""" - # pylint: disable=no-self-use + def get_available_credits(self, instance): # pylint: disable=no-self-use + """Get the available credits""" state.availabe_credit = instance.parent.children[1].text existing_credits = ( state.kivyapp.root.ids.sc18.ids.ml.children[0].children[ @@ -741,17 +741,17 @@ class Payment(Screen): class Credits(Screen): - """Credits Method""" + """Credits Module""" available_credits = StringProperty('{0}'.format('0')) class Login(Screen): - """Login Screeen.""" + """Login Screeen""" pass class NetworkStat(Screen): - """Method used to show network stat.""" + """Method used to show network stat""" text_variable_1 = StringProperty( '{0}::{1}'.format('Total Connections', '0')) text_variable_2 = StringProperty( @@ -763,12 +763,12 @@ class NetworkStat(Screen): 'Processed {0} object to be synced'.format('0')) def __init__(self, *args, **kwargs): - """Init method for network stat.""" + """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 inbox accounts.""" + """Clock Schdule for method inbox accounts""" import network.stats import shared from network import objectracker @@ -785,17 +785,17 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): - """Navigate Content Drawer.""" + """Navigate Content Drawer""" pass class Random(Screen): - """Generates Random Address.""" + """Generates Random Address""" is_active = BooleanProperty(False) checked = StringProperty("") def generateaddress(self, navApp): - """Method for Address Generator.""" + """Method for Address Generator""" entered_label = str(self.ids.label.text).strip() streamNumberForAddress = 1 label = self.ids.label.text @@ -828,7 +828,7 @@ class Random(Screen): toast('New address created') def add_validation(self, instance): - """Checking validation at address creation time.""" + """Checking validation at address creation time""" entered_label = str(instance.text.strip()) lables = [BMConfigParser().get(obj, 'label') for obj in BMConfigParser().addresses()] @@ -846,12 +846,12 @@ class Random(Screen): class Sent(Screen): - """Sent Screen uses screen to show widgets of screens.""" + """Sent Screen uses screen to show widgets of screens""" queryreturn = ListProperty() has_refreshed = True def __init__(self, *args, **kwargs): - """Association with the screen.""" + """Association with the screen""" super(Sent, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -859,17 +859,17 @@ class Sent(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method sent accounts.""" + """Clock Schdule for method sent accounts""" self.sentaccounts() print dt def sentaccounts(self): - """Load sent accounts.""" + """Load sent accounts""" account = state.association self.loadSent(account, 'All', '') def loadSent(self, account, where="", what=""): - """Load Sent list for Sent messages.""" + """Load Sent list for Sent messages""" if state.searcing_text: self.ids.scroll_y.scroll_y = 1.0 where = ['subject', 'message'] @@ -967,7 +967,7 @@ class Sent(Screen): self.set_mdlist(data, total_sent - 1) def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """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 total_sent_msg = len(self.ids.ml.children) @@ -979,7 +979,7 @@ class Sent(Screen): pass def update_sent_screen_on_scroll(self, total_sent_msg): - """This method is used to load more data on scroll down""" + """Load more data on scroll down""" data = [] for mail in self.queryreturn[total_sent_msg:total_sent_msg + 5]: data.append({ @@ -998,7 +998,7 @@ class Sent(Screen): state.sent_count = str(total_sent) def sent_detail(self, ackdata, *args): - """Load sent mail details.""" + """Load sent mail details""" state.detailPageType = 'sent' state.mail_id = ackdata if self.manager: @@ -1010,7 +1010,7 @@ class Sent(Screen): src_mng_obj.current = 'mailDetail' def delete(self, data_index, instance, *args): - """Delete sent mail from sent mail listing.""" + """Delete sent mail from sent mail listing""" try: msg_count_objs = self.parent.parent.parent.parent.children[ 2].children[0].ids @@ -1035,7 +1035,7 @@ class Sent(Screen): self.update_trash() def archive(self, data_index, instance, *args): - """Archive sent mail from sent mail listing.""" + """Archive sent mail from sent mail listing""" sqlExecute( "UPDATE sent SET folder = 'trash'" " WHERE ackdata = ?;", str(data_index)) @@ -1043,7 +1043,7 @@ class Sent(Screen): self.update_trash() def update_trash(self): - """Update trash screen mails which is deleted from inbox.""" + """Update trash screen mails which is deleted from inbox""" try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) @@ -1057,19 +1057,19 @@ class Sent(Screen): class Trash(Screen): - """Trash Screen uses screen to show widgets of screens.""" + """Trash Screen uses screen to show widgets of screens""" trash_messages = ListProperty() has_refreshed = True delete_index = StringProperty() table_name = StringProperty() def __init__(self, *args, **kwargs): - """Trash method, delete sent message and add in Trash.""" + """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, dt=0): - """Clock Schdule for method inbox accounts.""" + """Clock Schdule for method inbox accounts""" if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] @@ -1101,7 +1101,7 @@ class Trash(Screen): self.ids.ml.add_widget(content) def set_mdList(self, first_index, last_index): - """This method is used to create the mdlist""" + """Creating the mdlist""" for item in self.trash_messages[first_index:last_index]: meny = TwoLineAvatarIconListItem( text=item[1], @@ -1131,7 +1131,7 @@ class Trash(Screen): self.ids.ml.add_widget(carousel) def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """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 total_trash_msg = len(self.ids.ml.children) @@ -1143,11 +1143,11 @@ class Trash(Screen): pass def update_trash_screen_on_scroll(self, total_trash_msg): - """This method is used to load more data on scroll down""" + """Load more data on scroll down""" self.set_mdList(total_trash_msg, total_trash_msg + 5) def delete_permanently(self, data_index, folder, instance, *args): - """Deleting trash mail permanently.""" + """Deleting trash mail permanently""" self.table_name = folder.split(',')[1] self.delete_index = data_index self.delete_confirmation() @@ -1160,7 +1160,7 @@ class Trash(Screen): toast('Message is permanently deleted') def delete_confirmation(self): - """This method is used to show delete confirmation popup""" + """Show confirmation delete popup""" delete_msg_dialog = MDDialog( text='Are you sure you want to delete this' / ' message permanently from trash?', @@ -1172,14 +1172,14 @@ class Trash(Screen): delete_msg_dialog.open() def callback_for_delete_msg(self, text_item): - """Method is used for getting the callback of alert box""" + """Getting the callback of alert box""" if text_item == 'Yes': self.delete_message_from_trash() else: toast(text_item) def delete_message_from_trash(self): - """This method is used to delete """ + """Deleting message from trash""" self.children[1].active = True if self.table_name == 'inbox': sqlExecute("DELETE FROM inbox WHERE msgid = ?;", str( @@ -1196,16 +1196,14 @@ class Trash(Screen): class Page(Screen): - """Page Screen show widgets of page.""" - + """Page Screen show widgets of page""" pass class Create(Screen): - """Creates the screen widgets.""" - + """Creates the screen widgets""" def __init__(self, **kwargs): - """Getting Labels and address from addressbook.""" + """Getting Labels and address from addressbook""" super(Create, self).__init__(**kwargs) widget_1 = DropDownWidget() widget_1.ids.txt_input.word_list = [ @@ -1216,14 +1214,12 @@ class Create(Screen): class Setting(Screen): - """Setting the Screen components.""" - + """Setting the Screen components""" pass -class NavigateApp(App): - """Navigation Layout of class.""" - # pylint: disable=too-many-public-methods +class NavigateApp(App): # pylint: disable=too-many-public-methods + """Navigation Layout of class""" theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() @@ -1252,7 +1248,7 @@ class NavigateApp(App): ] def build(self): - """Method builds the widget.""" + """Method builds the widget""" main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -1264,14 +1260,14 @@ class NavigateApp(App): return main_widget def run(self): - """Running the widgets.""" + """Running the widgets""" kivyuisignaler.release() super(NavigateApp, self).run() # pylint: disable=inconsistent-return-statements @staticmethod def showmeaddresses(name="text"): - """Show the addresses in spinner to make as dropdown.""" + """Show the addresses in spinner to make as dropdown""" if name == "text": if BMConfigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' @@ -1283,7 +1279,7 @@ class NavigateApp(App): return "valuesdemo" def getCurrentAccountData(self, text): - """Get Current Address Account Data.""" + """Get Current Address Account Data""" self.set_identicon(text) address_label = self.current_address_label( BMConfigParser().get(text, 'label'), text) @@ -1338,19 +1334,19 @@ class NavigateApp(App): @staticmethod def getCurrentAccount(): - """It uses to get current account label.""" + """It uses to get current account label""" if state.association: return state.association return "Bitmessage Login" @staticmethod def addingtoaddressbook(): - """Adding to address Book.""" + """Adding to address Book""" p = GrashofPopup() p.open() def getDefaultAccData(self): - """Getting Default Account Data.""" + """Getting Default Account Data""" if BMConfigParser().addresses(): img = identiconGeneration.generate(BMConfigParser().addresses()[0]) self.createFolder('./images/default_identicon/') @@ -1370,7 +1366,7 @@ class NavigateApp(App): @staticmethod def createFolder(directory): - """This method is used to create the directory when app starts""" + """Create directory when app starts""" try: if not os.path.exists(directory): os.makedirs(directory) @@ -1387,13 +1383,13 @@ class NavigateApp(App): @staticmethod def addressexist(): - """Checking address existence.""" + """Checking address existence""" if BMConfigParser().addresses(): return True return False def on_key(self, window, key, *args): - """Method is used for going on previous screen.""" + """Method is used for going on previous screen""" if key == 27: if state.in_search_mode and self.root.ids.scr_mngr.current != ( "mailDetail"): @@ -1432,7 +1428,7 @@ class NavigateApp(App): Clock.schedule_once(self.search_callback, 0.5) def search_callback(self, dt=0): - """This method is used to show data after loader is loaded""" + """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) @@ -1462,19 +1458,19 @@ class NavigateApp(App): return def reset(self, *args): - """Method used to set transition direction.""" + """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): - """Method used for status dispatching acknowledgment.""" + """Dispatching Status acknowledgment""" ackData, message = data if state.ackdata == ackData: state.status.status = message def clear_composer(self): - """If slow down the nwe will make new composer edit screen.""" + """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 = '' @@ -1486,7 +1482,7 @@ class NavigateApp(App): state.in_sent_method = False def set_navbar_for_composer(self): - """This method is used for clearing toolbar data when composer open""" + """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 = [ @@ -1496,7 +1492,7 @@ class NavigateApp(App): lambda x: self.root.ids.sc3.children[1].send(self)]] def set_common_header(self): - """Common for all window""" + """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 = [ @@ -1504,10 +1500,10 @@ class NavigateApp(App): return def back_press(self): - """Method used for going back from composer to previous page.""" + """Method for, reverting composer to previous page""" self.save_draft() - if self.root.ids.scr_mngr.current == 'mailDetail' \ - and state.in_search_mode: + 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()]] @@ -1528,14 +1524,14 @@ class NavigateApp(App): @staticmethod def on_stop(): - """On stop methos is used for stoping the runing script.""" + """On stop methos is used for stoping the runing script""" print "*******************EXITING FROM APPLICATION*******************" import shutdown shutdown.doCleanShutdown() @staticmethod def current_address_label(current_add_label=None, current_addr=None): - """Getting current address labels.""" + """Getting current address labels""" if BMConfigParser().addresses(): if current_add_label: first_name = current_add_label @@ -1551,7 +1547,7 @@ class NavigateApp(App): return '' def searchQuery(self, instance): - """Method used for showing searched mails.""" + """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: @@ -1563,7 +1559,7 @@ class NavigateApp(App): state.in_search_mode = True def closeSearchScreen(self): - """Function for close search screen""" + """Function for close search screen""" self.set_common_header() address_label = self.current_address_label( BMConfigParser().get( @@ -1574,7 +1570,7 @@ class NavigateApp(App): state.in_search_mode = False def refreshScreen(self): # pylint: disable=unused-variable - """Method show search button only on inbox or sent screen.""" + """Method show search button only on inbox or sent screen""" state.searcing_text = '' if state.search_screen == 'inbox': try: @@ -1608,13 +1604,13 @@ class NavigateApp(App): return def set_identicon(self, text): - """This method is use for showing identicon in address spinner""" + """Show identicon in address spinner""" img = identiconGeneration.generate(text) self.root.children[2].children[0].ids.btn.children[1].texture = ( img.texture) def set_mail_detail_header(self): - """Method is used for setting the details of the page""" + """Setting the details of the page""" toolbar_obj = self.root.ids.toolbar toolbar_obj.left_action_items = [ ['arrow-left', lambda x: self.back_press()]] @@ -1649,15 +1645,14 @@ class NavigateApp(App): class GrashofPopup(Popup): - """Methods for saving contacts, error messages.""" + """Moule for save contacts and error messages""" - def __init__(self, **kwargs): - """Grash of pop screen settings.""" - # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + """Grash of pop screen settings""" super(GrashofPopup, self).__init__(**kwargs) def savecontact(self): - """Method is used for Saving Contacts.""" + """Method is used for saving contacts""" label = self.ids.label.text.strip() address = self.ids.address.text.strip() if label == '' and address == '': @@ -1685,7 +1680,7 @@ class GrashofPopup(Popup): # pylint: disable=attribute-defined-outside-init def show_error_message(self): - """Showing error message.""" + """Showing error message""" content = MDLabel( font_style='Body1', theme_text_color='Secondary', @@ -1705,7 +1700,7 @@ class GrashofPopup(Popup): @staticmethod def close_pop(): - """Pop is Canceled.""" + """Pop is Canceled""" toast('Canceled') def checkAddress_valid(self, instance): @@ -1730,7 +1725,7 @@ class GrashofPopup(Popup): self.ids.address.helper_text = 'This field is required' def checkLabel_valid(self, instance): - """Checking address label is unique of not""" + """Checking address label is unique or not""" entered_label = instance.text.strip() addr_labels = [labels[0] for labels in kivy_helper_search.search_sql( folder="addressbook")] @@ -1745,36 +1740,36 @@ class GrashofPopup(Popup): class AvatarSampleWidget(ILeftBody, Image): - """Avatar Sample Widget.""" + """Avatar Sample Widget""" pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): - """Left icon sample widget.""" + """Left icon sample widget""" pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): - """Right icon sample widget.""" + """Right icon sample widget""" pass class NavigationDrawerTwoLineListItem( TwoLineListItem, NavigationDrawerHeaderBase): - """Navigation Drawer in Listitems.""" + """Navigation Drawer in Listitems""" address_property = StringProperty() def __init__(self, **kwargs): - """Method for Navigation Drawer.""" + """Method for Navigation Drawer""" super(NavigationDrawerTwoLineListItem, self).__init__(**kwargs) Clock.schedule_once(lambda dt: self.setup()) def setup(self): - """Bind Controller.current_account property.""" + """Bind Controller.current_account property""" pass def on_current_account(self, account): - """Account detail.""" + """Account detail""" pass def _update_specific_text_color(self, instance, value): @@ -1785,7 +1780,7 @@ class NavigationDrawerTwoLineListItem( class MailDetail(Screen): - """MailDetail Screen uses to show the detail of mails.""" + """MailDetail Screen uses to show the detail of mails""" to_addr = StringProperty() from_addr = StringProperty() subject = StringProperty() @@ -1794,12 +1789,12 @@ class MailDetail(Screen): page_type = StringProperty() def __init__(self, *args, **kwargs): - """Mail Details method.""" + """Mail Details method""" super(MailDetail, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method MailDetail mails.""" + """Clock Schdule for method MailDetail mails""" self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent' or state.detailPageType == 'draft': data = sqlQuery( @@ -1817,7 +1812,7 @@ class MailDetail(Screen): state.kivyapp.set_mail_detail_header() def assign_mail_details(self, data): - """Assigning mail details.""" + """Assigning mail details""" self.to_addr = data[0][0] self.from_addr = data[0][1] self.subject = data[0][2].upper( @@ -1831,7 +1826,7 @@ class MailDetail(Screen): 'message': self.message} def delete_mail(self): - """Method for mail delete.""" + """Method for mail delete""" msg_count_objs = state.kivyapp.root.children[2].children[0].ids state.searcing_text = '' self.children[0].children[0].active = True @@ -1893,7 +1888,7 @@ class MailDetail(Screen): toast('Deleted') def inbox_reply(self): - """Method used for replying inbox messages.""" + """Reply inbox messages""" data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where" " msgid = ?;", str(state.mail_id)) @@ -1908,7 +1903,7 @@ class MailDetail(Screen): state.kivyapp.set_navbar_for_composer() def write_msg(self, navApp): - """Method used to write on draft mail.""" + """Write on draft mail""" state.send_draft_mail = state.mail_id composer_ids = ( self.parent.parent.parent.parent.parent.ids.sc3.children[1].ids) @@ -1923,7 +1918,7 @@ class MailDetail(Screen): @staticmethod def copy_composer_text(instance, *args): - """This method is used for copying the data from mail detail page""" + """Copy the data from mail detail page""" if len(instance.parent.text.split(':')) > 1: cpy_text = instance.parent.text.split(':')[1].strip() else: @@ -1933,22 +1928,21 @@ class MailDetail(Screen): class MyaddDetailPopup(Popup): - """MyaddDetailPopup pop is used for showing my address detail.""" + """MyaddDetailPopup pop is used for showing my address detail""" address_label = StringProperty() address = StringProperty() - def __init__(self, **kwargs): - """My Address Details screen setting.""" - # pylint: disable=useless-super-delegation + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + """My Address Details screen setting""" super(MyaddDetailPopup, self).__init__(**kwargs) def set_address(self, address, label): - """Getting address for displaying details on popup.""" + """Getting address for displaying details on popup""" self.address_label = label self.address = address def send_message_from(self): - """Method used to fill from address of composer autofield.""" + """Method used to fill from address of composer autofield""" state.kivyapp.set_navbar_for_composer() window_obj = self.parent.children[1].ids window_obj.sc3.children[1].ids.ti.text = self.address @@ -1961,27 +1955,27 @@ class MyaddDetailPopup(Popup): @staticmethod def close_pop(): - """Pop is Canceled.""" + """Pop is Canceled""" toast('Canceled') class AddbookDetailPopup(Popup): - """AddbookDetailPopup pop is used for showing my address detail.""" + """AddbookDetailPopup pop is used for showing my address detail""" address_label = StringProperty() address = StringProperty() def __init__(self, **kwargs): - """Method used set screen of address detail page.""" + """Set screen of address detail page""" # pylint: disable=useless-super-delegation super(AddbookDetailPopup, self).__init__(**kwargs) def set_addbook_data(self, address, label): - """Getting address book data for detial dipaly.""" + """Getting address book data for detial dipaly""" self.address_label = label self.address = address def update_addbook_label(self, address): - """Updating the label of address book address.""" + """Updating the label of address book address""" address_list = kivy_helper_search.search_sql(folder="addressbook") stored_labels = [labels[0] for labels in address_list] add_dict = dict(address_list) @@ -1999,7 +1993,7 @@ class AddbookDetailPopup(Popup): toast('Saved') def send_message_to(self): - """Method used to fill to_address of composer autofield.""" + """Method used to fill to_address of composer autofield""" state.kivyapp.set_navbar_for_composer() window_obj = self.parent.children[1].ids window_obj.sc3.children[1].ids.txt_input.text = self.address @@ -2012,7 +2006,7 @@ class AddbookDetailPopup(Popup): @staticmethod def close_pop(): - """Pop is Canceled.""" + """Pop is Canceled""" toast('Canceled') def checkLabel_valid(self, instance): @@ -2033,10 +2027,10 @@ class AddbookDetailPopup(Popup): class ShowQRCode(Screen): - """ShowQRCode Screen uses to show the detail of mails.""" + """ShowQRCode Screen uses to show the detail of mails""" def qrdisplay(self): - """Method used for showing QR Code.""" + """Showing QR Code""" # self.manager.parent.parent.parent.ids.search_bar.clear_widgets() self.ids.qr.clear_widgets() from kivy.garden.qrcode import QRCodeWidget @@ -2046,13 +2040,13 @@ class ShowQRCode(Screen): class Draft(Screen): - """Draft screen is used to show the list of draft messages.""" + """Draft screen is used to show the list of draft messages""" data = ListProperty() queryreturn = ListProperty() has_refreshed = True def __init__(self, *args, **kwargs): - """Method used for storing draft messages.""" + """Method used for storing draft messages""" super(Draft, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -2060,17 +2054,17 @@ class Draft(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method draft accounts.""" + """Clock Schdule for method draft accounts""" self.sentaccounts() print dt def sentaccounts(self): - """Load draft accounts.""" + """Load draft accounts""" account = state.association self.loadDraft(account, 'All', '') def loadDraft(self, account, where="", what=""): - """Load draft list for Draft messages.""" + """Load draft list for Draft messages""" xAddress = 'fromaddress' self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "draft", where, what, False) @@ -2095,7 +2089,7 @@ class Draft(Screen): self.ids.ml.add_widget(content) def set_mdList(self, first_index, last_index): - """This method is used to create mdlist""" + """Create mdlist""" data = [] for mail in self.queryreturn[first_index:last_index]: third_text = mail[3].replace('\n', ' ') @@ -2133,7 +2127,7 @@ class Draft(Screen): self.ids.ml.add_widget(carousel) def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """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 total_draft_msg = len(self.ids.ml.children) @@ -2145,11 +2139,11 @@ class Draft(Screen): pass def update_draft_screen_on_scroll(self, total_draft_msg): - """This method is used to load more data on scroll down""" + """Load more data on scroll down""" self.set_mdList(total_draft_msg, total_draft_msg + 5) def draft_detail(self, ackdata, *args): - """Method used to show draft Details.""" + """Show draft Details""" state.detailPageType = 'draft' state.mail_id = ackdata if self.manager: @@ -2161,7 +2155,7 @@ class Draft(Screen): src_mng_obj.current = 'mailDetail' def delete_draft(self, data_index, instance, *args): - """Method used to delete draft message permanently.""" + """Delete draft message permanently""" sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( data_index)) try: @@ -2178,9 +2172,8 @@ class Draft(Screen): toast('Deleted') @staticmethod - def draft_msg(src_object): - """Method used for saving draft mails.""" - # pylint: disable=too-many-locals + def draft_msg(src_object): # pylint: disable=too-many-locals + """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) @@ -2225,22 +2218,22 @@ class Draft(Screen): class CustomSpinner(Spinner): - """This class is used for setting spinner size.""" + """This class is used for setting spinner size""" def __init__(self, *args, **kwargs): - """Method used for setting size of spinner.""" + """Setting size of spinner""" super(CustomSpinner, self).__init__(*args, **kwargs) self.dropdown_cls.max_height = Window.size[1] / 3 class Allmails(Screen): - """all mails Screen uses screen to show widgets of screens.""" + """All mails Screen uses screen to show widgets of screens""" data = ListProperty() has_refreshed = True all_mails = ListProperty() def __init__(self, *args, **kwargs): - """Method Parsing the address.""" + """Method Parsing the address""" super(Allmails, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -2248,17 +2241,17 @@ class Allmails(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method all mails.""" + """Clock Schdule for method all mails""" self.mailaccounts() print dt def mailaccounts(self): - """Load all mails for account.""" + """Load all mails for account""" account = state.association self.loadMessagelist(account, 'All', '') def loadMessagelist(self, account, where="", what=""): - """Load Inbox, Sent anf Draft list of messages.""" + """Load Inbox, Sent anf Draft list of messages""" self.all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata" " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" @@ -2286,7 +2279,7 @@ class Allmails(Screen): self.ids.ml.add_widget(content) def set_mdlist(self, start_pnt, end_pnt): - """This method is used to create mdList for allmaills""" + """Create mdList for allmaills""" for item in self.all_mails[start_pnt:end_pnt]: meny = TwoLineAvatarIconListItem( text=item[1], @@ -2318,7 +2311,7 @@ class Allmails(Screen): self.ids.ml.add_widget(carousel) def check_scroll_y(self, instance, somethingelse): - """This method is used for scrolling on fixing length""" + """Scroll fixed length""" if self.ids.refresh_layout.scroll_y <= -0.00 and self.has_refreshed: self.ids.refresh_layout.scroll_y = .06 load_more = len(self.ids.ml.children) @@ -2327,8 +2320,7 @@ class Allmails(Screen): pass def updating_allmail(self, load_more): - """This method is used to update the all mail - listing value on the scroll of screen""" + """Update the all mail listing value on the scroll of screen""" if self.all_mails and load_more != len(self.all_mails): state.all_count = str(len(self.all_mails)) self.set_mdlist(load_more, load_more + 5) @@ -2336,7 +2328,7 @@ class Allmails(Screen): self.all_mails) else False def mail_detail(self, unique_id, folder, *args): - """Load sent and inbox mail details.""" + """Load sent and inbox mail details""" state.detailPageType = folder state.is_allmail = True state.mail_id = unique_id @@ -2349,7 +2341,7 @@ class Allmails(Screen): src_mng_obj.current = 'mailDetail' def swipe_delete(self, unique_id, folder, instance, *args): - """Delete inbox mail from all mail listing.""" + """Delete inbox mail from all mail listing""" if folder == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( @@ -2393,9 +2385,9 @@ class Allmails(Screen): # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): """Method updates the state of application, - While the spinner remains on the screen.""" + While the spinner remains on the screen""" def refresh_callback(interval): - """Method used for loading the allmails screen data.""" + """Load the allmails screen data""" self.ids.ml.clear_widgets() self.remove_widget(self.children[1]) try: @@ -2427,17 +2419,17 @@ def avatarImageFirstLetter(letter_string): class Starred(Screen): - """Starred Screen show widgets of page.""" + """Starred Screen show widgets of page""" pass class Archieve(Screen): - """Archieve Screen show widgets of page.""" + """Archieve Screen show widgets of page""" pass class Spam(Screen): - """Spam Screen show widgets of page.""" + """Spam Screen show widgets of page""" pass From 73f649b9a018d07b8d4cd7b229233db28c05126c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 30 Nov 2019 19:23:41 +0530 Subject: [PATCH 249/306] fixes after pull --- src/bitmessagekivy/mpybit.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 1a8dabac..f14280ec 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -834,7 +834,9 @@ class Random(Screen): for obj in BMConfigParser().addresses()] if entered_label in lables: self.ids.label.error = True - self.ids.label.helper_text = 'Label name is already exist you can try this Ex. ( {0}_1, {0}_2 )'.format(entered_label) + self.ids.label.helper_text = 'Label name is already exist you'\ + ' can try this Ex. ( {0}_1, {0}_2 )'.format( + entered_label) elif entered_label: self.ids.label.error = False else: @@ -842,6 +844,7 @@ class Random(Screen): self.ids.label.helper_text = 'This field is required' def reset_address_label(self): + """Resetting address labels""" self.ids.label.text = '' @@ -1162,7 +1165,7 @@ class Trash(Screen): def delete_confirmation(self): """Show confirmation delete popup""" delete_msg_dialog = MDDialog( - text='Are you sure you want to delete this' / + text='Are you sure you want to delete this' ' message permanently from trash?', title='', size_hint=(.8, .25), From 3fc7414a609637259c7760e02ebc74fef6f7f4c1 Mon Sep 17 00:00:00 2001 From: navjot Date: Wed, 4 Dec 2019 21:15:45 +0530 Subject: [PATCH 250/306] worked on optimizing sql query for all screens --- src/bitmessagekivy/kivy_helper_search.py | 8 +- src/bitmessagekivy/mpybit.py | 355 +++++++++++++---------- 2 files changed, 203 insertions(+), 160 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 390d6fbd..829d4f00 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -4,7 +4,7 @@ Sql queries for bitmessagekivy from helper_sql import sqlQuery -def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False): +def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False, start_indx=0, end_indx=20): """Method helping for searching mails""" # pylint: disable=too-many-arguments, too-many-branches if what is not None and what != "": @@ -59,7 +59,9 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if sqlStatementParts: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent" or folder == "draft": - sqlStatementBase += " ORDER BY lastactiontime DESC" + sqlStatementBase += " ORDER BY lastactiontime DESC limit {0}, {1}".format(start_indx, end_indx) elif folder == "inbox": - sqlStatementBase += " ORDER BY received DESC" + sqlStatementBase += " ORDER BY received DESC limit {0}, {1}".format(start_indx, end_indx) + elif folder == "addressbook": + sqlStatementBase += " limit {0}, {1}".format(start_indx, end_indx) return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index f14280ec..a2c10f0e 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -80,44 +80,43 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): - """Inbox Screen uses screen to show widgets of screens""" + """Inbox Screen uses screen to show widgets of screens.""" queryreturn = ListProperty() has_refreshed = True + account = StringProperty() def __init__(self, *args, **kwargs): - """Method Parsing the address""" + """Method Parsing the address.""" super(Inbox, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def set_defaultAddress(self): + """This method set default address""" if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock schdule for method inbox accounts""" - self.inboxaccounts() - print dt + """Clock schdule for method inbox accounts.""" + self.loadMessagelist() - def inboxaccounts(self): - """Load all inbox accounts""" - account = state.association - self.loadMessagelist(account, 'All', '') - - def loadMessagelist(self, account, where="", what=""): - """Load inbox list for inbox messages""" + def loadMessagelist(self, where="", what=""): + """Load Inbox list for Inbox messages.""" # pylint: disable=too-many-locals + self.set_defaultAddress() + self.account = state.association if state.searcing_text: self.children[2].children[0].children[0].scroll_y = 1.0 where = ['subject', 'message'] what = state.searcing_text xAddress = 'toaddress' data = [] - self.queryreturn = kivy_helper_search.search_sql( - xAddress, account, "inbox", where, what, False) + self.inboxDataQuery(xAddress, where, what) if self.queryreturn: + state.kivyapp.get_inbox_count() src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.inbox_cnt.badge_text = str(len(self.queryreturn)) - state.inbox_count = str(len(self.queryreturn)) - for mail in self.queryreturn[:20]: + src_mng_obj.inbox_cnt.badge_text = state.inbox_count + for mail in self.queryreturn: # third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), @@ -141,8 +140,14 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) + def inboxDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This method used for retrieving inbox data""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, self.account, "inbox", where, what, False, start_indx, end_indx) + def set_mdList(self, data): """This method is used to create the mdList""" + total_message = len(self.ids.ml.children) for item in data: meny = TwoLineAvatarIconListItem( text=item['text'], @@ -179,6 +184,8 @@ class Inbox(Screen): carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) + update_message = len(self.ids.ml.children) + self.has_refreshed = True if total_message != update_message else False def check_scroll_y(self, instance, somethingelse): """This method is used to load data on scroll""" @@ -186,17 +193,19 @@ class Inbox(Screen): 0].scroll_y <= -0.0 and self.has_refreshed: self.children[2].children[0].children[0].scroll_y = 0.06 total_message = len(self.ids.ml.children) - if total_message != len(self.queryreturn): - self.update_inbox_screen_on_scroll(total_message) - self.has_refreshed = True if total_message != len( - self.queryreturn) else False + self.update_inbox_screen_on_scroll(total_message) else: pass - def update_inbox_screen_on_scroll(self, total_message): + def update_inbox_screen_on_scroll(self, total_message, where="", what=""): """This method is used to load more data on scroll down""" data = [] - for mail in self.queryreturn[total_message:total_message + 5]: + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text + self.inboxDataQuery('toaddress', where, what, total_message, 5) + for mail in self.queryreturn: + # third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), 'secondary_text': mail[5][:50] + '........' if len( @@ -286,17 +295,18 @@ class Inbox(Screen): class MyAddress(Screen): - """MyAddress screen uses screen to show widgets of screens""" + """MyAddress screen uses screen to show widgets of screens.""" addresses_list = ListProperty() has_refreshed = True + is_add_created = False def __init__(self, *args, **kwargs): - """Clock schdule for method inbox accounts""" + """Clock schdule for method Myaddress accounts.""" super(MyAddress, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock schdule for method inbox accounts""" + """Clock schdule for method Myaddress accounts""" # pylint: disable=unnecessary-lambda, deprecated-lambda self.addresses_list = state.kivyapp.variable_1 if state.searcing_text: @@ -321,7 +331,7 @@ class MyAddress(Screen): size_hint_y=None, valign='top') self.ids.ml.add_widget(content) - if not state.searcing_text: + if not state.searcing_text and not self.is_add_created: try: self.manager.current = 'login' except Exception: @@ -768,7 +778,7 @@ class NetworkStat(Screen): Clock.schedule_interval(self.init_ui, 1) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts""" + """Clock Schdule for method networkstat screen""" import network.stats import shared from network import objectracker @@ -823,8 +833,8 @@ class Random(Screen): """New address created""" state.kivyapp.root.ids.sc10.children[1].active = 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.manager.current = 'myaddress' toast('New address created') def add_validation(self, instance): @@ -852,9 +862,10 @@ class Sent(Screen): """Sent Screen uses screen to show widgets of screens""" queryreturn = ListProperty() has_refreshed = True + account = StringProperty() def __init__(self, *args, **kwargs): - """Association with the screen""" + """Association with the screen.""" super(Sent, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -867,32 +878,22 @@ class Sent(Screen): print dt def sentaccounts(self): - """Load sent accounts""" - account = state.association - self.loadSent(account, 'All', '') + """Load sent accounts.""" + self.account = state.association + self.loadSent() - def loadSent(self, account, where="", what=""): - """Load Sent list for Sent messages""" + def loadSent(self, where="", what=""): + """Load Sent list for Sent messages.""" if state.searcing_text: self.ids.scroll_y.scroll_y = 1.0 where = ['subject', 'message'] what = state.searcing_text xAddress = 'fromaddress' data = [] - self.queryreturn = kivy_helper_search.search_sql( - xAddress, account, "sent", where, what, False) - if state.msg_counter_objs and state.association == ( - state.check_sent_acc): - state.msg_counter_objs.send_cnt.badge_text = str( - len(self.queryreturn)) - state.sent_count = str(int(state.sent_count) + 1) - state.all_count = str(int(state.all_count) + 1) - state.msg_counter_objs.allmail_cnt.badge_text = state.all_count - state.check_sent_acc = None - + self.sentDataQuery(xAddress, where, what) if self.queryreturn: - self.set_sentCount(len(self.queryreturn)) - for mail in self.queryreturn[0:20]: + self.set_sentCount(state.sent_count) + for mail in self.queryreturn: data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( @@ -914,8 +915,14 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) - def set_mdlist(self, data, set_index): + def sentDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This method is used to retrieving data from sent table""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, self.account, "sent", where, what, False, start_indx, end_indx) + + 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: meny = TwoLineAvatarIconListItem( text=item['text'], @@ -947,20 +954,24 @@ class Sent(Screen): carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel, 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""" if len(self.ids.ml.children) < 3: + self.account = state.association self.ids.ml.clear_widgets() - self.loadSent(state.association) + self.loadSent() + total_sent = int(state.sent_count) + 1 + self.set_sentCount(total_sent) else: account = state.association data = [] - self.queryreturn = kivy_helper_search.search_sql( - 'fromaddress', account, "sent", '', '', False) - total_sent = len(self.queryreturn) + self.sentDataQuery('fromaddress', '', '', 0, 1) + total_sent = int(state.sent_count) + 1 self.set_sentCount(total_sent) - for mail in self.queryreturn[:1]: + for mail in self.queryreturn: data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( @@ -968,23 +979,29 @@ class Sent(Screen): '\n', ''))[0:50] + '........', 'ackdata': mail[5]}) self.set_mdlist(data, total_sent - 1) + if state.msg_counter_objs and state.association == ( + state.check_sent_acc): + state.all_count = str(int(state.all_count) + 1) + state.msg_counter_objs.allmail_cnt.badge_text = state.all_count + state.check_sent_acc = None def check_scroll_y(self, instance, somethingelse): """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 total_sent_msg = len(self.ids.ml.children) - if total_sent_msg != len(self.queryreturn): - self.update_sent_screen_on_scroll(total_sent_msg) - self.has_refreshed = True if total_sent_msg != len( - self.queryreturn) else False + self.update_sent_screen_on_scroll(total_sent_msg) else: pass - def update_sent_screen_on_scroll(self, total_sent_msg): - """Load more data on scroll down""" + def update_sent_screen_on_scroll(self, total_sent_msg, where="", what=""): + """This method is used to load more data on scroll down""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text + self.sentDataQuery('fromaddress', where, what, total_sent_msg, 5) data = [] - for mail in self.queryreturn[total_sent_msg:total_sent_msg + 5]: + for mail in self.queryreturn: data.append({ 'text': mail[1].strip(), 'secondary_text': mail[2][:50] + '........' if len( @@ -1072,25 +1089,15 @@ class Trash(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts""" + """Clock Schdule for method trash screen.""" if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message," - " folder ||',' || 'sent' as folder, ackdata As id," - " DATE(lastactiontime) As actionTime FROM sent" - " WHERE folder = 'trash' and fromaddress = '{0}' UNION" - " SELECT toaddress, fromaddress, subject, message," - " folder ||',' || 'inbox' as folder, msgid As id," - " DATE(received) As actionTime FROM inbox WHERE" - " folder = 'trash' and toaddress = '{0}'" - " ORDER BY actionTime DESC".format(state.association)) + self.trashDataQuery(0, 20) if self.trash_messages: src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.trash_cnt.badge_text = str(len(self.trash_messages)) - state.trash_count = str(len(self.trash_messages)) - self.set_mdList(0, 20) + src_mng_obj.trash_cnt.badge_text = state.trash_count + self.set_mdList() self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -1103,9 +1110,17 @@ class Trash(Screen): valign='top') self.ids.ml.add_widget(content) - def set_mdList(self, first_index, last_index): - """Creating the mdlist""" - for item in self.trash_messages[first_index:last_index]: + def trashDataQuery(self, start_indx, end_indx): + self.trash_messages = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder ||',' || 'sent' as folder, ackdata As id, DATE(lastactiontime)" + " As actionTime FROM sent WHERE folder = 'trash' and fromaddress = '{0}' UNION" + " SELECT toaddress, fromaddress, subject, message, folder ||',' || 'inbox' as folder, msgid As id, DATE(received) As" + " actionTime FROM inbox WHERE folder = 'trash' and toaddress = '{0}' ORDER BY actionTime DESC limit {1}, {2}".format(state.association, start_indx, end_indx)) + + def set_mdList(self): + """This method is used to create the mdlist""" + total_trash_msg = len(self.ids.ml.children) + for item in self.trash_messages: meny = TwoLineAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( @@ -1132,22 +1147,22 @@ class Trash(Screen): carousel.add_widget(meny) carousel.index = 1 self.ids.ml.add_widget(carousel) + self.has_refreshed = True if total_trash_msg != len( + self.ids.ml.children) else False def check_scroll_y(self, instance, somethingelse): """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 total_trash_msg = len(self.ids.ml.children) - if total_trash_msg != len(self.trash_messages): - self.update_trash_screen_on_scroll(total_trash_msg) - self.has_refreshed = True if total_trash_msg != len( - self.trash_messages) else False + self.update_trash_screen_on_scroll(total_trash_msg) else: pass def update_trash_screen_on_scroll(self, total_trash_msg): """Load more data on scroll down""" - self.set_mdList(total_trash_msg, total_trash_msg + 5) + self.trashDataQuery(total_trash_msg, 5) + self.set_mdList() def delete_permanently(self, data_index, folder, instance, *args): """Deleting trash mail permanently""" @@ -1307,33 +1322,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' - msg_counter_objs = ( - self.root_window.children[2].children[2].children[0].ids) - state.sent_count = str( - sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" - " folder = 'sent' ;".format(state.association))[0][0]) - state.inbox_count = str( - sqlQuery( - "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" - " folder = 'inbox' ;".format(state.association))[0][0]) - state.trash_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent" - " where fromaddress = '{0}' and folder = 'trash' )" - "+(SELECT count(*) FROM inbox where toaddress = '{0}' and" - " folder = 'trash') AS SumCount".format(state.association))[0][0]) - state.draft_count = str( - sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" - " folder = 'draft' ;".format(state.association))[0][0]) - state.all_count = str(int(state.sent_count) + int(state.inbox_count)) - - if msg_counter_objs: - msg_counter_objs.send_cnt.badge_text = state.sent_count - msg_counter_objs.inbox_cnt.badge_text = state.inbox_count - msg_counter_objs.trash_cnt.badge_text = state.trash_count - msg_counter_objs.draft_cnt.badge_text = state.draft_count - msg_counter_objs.allmail_cnt.badge_text = state.all_count + self.set_message_count() @staticmethod def getCurrentAccount(): @@ -1525,6 +1514,48 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods state.detailPageType = '' state.in_composer = False + def get_inbox_count(self): + state.inbox_count = str( + sqlQuery( + "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" + " folder = 'inbox' ;".format(state.association))[0][0]) + + def get_sent_count(self): + state.sent_count = str( + sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'sent' ;".format(state.association))[0][0]) + + def set_message_count(self): + try: + msg_counter_objs = ( + self.root_window.children[0].children[2].children[0].ids) + except Exception as e: + msg_counter_objs = ( + self.root_window.children[2].children[2].children[0].ids) + self.get_inbox_count() + self.get_sent_count() + state.trash_count = str(sqlQuery( + "SELECT (SELECT count(*) FROM sent" + " where fromaddress = '{0}' and folder = 'trash' )" + "+(SELECT count(*) FROM inbox where toaddress = '{0}' and" + " folder = 'trash') AS SumCount".format(state.association))[0][0]) + state.draft_count = str( + sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'draft' ;".format(state.association))[0][0]) + state.all_count = str(int(state.sent_count) + int(state.inbox_count)) + + if msg_counter_objs: + msg_counter_objs.send_cnt.badge_text = state.sent_count + msg_counter_objs.inbox_cnt.badge_text = state.inbox_count + msg_counter_objs.trash_cnt.badge_text = state.trash_count + msg_counter_objs.draft_cnt.badge_text = state.draft_count + msg_counter_objs.allmail_cnt.badge_text = state.all_count + + def on_start(self): + self.set_message_count() + @staticmethod def on_stop(): """On stop methos is used for stoping the runing script""" @@ -2045,6 +2076,7 @@ class ShowQRCode(Screen): class Draft(Screen): """Draft screen is used to show the list of draft messages""" data = ListProperty() + account = StringProperty() queryreturn = ListProperty() has_refreshed = True @@ -2062,23 +2094,21 @@ class Draft(Screen): print dt def sentaccounts(self): - """Load draft accounts""" - account = state.association - self.loadDraft(account, 'All', '') + """Load draft accounts.""" + self.account = state.association + self.loadDraft() - def loadDraft(self, account, where="", what=""): - """Load draft list for Draft messages""" + def loadDraft(self, where="", what=""): + """Load draft list for Draft messages.""" xAddress = 'fromaddress' - self.queryreturn = kivy_helper_search.search_sql( - xAddress, account, "draft", where, what, False) + self.draftDataQuery(xAddress, where, what) if state.msg_counter_objs: state.msg_counter_objs.draft_cnt.badge_text = str( len(self.queryreturn)) if self.queryreturn: src_mng_obj = state.kivyapp.root.children[2].children[0].ids - src_mng_obj.draft_cnt.badge_text = str(len(self.queryreturn)) - state.draft_count = str(len(self.queryreturn)) - self.set_mdList(0, 20) + src_mng_obj.draft_cnt.badge_text = state.draft_count + self.set_mdList() self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -2091,10 +2121,16 @@ class Draft(Screen): valign='top') self.ids.ml.add_widget(content) - def set_mdList(self, first_index, last_index): - """Create mdlist""" + def draftDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This methosd is for retrieving draft messages""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, self.account, "draft", where, what, False, start_indx, end_indx) + + def set_mdList(self): + """This method is used to create mdlist""" data = [] - for mail in self.queryreturn[first_index:last_index]: + 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(), @@ -2128,22 +2164,22 @@ class Draft(Screen): carousel.add_widget(meny) carousel.index = 1 self.ids.ml.add_widget(carousel) + updated_msg = len(self.ids.ml.children) + self.has_refreshed = True if total_draft_msg != updated_msg else False def check_scroll_y(self, instance, somethingelse): """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 total_draft_msg = len(self.ids.ml.children) - if total_draft_msg != len(self.queryreturn): - self.update_draft_screen_on_scroll(total_draft_msg) - self.has_refreshed = True if total_draft_msg != len( - self.queryreturn) else False + self.update_draft_screen_on_scroll(total_draft_msg) else: pass - def update_draft_screen_on_scroll(self, total_draft_msg): + def update_draft_screen_on_scroll(self, total_draft_msg, where='', what=''): """Load more data on scroll down""" - self.set_mdList(total_draft_msg, total_draft_msg + 5) + self.draftDataQuery('fromaddress', where, what, total_draft_msg, 5) + self.set_mdList() def draft_detail(self, ackdata, *args): """Show draft Details""" @@ -2234,9 +2270,10 @@ class Allmails(Screen): data = ListProperty() has_refreshed = True all_mails = ListProperty() + account = StringProperty() def __init__(self, *args, **kwargs): - """Method Parsing the address""" + """Method Parsing the address.""" super(Allmails, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -2249,26 +2286,20 @@ class Allmails(Screen): print dt def mailaccounts(self): - """Load all mails for account""" - account = state.association - self.loadMessagelist(account, 'All', '') + """Load all mails for account.""" + self.account = state.association + self.loadMessagelist() - def loadMessagelist(self, account, where="", what=""): - """Load Inbox, Sent anf Draft list of messages""" - self.all_mails = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata" - " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" - " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress," - " fromaddress, subject, message, folder, msgid As id," - " DATE(received) As actionTime FROM inbox WHERE" - " folder = 'inbox' and toaddress = '{0}'" - " ORDER BY actionTime DESC".format(account)) + def loadMessagelist(self): + """Load Inbox, Sent anf Draft list of messages.""" + self.allMessageQuery(0, 20) if self.all_mails: + state.kivyapp.get_inbox_count() + state.kivyapp.get_sent_count() + state.all_count = str(int(state.sent_count) + int(state.inbox_count)) state.kivyapp.root.children[2].children[ - 0].ids.allmail_cnt.badge_text = str( - len(self.all_mails)) - state.all_count = str(len(self.all_mails)) - self.set_mdlist(0, 20) + 0].ids.allmail_cnt.badge_text = state.all_count + self.set_mdlist() self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( @@ -2281,9 +2312,19 @@ class Allmails(Screen): valign='top') self.ids.ml.add_widget(content) - def set_mdlist(self, start_pnt, end_pnt): - """Create mdList for allmaills""" - for item in self.all_mails[start_pnt:end_pnt]: + def allMessageQuery(self, start_indx, end_indx): + """This method is used for retrieving data from inbox or sent both tables""" + self.all_mails = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder, ackdata" + " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" + " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress, fromaddress, subject," + " message, folder, msgid As id, DATE(received) As actionTime" + " FROM inbox WHERE folder = 'inbox' and toaddress = '{0}' ORDER BY actionTime DESC limit {1}, {2}".format(self.account, start_indx, end_indx)) + + 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: meny = TwoLineAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( @@ -2312,6 +2353,8 @@ class Allmails(Screen): carousel.add_widget(meny) carousel.index = 1 self.ids.ml.add_widget(carousel) + updated_data = len(self.ids.ml.children) + self.has_refreshed = True if data_exist != updated_data else False def check_scroll_y(self, instance, somethingelse): """Scroll fixed length""" @@ -2323,12 +2366,10 @@ class Allmails(Screen): pass def updating_allmail(self, load_more): - """Update the all mail listing value on the scroll of screen""" - if self.all_mails and load_more != len(self.all_mails): - state.all_count = str(len(self.all_mails)) - self.set_mdlist(load_more, load_more + 5) - self.has_refreshed = True if load_more != len( - self.all_mails) else False + """This method is used to update the all mail + listing value on the scroll of screen""" + self.allMessageQuery(load_more, 5) + self.set_mdlist() def mail_detail(self, unique_id, folder, *args): """Load sent and inbox mail details""" From 516f0a26adf480f9e32e160cdc40663a6a2840dd Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 5 Dec 2019 19:06:33 +0530 Subject: [PATCH 251/306] mpybit fixes --- src/bitmessagekivy/mpybit.py | 85 +++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a2c10f0e..3f5445c2 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -90,7 +90,8 @@ class Inbox(Screen): super(Inbox, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) - def set_defaultAddress(self): + @staticmethod + def set_defaultAddress(): """This method set default address""" if state.association == '': if BMConfigParser().addresses(): @@ -140,10 +141,18 @@ class Inbox(Screen): valign='top') self.ids.ml.add_widget(content) + # pylint: disable=too-many-arguments def inboxDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This method used for retrieving inbox data""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, self.account, "inbox", where, what, False, start_indx, end_indx) + xAddress, + self.account, + "inbox", + where, + what, + False, + start_indx, + end_indx) def set_mdList(self, data): """This method is used to create the mdList""" @@ -402,7 +411,8 @@ class MyAddress(Screen): # if filter(lambda x: (state.searcing_text).lower() in x, [ # BMConfigParser().get( # address, 'label').lower(), address.lower()]): - if [x for x in [BMConfigParser().get(address, 'label').lower(), address.lower()]]: + if [x for x in [BMConfigParser().get( + address, 'label').lower(), address.lower()]]: return True return False @@ -829,7 +839,8 @@ class Random(Screen): self.manager.current = 'myaddress' Clock.schedule_once(self.address_created_callback, 6) - def address_created_callback(self, dt=0): + @staticmethod + def address_created_callback(dt=0): """New address created""" state.kivyapp.root.ids.sc10.children[1].active = False state.kivyapp.root.ids.sc10.ids.ml.clear_widgets() @@ -915,10 +926,18 @@ class Sent(Screen): valign='top') self.ids.ml.add_widget(content) + # pylint: disable=too-many-arguments def sentDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This method is used to retrieving data from sent table""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, self.account, "sent", where, what, False, start_indx, end_indx) + xAddress, + self.account, + "sent", + where, + what, + False, + start_indx, + end_indx) def set_mdlist(self, data, set_index=0): """This method is used to create the mdList""" @@ -959,14 +978,13 @@ class Sent(Screen): def update_sent_messagelist(self): """This method is used to update screen when new mail is sent""" + self.account = state.association if len(self.ids.ml.children) < 3: - self.account = state.association self.ids.ml.clear_widgets() self.loadSent() total_sent = int(state.sent_count) + 1 self.set_sentCount(total_sent) else: - account = state.association data = [] self.sentDataQuery('fromaddress', '', '', 0, 1) total_sent = int(state.sent_count) + 1 @@ -1111,11 +1129,18 @@ class Trash(Screen): self.ids.ml.add_widget(content) def trashDataQuery(self, start_indx, end_indx): + """Trash message query""" self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder ||',' || 'sent' as folder, ackdata As id, DATE(lastactiontime)" - " As actionTime FROM sent WHERE folder = 'trash' and fromaddress = '{0}' UNION" - " SELECT toaddress, fromaddress, subject, message, folder ||',' || 'inbox' as folder, msgid As id, DATE(received) As" - " actionTime FROM inbox WHERE folder = 'trash' and toaddress = '{0}' ORDER BY actionTime DESC limit {1}, {2}".format(state.association, start_indx, end_indx)) + "SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'sent' as folder, ackdata As" + " id, DATE(lastactiontime) As actionTime FROM sent" + " WHERE folder = 'trash' and fromaddress = '{0}' UNION" + " SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'inbox' as folder, msgid As id," + " DATE(received) As actionTime FROM inbox" + " WHERE folder = 'trash' and toaddress = '{0}'" + " ORDER BY actionTime DESC limit {1}, {2}".format( + state.association, start_indx, end_indx)) def set_mdList(self): """This method is used to create the mdlist""" @@ -1148,7 +1173,7 @@ class Trash(Screen): carousel.index = 1 self.ids.ml.add_widget(carousel) self.has_refreshed = True if total_trash_msg != len( - self.ids.ml.children) else False + self.ids.ml.children) else False def check_scroll_y(self, instance, somethingelse): """Load data on scroll""" @@ -1220,6 +1245,7 @@ class Page(Screen): class Create(Screen): """Creates the screen widgets""" + def __init__(self, **kwargs): """Getting Labels and address from addressbook""" super(Create, self).__init__(**kwargs) @@ -1514,23 +1540,28 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods state.detailPageType = '' state.in_composer = False - def get_inbox_count(self): + @staticmethod + def get_inbox_count(): + """Getting inbox count""" state.inbox_count = str( sqlQuery( "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" " folder = 'inbox' ;".format(state.association))[0][0]) - def get_sent_count(self): + @staticmethod + def get_sent_count(): + """Getting sent count""" state.sent_count = str( sqlQuery( "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" " folder = 'sent' ;".format(state.association))[0][0]) def set_message_count(self): + """Setting message count""" try: msg_counter_objs = ( self.root_window.children[0].children[2].children[0].ids) - except Exception as e: + except Exception: msg_counter_objs = ( self.root_window.children[2].children[2].children[0].ids) self.get_inbox_count() @@ -2121,10 +2152,18 @@ class Draft(Screen): valign='top') self.ids.ml.add_widget(content) + # pylint: disable=too-many-arguments def draftDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This methosd is for retrieving draft messages""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, self.account, "draft", where, what, False, start_indx, end_indx) + xAddress, + self.account, + "draft", + where, + what, + False, + start_indx, + end_indx) def set_mdList(self): """This method is used to create mdlist""" @@ -2296,7 +2335,8 @@ class Allmails(Screen): if self.all_mails: state.kivyapp.get_inbox_count() state.kivyapp.get_sent_count() - state.all_count = str(int(state.sent_count) + int(state.inbox_count)) + state.all_count = str( + int(state.sent_count) + int(state.inbox_count)) state.kivyapp.root.children[2].children[ 0].ids.allmail_cnt.badge_text = state.all_count self.set_mdlist() @@ -2313,13 +2353,16 @@ class Allmails(Screen): self.ids.ml.add_widget(content) def allMessageQuery(self, start_indx, end_indx): - """This method is used for retrieving data from inbox or sent both tables""" + """Retrieving data from inbox or sent both tables""" self.all_mails = sqlQuery( "SELECT toaddress, fromaddress, subject, message, folder, ackdata" " As id, DATE(lastactiontime) As actionTime FROM sent WHERE" - " folder = 'sent' and fromaddress = '{0}' UNION SELECT toaddress, fromaddress, subject," - " message, folder, msgid As id, DATE(received) As actionTime" - " FROM inbox WHERE folder = 'inbox' and toaddress = '{0}' ORDER BY actionTime DESC limit {1}, {2}".format(self.account, start_indx, end_indx)) + " folder = 'sent' and fromaddress = '{0}'" + " UNION SELECT toaddress, fromaddress, subject, message, folder," + " msgid As id, DATE(received) As actionTime FROM inbox" + " WHERE folder = 'inbox' and toaddress = '{0}'" + " ORDER BY actionTime DESC limit {1}, {2}".format( + self.account, start_indx, end_indx)) def set_mdlist(self): """This method is used to create mdList for allmaills""" From e458de733e6c2c3c6fb9345f227f9bdeab354343 Mon Sep 17 00:00:00 2001 From: navjot Date: Tue, 10 Dec 2019 17:02:18 +0530 Subject: [PATCH 252/306] worked on addressbook address validation --- src/bitmessagekivy/kivy_helper_search.py | 4 +- src/bitmessagekivy/main.kv | 41 ++++++--- src/bitmessagekivy/mpybit.py | 108 +++++++++++++++++------ 3 files changed, 110 insertions(+), 43 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 829d4f00..48e77cb2 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -62,6 +62,6 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase += " ORDER BY lastactiontime DESC limit {0}, {1}".format(start_indx, end_indx) elif folder == "inbox": sqlStatementBase += " ORDER BY received DESC limit {0}, {1}".format(start_indx, end_indx) - elif folder == "addressbook": - sqlStatementBase += " limit {0}, {1}".format(start_indx, end_indx) + # elif folder == "addressbook": + # sqlStatementBase += " limit {0}, {1}".format(start_indx, end_indx) return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1c2e3c6a..6b6cde88 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -99,6 +99,7 @@ icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'allmails' badge_text: "0" + on_press: app.load_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -203,11 +204,18 @@ NavigationLayout: orientation: 'vertical' spacing: dp(10) SearchBar: - FloatLayout: - MDScrollViewRefreshLayout: - id: refresh_layout - refresh_callback: root.refresh_callback - root_layout: root.set_root_layout() + #FloatLayout: + # MDScrollViewRefreshLayout: + # id: refresh_layout + # refresh_callback: root.refresh_callback + # root_layout: root.set_root_layout() + # MDList: + # id: ml + BoxLayout: + orientation:'vertical' + ScrollView: + id: scroll_y + do_scroll_x: False MDList: id: ml Loader: @@ -273,13 +281,21 @@ NavigationLayout: : name: 'allmails' - FloatLayout: - MDScrollViewRefreshLayout: - id: refresh_layout - refresh_callback: root.refresh_callback - root_layout: root.set_root_layout() + #FloatLayout: + # MDScrollViewRefreshLayout: + # id: refresh_layout + # refresh_callback: root.refresh_callback + # root_layout: root.set_root_layout() + # MDList: + # id: ml + BoxLayout: + orientation:'vertical' + ScrollView: + id: scroll_y + do_scroll_x: False MDList: id: ml + Loader: ComposerButton: : @@ -366,7 +382,8 @@ NavigationLayout: size_hint_y: None font_size: '13sp' height: self.parent.height/2 - hint_text: 'type or search recipients address starting with BM-' + #hint_text: 'type or search recipients address starting with BM-' + hint_text: 'type, select or scan QR code for recipients address' RV: id: rv MDTextField: @@ -648,7 +665,7 @@ NavigationLayout: do_scroll_x: False BoxLayout: orientation: 'vertical' - padding: [dp(app.window_size[0]/16 if app.window_size[0] <= 720 else app.window_size[0]/4*1.1), dp(10)] + padding: [dp(app.window_size[0]/16 if app.window_size[0] <= 720 else app.window_size[0]/4*1.1 if app.window_size[0] <= 800 else app.window_size[0]/18), dp(10)] spacing: 12 size_hint_y: None height: self.minimum_height + dp(app.window_size[1]) if app.window_size[1] > app.window_size[0] else dp(app.window_size[0]) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 3f5445c2..5fc561da 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -62,6 +62,7 @@ import state from uikivysignaler import UIkivySignaler import identiconGeneration +from addresses import addBMIfNotPresent, decodeAddress, encodeVarint def toast(text): @@ -298,9 +299,9 @@ class Inbox(Screen): Clock.schedule_once(refresh_callback, 1) - def set_root_layout(self): - """Setting root layout""" - return self.parent.parent.parent + # def set_root_layout(self): + # """Setting root layout""" + # return self.parent.parent.parent class MyAddress(Screen): @@ -652,8 +653,8 @@ class DropDownWidget(BoxLayout): # self.parent.parent.screens[0].ids.ml.clear_widgets() # self.parent.parent.screens[0].loadMessagelist(state.association) self.parent.parent.screens[3].update_sent_messagelist() - self.parent.parent.screens[16].clear_widgets() - self.parent.parent.screens[16].add_widget(Allmails()) + # self.parent.parent.screens[16].clear_widgets() + # self.parent.parent.screens[16].add_widget(Allmails()) Clock.schedule_once(self.callback_for_msgsend, 3) queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" @@ -1331,6 +1332,11 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods state.association = text state.searcing_text = '' LoadingPopup().open() + self.set_message_count() + Clock.schedule_once(self.setCurrentAccountData, 0.5) + + 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) @@ -1348,7 +1354,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' - self.set_message_count() @staticmethod def getCurrentAccount(): @@ -1699,18 +1704,32 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods if instance.text == 'Inbox': self.root.ids.scr_mngr.current = 'inbox' self.root.ids.sc1.children[1].active = True - self.root.ids.sc1.ids.ml.clear_widgets() - Clock.schedule_once(partial(self.load_screen_callback, instance), 0.5) + elif instance.text == 'All Mails': + self.root.ids.scr_mngr.current = 'allmails' + try: + self.root.ids.sc17.children[1].active = True + except Exception as e: + self.root.ids.sc17.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 as e: + self.root.ids.sc17.children[0].children[1].active = False class GrashofPopup(Popup): """Moule for save contacts and error messages""" + valid = False def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """Grash of pop screen settings""" @@ -1733,7 +1752,7 @@ class GrashofPopup(Popup): stored_labels = [labels[0] for labels in kivy_helper_search.search_sql( folder="addressbook")] if label and address and address not in stored_address \ - and label not in stored_labels: + and label not in stored_labels and self.valid: # state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() @@ -1779,12 +1798,17 @@ class GrashofPopup(Popup): text = 'Address is already in the addressbook.' elif entered_text in my_addresses: text = 'You can not save your own address.' + elif entered_text: + text = self.addressChanged(entered_text) if entered_text in my_addresses or entered_text in add_book: self.ids.address.error = True self.ids.address.helper_text = text - elif entered_text: + elif entered_text and self.valid: self.ids.address.error = False + elif entered_text: + self.ids.address.error = True + self.ids.address.helper_text = text else: self.ids.address.error = False self.ids.address.helper_text = 'This field is required' @@ -1803,6 +1827,33 @@ class GrashofPopup(Popup): self.ids.label.error = False self.ids.label.helper_text = 'This field is required' + def _onSuccess(self, addressVersion, streamNumber, ripe): + pass + + def addressChanged(self, addr): + """Address validation callback, performs validation and gives feedback""" + status, addressVersion, streamNumber, ripe = decodeAddress( + str(addr)) + self.valid = status == 'success' + if self.valid: + text = "Address is valid." + self._onSuccess(addressVersion, streamNumber, ripe) + elif status == 'missingbm': + text = "The address should start with ''BM-''" + elif status == 'checksumfailed': + text = "The address is not typed or copied correctly(the checksum failed)." + elif status == 'versiontoohigh': + text = "The version number of this address is higher than this software can support. Please upgrade Bitmessage." + elif status == 'invalidcharacters': + text = "The address contains invalid characters." + elif status == 'ripetooshort': + text = "Some data encoded in the address is too short." + elif status == 'ripetoolong': + text = "Some data encoded in the address is too long." + elif status == 'varintmalformed': + text = "Some data encoded in the address is malformed." + return text + class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget""" @@ -2321,16 +2372,12 @@ class Allmails(Screen): def init_ui(self, dt=0): """Clock Schdule for method all mails""" - self.mailaccounts() - print dt - - def mailaccounts(self): - """Load all mails for account.""" - self.account = state.association self.loadMessagelist() + print dt def loadMessagelist(self): """Load Inbox, Sent anf Draft list of messages.""" + self.account = state.association self.allMessageQuery(0, 20) if self.all_mails: state.kivyapp.get_inbox_count() @@ -2340,7 +2387,8 @@ class Allmails(Screen): state.kivyapp.root.children[2].children[ 0].ids.allmail_cnt.badge_text = state.all_count self.set_mdlist() - self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + # self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( font_style='Body1', @@ -2401,8 +2449,8 @@ class Allmails(Screen): def check_scroll_y(self, instance, somethingelse): """Scroll fixed length""" - if self.ids.refresh_layout.scroll_y <= -0.00 and self.has_refreshed: - self.ids.refresh_layout.scroll_y = .06 + if self.ids.scroll_y.scroll_y <= -0.00 and self.has_refreshed: + self.ids.scroll_y.scroll_y = .06 load_more = len(self.ids.ml.children) self.updating_allmail(load_more) else: @@ -2439,13 +2487,13 @@ class Allmails(Screen): unique_id)) self.ids.ml.remove_widget(instance.parent.parent) try: - msg_count_objs = self.parent.parent.parent.parent.children[ - 2].children[0].ids - nav_lay_obj = self.parent.parent.parent.parent.ids - except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids nav_lay_obj = self.parent.parent.parent.parent.parent.ids + except Exception: + msg_count_objs = self.parent.parent.parent.parent.parent.parent.children[ + 2].children[0].ids + nav_lay_obj = self.parent.parent.parent.parent.parent.parent.ids if folder == 'inbox': msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) @@ -2466,8 +2514,7 @@ class Allmails(Screen): state.all_count = str(int(state.all_count) - 1) nav_lay_obj.sc5.clear_widgets() nav_lay_obj.sc5.add_widget(Trash()) - nav_lay_obj.sc17.clear_widgets() - nav_lay_obj.sc17.add_widget(Allmails()) + nav_lay_obj.sc17.remove_widget(instance.parent.parent) # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): @@ -2496,10 +2543,13 @@ class Allmails(Screen): def avatarImageFirstLetter(letter_string): """This function is used to the first letter for the avatar image""" - 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] + if letter_string: + 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 = '!' else: img_latter = '!' return img_latter From e092ca7aa6a17ad630748f13ee87195bd75c27b8 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 10 Dec 2019 19:07:48 +0530 Subject: [PATCH 253/306] mpybit fixes --- src/bitmessagekivy/kivy_helper_search.py | 20 +++++++++++++------- src/bitmessagekivy/mpybit.py | 13 +++++-------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 48e77cb2..085e2aa2 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -4,7 +4,9 @@ Sql queries for bitmessagekivy from helper_sql import sqlQuery -def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, what=None, unreadOnly=False, start_indx=0, end_indx=20): +def search_sql( + xAddress="toaddress", account=None, folder="inbox", where=None, + what=None, unreadOnly=False, start_indx=0, end_indx=20): """Method helping for searching mails""" # pylint: disable=too-many-arguments, too-many-branches if what is not None and what != "": @@ -14,14 +16,14 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if folder == "sent" or folder == "draft": sqlStatementBase = ( - '''SELECT toaddress, fromaddress, subject, message, status, ackdata,''' - ''' lastactiontime FROM sent ''') + '''SELECT toaddress, fromaddress, subject, message, status,''' + ''' ackdata, lastactiontime FROM sent ''') elif folder == "addressbook": sqlStatementBase = '''SELECT label, address From addressbook ''' else: sqlStatementBase = ( - '''SELECT folder, msgid, toaddress, message, fromaddress, subject,''' - ''' received, read FROM inbox ''') + '''SELECT folder, msgid, toaddress, message, fromaddress,''' + ''' subject, received, read FROM inbox ''') sqlStatementParts = [] sqlArguments = [] @@ -59,9 +61,13 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w if sqlStatementParts: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent" or folder == "draft": - sqlStatementBase += " ORDER BY lastactiontime DESC limit {0}, {1}".format(start_indx, end_indx) + sqlStatementBase += \ + " ORDER BY lastactiontime DESC limit {0}, {1}".format( + start_indx, end_indx) elif folder == "inbox": - sqlStatementBase += " ORDER BY received DESC limit {0}, {1}".format(start_indx, end_indx) + sqlStatementBase += \ + " ORDER BY received DESC limit {0}, {1}".format( + start_indx, end_indx) # elif folder == "addressbook": # sqlStatementBase += " limit {0}, {1}".format(start_indx, end_indx) return sqlQuery(sqlStatementBase, sqlArguments) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 5fc561da..b5a11667 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -62,7 +62,7 @@ import state from uikivysignaler import UIkivySignaler import identiconGeneration -from addresses import addBMIfNotPresent, decodeAddress, encodeVarint +from addresses import addBMIfNotPresent, decodeAddress def toast(text): @@ -590,7 +590,6 @@ class DropDownWidget(BoxLayout): sendMessageToPeople = True if sendMessageToPeople: if toAddress != '' and subject and message: - from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = ( decodeAddress(toAddress)) if status == 'success': @@ -612,7 +611,6 @@ class DropDownWidget(BoxLayout): state.detailPageType = '' state.send_draft_mail = None else: - from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' if (addressVersionNumber > 4) or ( @@ -1708,7 +1706,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.current = 'allmails' try: self.root.ids.sc17.children[1].active = True - except Exception as e: + except Exception: self.root.ids.sc17.children[0].children[1].active = True Clock.schedule_once(partial(self.load_screen_callback, instance), 1) @@ -1723,7 +1721,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc17.add_widget(Allmails()) try: self.root.ids.sc17.children[1].active = False - except Exception as e: + except Exception: self.root.ids.sc17.children[0].children[1].active = False @@ -1843,7 +1841,8 @@ class GrashofPopup(Popup): elif status == 'checksumfailed': text = "The address is not typed or copied correctly(the checksum failed)." elif status == 'versiontoohigh': - text = "The version number of this address is higher than this software can support. Please upgrade Bitmessage." + text = "The version number of this address is higher"\ + " than this software can support. Please upgrade Bitmessage." elif status == 'invalidcharacters': text = "The address contains invalid characters." elif status == 'ripetooshort': @@ -2311,9 +2310,7 @@ class Draft(Screen): encoding = 3 sendMessageToPeople = True if sendMessageToPeople: - from addresses import decodeAddress streamNumber, ripe = decodeAddress(toAddress)[2:] - from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') From 55d1a4f4e1687d8f44852cc7665ddeeee726daa9 Mon Sep 17 00:00:00 2001 From: navjot Date: Wed, 18 Dec 2019 16:48:23 +0530 Subject: [PATCH 254/306] fixed draft or trash screen update issue --- src/bitmessagekivy/main.kv | 8 +------- src/bitmessagekivy/mpybit.py | 31 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 6b6cde88..c4352cfe 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -552,12 +552,6 @@ NavigationLayout: color: (1,1,1,1) halign: 'center' -: - name: 'add_sucess' - Label: - text: 'Successfully created a new bit address' - color: 0,0,0,1 - : name: 'set' ScrollView: @@ -665,7 +659,7 @@ NavigationLayout: do_scroll_x: False BoxLayout: orientation: 'vertical' - padding: [dp(app.window_size[0]/16 if app.window_size[0] <= 720 else app.window_size[0]/4*1.1 if app.window_size[0] <= 800 else app.window_size[0]/18), dp(10)] + padding: [dp(app.window_size[0]/16 if app.window_size[0] <= 720 else app.window_size[0]/6 if app.window_size[0] <= 800 else app.window_size[0]/18), dp(10)] spacing: 12 size_hint_y: None height: self.minimum_height + dp(app.window_size[1]) if app.window_size[1] > app.window_size[0] else dp(app.window_size[0]) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b5a11667..a0a03f9d 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -409,11 +409,9 @@ class MyAddress(Screen): @staticmethod def filter_address(address): """Method will filter the my address list data""" - # if filter(lambda x: (state.searcing_text).lower() in x, [ - # BMConfigParser().get( - # address, 'label').lower(), address.lower()]): - if [x for x in [BMConfigParser().get( - address, 'label').lower(), address.lower()]]: + if filter(lambda x: (state.searcing_text).lower() in x, [ + BMConfigParser().get( + address, 'label').lower(), address.lower()]): return True return False @@ -608,8 +606,6 @@ class DropDownWidget(BoxLayout): str(state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) - state.detailPageType = '' - state.send_draft_mail = None else: toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' @@ -648,6 +644,12 @@ class DropDownWidget(BoxLayout): state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[2].children[0].ids + if state.detailPageType == 'draft' \ + and state.send_draft_mail: + state.draft_count = str(int(state.draft_count) - 1) + state.msg_counter_objs.draft_cnt.badge_text = state.draft_count + state.detailPageType = '' + state.send_draft_mail = None # self.parent.parent.screens[0].ids.ml.clear_widgets() # self.parent.parent.screens[0].loadMessagelist(state.association) self.parent.parent.screens[3].update_sent_messagelist() @@ -884,16 +886,12 @@ class Sent(Screen): def init_ui(self, dt=0): """Clock Schdule for method sent accounts""" - self.sentaccounts() - print dt - - def sentaccounts(self): - """Load sent accounts.""" - self.account = state.association self.loadSent() + print dt def loadSent(self, where="", what=""): """Load Sent list for Sent messages.""" + self.account = state.association if state.searcing_text: self.ids.scroll_y.scroll_y = 1.0 where = ['subject', 'message'] @@ -1987,8 +1985,8 @@ class MailDetail(Screen): int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) - self.parent.screens[4].ids.ml.clear_widgets() - self.parent.screens[4].init_ui(dt=0) + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) self.parent.screens[16].ids.ml.clear_widgets() self.parent.screens[16].init_ui(dt=0) Clock.schedule_once(self.callback_for_delete, 4) @@ -2288,7 +2286,8 @@ class Draft(Screen): data_index)) try: msg_count_objs = ( - self.parent.parent.parent.parent.children[2].children[0].ids) + self.parent.parent.parent.parent.parent.parent.children[ + 2].children[0].ids) except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids From 65ef7b3a0ee5c0f6885a9e3545e606cbf1e803e3 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 18 Dec 2019 19:20:56 +0530 Subject: [PATCH 255/306] fixes after pull --- src/bitmessagekivy/mpybit.py | 5 +++-- src/class_singleCleaner.py | 2 +- src/state.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a0a03f9d..64b47fa3 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -409,6 +409,7 @@ class MyAddress(Screen): @staticmethod def filter_address(address): """Method will filter the my address list data""" + # pylint: disable=deprecated-lambda if filter(lambda x: (state.searcing_text).lower() in x, [ BMConfigParser().get( address, 'label').lower(), address.lower()]): @@ -529,7 +530,7 @@ class AddressBook(Screen): class SelectableRecycleBoxLayout( FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view""" - # pylint: disable = too-many-ancestors + # pylint: disable = too-many-ancestors, duplicate-bases pass @@ -2287,7 +2288,7 @@ class Draft(Screen): try: msg_count_objs = ( self.parent.parent.parent.parent.parent.parent.children[ - 2].children[0].ids) + 2].children[0].ids) except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 2f435b99..e16ddcf4 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -21,12 +21,12 @@ It resends messages when there has been no response: # pylint: disable=relative-import, protected-access import gc import os +from datetime import datetime, timedelta import time import shared import knownnodes import queues -import shared import state import tr from bmconfigparser import BMConfigParser diff --git a/src/state.py b/src/state.py index 038e0e0a..8abd211d 100644 --- a/src/state.py +++ b/src/state.py @@ -124,4 +124,4 @@ availabe_credit = 0 in_sent_method = False -in_search_mode = False \ No newline at end of file +in_search_mode = False From 3b115adf9cc35a4b12539925ba0dce2d30d84b83 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 18 Dec 2019 19:51:24 +0530 Subject: [PATCH 256/306] fixes after pull --- src/bitmessagekivy/mpybit.py | 6 ++++-- src/class_singleCleaner.py | 2 +- src/state.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a0a03f9d..94a461c4 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -409,6 +409,7 @@ class MyAddress(Screen): @staticmethod def filter_address(address): """Method will filter the my address list data""" + # pylint: disable=deprecated-lambda if filter(lambda x: (state.searcing_text).lower() in x, [ BMConfigParser().get( address, 'label').lower(), address.lower()]): @@ -529,7 +530,7 @@ class AddressBook(Screen): class SelectableRecycleBoxLayout( FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view""" - # pylint: disable = too-many-ancestors + # pylint: disable = too-many-ancestors, duplicate-bases pass @@ -1586,6 +1587,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods msg_counter_objs.allmail_cnt.badge_text = state.all_count def on_start(self): + """Method activates on start""" self.set_message_count() @staticmethod @@ -2287,7 +2289,7 @@ class Draft(Screen): try: msg_count_objs = ( self.parent.parent.parent.parent.parent.parent.children[ - 2].children[0].ids) + 2].children[0].ids) except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 2f435b99..e16ddcf4 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -21,12 +21,12 @@ It resends messages when there has been no response: # pylint: disable=relative-import, protected-access import gc import os +from datetime import datetime, timedelta import time import shared import knownnodes import queues -import shared import state import tr from bmconfigparser import BMConfigParser diff --git a/src/state.py b/src/state.py index 038e0e0a..8abd211d 100644 --- a/src/state.py +++ b/src/state.py @@ -124,4 +124,4 @@ availabe_credit = 0 in_sent_method = False -in_search_mode = False \ No newline at end of file +in_search_mode = False From 55a7a96e8cd8b9706bf22011a8b84274fff2312b Mon Sep 17 00:00:00 2001 From: navjot Date: Wed, 18 Dec 2019 20:02:03 +0530 Subject: [PATCH 257/306] fixed search enter button extra load issue --- src/bitmessagekivy/mpybit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a0a03f9d..7aba57ad 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1432,8 +1432,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) return True - elif key == 13: - if state.search_screen == 'inbox' and state.searcing_text: + elif key == 13 and state.searcing_text: + 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': From c79636863d8bae013e929c0ab842fd40d0cd13c2 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 5 Dec 2019 18:17:35 +0200 Subject: [PATCH 258/306] If tray is not available, disable settings group "Tray" and related checkboxes; set checkBoxMinimizeToTray to false by default --- src/bitmessageqt/settings.py | 39 +++++++++++++++++++++++++----------- src/bitmessageqt/settings.ui | 2 +- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 982328cc..7fb0ea91 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -47,20 +47,33 @@ class SettingsDialog(QtGui.QDialog): def adjust_from_config(self, config): """Adjust all widgets state according to config settings""" # pylint: disable=too-many-branches,too-many-statements - self.checkBoxStartOnLogon.setChecked( - config.getboolean('bitmessagesettings', 'startonlogon')) - self.checkBoxMinimizeToTray.setChecked( - config.getboolean('bitmessagesettings', 'minimizetotray')) - self.checkBoxTrayOnClose.setChecked( - config.safeGetBoolean('bitmessagesettings', 'trayonclose')) + if not self.parent.tray.isSystemTrayAvailable(): + self.groupBoxTray.setEnabled(False) + self.groupBoxTray.setTitle(_translate( + "MainWindow", "Tray (not available in your system)")) + for setting in ( + 'minimizetotray', 'trayonclose', 'startintray'): + config.set('bitmessagesettings', setting, 'false') + else: + self.checkBoxMinimizeToTray.setChecked( + config.getboolean('bitmessagesettings', 'minimizetotray')) + self.checkBoxTrayOnClose.setChecked( + config.safeGetBoolean('bitmessagesettings', 'trayonclose')) + self.checkBoxStartInTray.setChecked( + config.getboolean('bitmessagesettings', 'startintray')) + self.checkBoxHideTrayConnectionNotifications.setChecked( - config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) + config.getboolean( + 'bitmessagesettings', 'hidetrayconnectionnotifications')) self.checkBoxShowTrayNotifications.setChecked( config.getboolean('bitmessagesettings', 'showtraynotifications')) - self.checkBoxStartInTray.setChecked( - config.getboolean('bitmessagesettings', 'startintray')) + + self.checkBoxStartOnLogon.setChecked( + config.getboolean('bitmessagesettings', 'startonlogon')) + self.checkBoxWillinglySendToMobile.setChecked( - config.safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) + config.safeGetBoolean( + 'bitmessagesettings', 'willinglysendtomobile')) self.checkBoxUseIdenticons.setChecked( config.safeGetBoolean('bitmessagesettings', 'useidenticons')) self.checkBoxReplyBelow.setChecked( @@ -82,10 +95,12 @@ class SettingsDialog(QtGui.QDialog): "MainWindow", "Start-on-login not yet supported on your OS.")) self.checkBoxMinimizeToTray.setDisabled(True) self.checkBoxMinimizeToTray.setText(_translate( - "MainWindow", "Minimize-to-tray not yet supported on your OS.")) + "MainWindow", + "Minimize-to-tray not yet supported on your OS.")) self.checkBoxShowTrayNotifications.setDisabled(True) self.checkBoxShowTrayNotifications.setText(_translate( - "MainWindow", "Tray notifications not yet supported on your OS.")) + "MainWindow", + "Tray notifications not yet supported on your OS.")) elif 'linux' in sys.platform: self.checkBoxStartOnLogon.setDisabled(True) self.checkBoxStartOnLogon.setText(_translate( diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 963f2e64..33278e94 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -75,7 +75,7 @@ Minimize to tray - true + false From 5a35de6bca4385431905be5a59f004f7bfd2896c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 20 Dec 2019 15:20:14 +0200 Subject: [PATCH 259/306] Fix sendOnionPeerObj() broken in 9923e97 --- src/class_singleWorker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index a275b79d..d035c092 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -467,8 +467,8 @@ class singleWorker(StoppableThread): def sendOnionPeerObj(self, peer=None): """Send onionpeer object representing peer""" if not peer: # find own onionhostname - for peer_ in state.ownAddresses: - if peer_.host.endswith('.onion'): + for peer in state.ownAddresses: + if peer.host.endswith('.onion'): break else: return From e8c4a44f35ec151608275b6d4acbffc584ef9d0b Mon Sep 17 00:00:00 2001 From: navjot Date: Mon, 23 Dec 2019 20:18:03 +0530 Subject: [PATCH 260/306] worked on implementing screen identifier tag feature --- src/bitmessagekivy/main.kv | 133 +++++++++++++++++++++++++++++------ src/bitmessagekivy/mpybit.py | 92 +++++++++++++----------- 2 files changed, 160 insertions(+), 65 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index c4352cfe..85ba2979 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -16,6 +16,7 @@ #:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout #:import MDSpinner kivymd.spinner.MDSpinner #:import NoTransition kivy.uix.screenmanager.NoTransition +#:import MDSeparator kivymd.card.MDSeparator #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -202,8 +203,18 @@ NavigationLayout: transition: NoTransition() BoxLayout: orientation: 'vertical' - spacing: dp(10) + spacing: dp(5) SearchBar: + GridLayout: + id: identi_tag + padding: [20, 0, 0, 5] + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True #FloatLayout: # MDScrollViewRefreshLayout: # id: refresh_layout @@ -225,7 +236,18 @@ NavigationLayout: name: 'sent' BoxLayout: orientation: 'vertical' + spacing: dp(5) SearchBar: + GridLayout: + id: identi_tag + padding: [20, 0, 0, 5] + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True BoxLayout: orientation:'vertical' ScrollView: @@ -238,21 +260,52 @@ NavigationLayout: : name: 'trash' - ScrollView: - id: scroll_y - do_scroll_x: False - MDList: - id: ml + BoxLayout: + orientation: 'vertical' + spacing: dp(5) + GridLayout: + id: identi_tag + padding: [20, 20, 0, 5] + spacing: dp(5) + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True + BoxLayout: + orientation:'vertical' + ScrollView: + id: scroll_y + do_scroll_x: False + MDList: + id: ml Loader: ComposerButton: - + : name: 'draft' - ScrollView: - id: scroll_y - do_scroll_x: False - MDList: - id: ml + BoxLayout: + orientation: 'vertical' + spacing: dp(5) + GridLayout: + id: identi_tag + padding: [20, 20, 0, 5] + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True + BoxLayout: + orientation:'vertical' + ScrollView: + id: scroll_y + do_scroll_x: False + MDList: + id: ml ComposerButton: : @@ -289,12 +342,26 @@ NavigationLayout: # MDList: # id: ml BoxLayout: - orientation:'vertical' - ScrollView: - id: scroll_y - do_scroll_x: False - MDList: - id: ml + orientation: 'vertical' + spacing: dp(5) + GridLayout: + id: identi_tag + padding: [20, 20, 0, 5] + spacing: dp(5) + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True + BoxLayout: + orientation:'vertical' + ScrollView: + id: scroll_y + do_scroll_x: False + MDList: + id: ml Loader: ComposerButton: @@ -495,7 +562,6 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .5, .35 height: dp(40) on_press: app.root.ids.scr_mngr.current = 'random' on_press: app.root.ids.sc7.reset_address_label() @@ -541,7 +607,6 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .5, None height: dp(40) on_release: root.generateaddress(app) opposite_colors: True @@ -627,7 +692,18 @@ NavigationLayout: name: 'myaddress' BoxLayout: orientation: 'vertical' + spacing: dp(5) SearchBar: + GridLayout: + id: identi_tag + padding: [20, 0, 0, 5] + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: 'My Addresses' + font_style: 'Body1' + bold: True FloatLayout: MDScrollViewRefreshLayout: id: refresh_layout @@ -642,7 +718,18 @@ NavigationLayout: name: 'addressbook' BoxLayout: orientation: 'vertical' + spacing: dp(5) SearchBar: + GridLayout: + id: identi_tag + padding: [20, 0, 0, 5] + cols: 1 + size_hint_y: None + height: self.minimum_height + MDLabel: + text: '' + font_style: 'Body1' + bold: True BoxLayout: orientation:'vertical' ScrollView: @@ -803,7 +890,7 @@ NavigationLayout: id: popup size_hint : (None,None) height: 2*(label.height + address.height) + 10 - width :app.window_size[0] - app.window_size[0]/10 + width :app.window_size[0] - (app.window_size[0]/10 if app.app_platform == 'android' else app.window_size[0]/4) title: 'add contact\'s' background: './images/popup.jpeg' title_size: sp(20) @@ -1036,7 +1123,7 @@ NavigationLayout: id: myadd_popup size_hint : (None,None) height: 4.5*(myaddr_label.height+ my_add_btn.children[0].height) - width :app.window_size[0] - app.window_size[0]/10 + width :app.window_size[0] - (app.window_size[0]/10 if app.app_platform == 'android' else app.window_size[0]/4) background: './images/popup.jpeg' auto_dismiss: False separator_height: 0 @@ -1116,7 +1203,7 @@ NavigationLayout: id: addbook_popup size_hint : (None,None) height: 4*(add_label.height) - width :app.window_size[0] - app.window_size[0]/10 + width :app.window_size[0] - (app.window_size[0]/10 if app.app_platform == 'android' else app.window_size[0]/4) background: './images/popup.jpeg' separator_height: 0 auto_dismiss: False diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index cdb55a18..c138831a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -114,7 +114,9 @@ class Inbox(Screen): xAddress = 'toaddress' data = [] self.inboxDataQuery(xAddress, where, what) + self.ids.identi_tag.children[0].text = '' if self.queryreturn: + self.ids.identi_tag.children[0].text = 'Inbox' state.kivyapp.get_inbox_count() src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.inbox_cnt.badge_text = state.inbox_count @@ -261,6 +263,8 @@ class Inbox(Screen): int(state.trash_count) + 1) state.all_count = str( int(state.all_count) - 1) + if int(state.inbox_count) <= 0: + self.ids.identi_tag.children[0].text = '' self.ids.ml.remove_widget( instance.parent.parent) toast('Deleted') @@ -326,7 +330,9 @@ class MyAddress(Screen): addr), BMConfigParser().addresses()) self.addresses_list = filtered_list self.addresses_list = [obj for obj in reversed(self.addresses_list)] + self.ids.identi_tag.children[0].text = '' if self.addresses_list: + self.ids.identi_tag.children[0].text = 'My Addresses' self.has_refreshed = True self.set_mdList(0, 15) self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) @@ -398,7 +404,7 @@ class MyAddress(Screen): """Method used for loading the myaddress screen data""" state.searcing_text = '' state.kivyapp.root.ids.sc10.children[2].active = False - self.children[2].children[1].ids.search_field.text = '' + self.children[2].children[2].ids.search_field.text = '' self.has_refreshed = True self.ids.ml.clear_widgets() self.init_ui() @@ -443,10 +449,12 @@ class AddressBook(Screen): where = ['label', 'address'] what = state.searcing_text xAddress = '' + self.ids.identi_tag.children[0].text = '' self.queryreturn = kivy_helper_search.search_sql( xAddress, account, "addressbook", where, what, False) self.queryreturn = [obj for obj in reversed(self.queryreturn)] if self.queryreturn: + self.ids.identi_tag.children[0].text = 'Address Book' self.has_refreshed = True self.set_mdList(0, 20) self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) @@ -523,6 +531,8 @@ class AddressBook(Screen): def delete_address(self, address, instance, *args): """Delete inbox mail from inbox listing""" self.ids.ml.remove_widget(instance.parent.parent) + if len(self.ids.ml.children) == 0: + self.ids.identi_tag.children[0].text = '' sqlExecute( "DELETE FROM addressbook WHERE address = '{}';".format(address)) @@ -680,9 +690,10 @@ class DropDownWidget(BoxLayout): # pylint: disable=attribute-defined-outside-init def address_error_message(self, msg): """Generates error message""" + width = .8 if platform == 'android' else .55 msg_dialog = MDDialog( text=msg, - title='', size_hint=(.8, .25), text_button_ok='Ok', + title='', size_hint=(width, .25), text_button_ok='Ok', events_callback=self.callback_for_menu_items) msg_dialog.open() @@ -899,8 +910,10 @@ class Sent(Screen): what = state.searcing_text xAddress = 'fromaddress' data = [] + self.ids.identi_tag.children[0].text = '' self.sentDataQuery(xAddress, where, what) if self.queryreturn: + self.ids.identi_tag.children[0].text = 'Sent' self.set_sentCount(state.sent_count) for mail in self.queryreturn: data.append({ @@ -1063,6 +1076,8 @@ class Sent(Screen): state.sent_count = str(int(state.sent_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) + if int(state.sent_count) <= 0: + self.ids.identi_tag.children[0].text = '' sqlExecute( "UPDATE sent SET folder = 'trash'" " WHERE ackdata = ?;", str(data_index)) @@ -1109,8 +1124,10 @@ class Trash(Screen): if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] + self.ids.identi_tag.children[0].text = '' self.trashDataQuery(0, 20) if self.trash_messages: + self.ids.identi_tag.children[0].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_mdList() @@ -1202,11 +1219,12 @@ class Trash(Screen): def delete_confirmation(self): """Show confirmation delete popup""" + width = .8 if platform == 'android' else .55 delete_msg_dialog = MDDialog( text='Are you sure you want to delete this' ' message permanently from trash?', title='', - size_hint=(.8, .25), + size_hint=(width, .25), text_button_ok='Yes', text_button_cancel='No', events_callback=self.callback_for_delete_msg) @@ -1269,6 +1287,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods nav_drawer = ObjectProperty() state.screen_density = Window.size window_size = state.screen_density + app_platform = platform title = "PyBitmessage" imgstatus = False count = 0 @@ -1338,7 +1357,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.sc1.loadMessagelist(state.association) self.root.ids.sc4.ids.ml.clear_widgets() - self.root.ids.sc4.children[2].children[1].ids.search_field.text = '' + 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() @@ -1429,7 +1448,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods elif self.root.ids.scr_mngr.current == "random": self.root.ids.scr_mngr.current = 'login' else: - self.root.ids.scr_mngr.current = 'inbox' + 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 @@ -1643,30 +1663,30 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods if state.search_screen == 'inbox': try: self.root.ids.sc1.children[ - 3].children[1].ids.search_field.text = '' + 3].children[2].ids.search_field.text = '' except Exception: self.root.ids.sc1.children[ - 2].children[1].ids.search_field.text = '' + 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.children[ - 2].children[1].ids.search_field.text = '' + 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': try: self.root.ids.sc10.children[ - 3].children[1].ids.search_field.text = '' + 3].children[2].ids.search_field.text = '' except Exception: self.root.ids.sc10.children[ - 2].children[1].ids.search_field.text = '' + 2].children[2].ids.search_field.text = '' self.root.ids.sc10.children[1].active = True Clock.schedule_once(self.search_callback, 0.5) else: self.root.ids.sc4.children[ - 2].children[1].ids.search_field.text = '' + 2].children[2].ids.search_field.text = '' self.root.ids.sc4.children[1].active = True Clock.schedule_once(self.search_callback, 0.5) return @@ -1760,26 +1780,6 @@ class GrashofPopup(Popup): self.parent.children[1].ids.scr_mngr.current = 'addressbook' toast('Saved') - # pylint: disable=attribute-defined-outside-init - def show_error_message(self): - """Showing error message""" - content = MDLabel( - font_style='Body1', - theme_text_color='Secondary', - text="Hey you are not allowed to save blank address contact. " - "That's wrong!", - size_hint_y=None, - valign='top') - content.bind(texture_size=content.setter('size')) - self.dialog = MDDialog(content=content, - size_hint=(.8, None), - height=dp(200), - auto_dismiss=False) - - self.dialog.add_action_button("ok", - action=lambda *x: self.dialog.dismiss()) - self.dialog.open() - @staticmethod def close_pop(): """Pop is Canceled""" @@ -1947,25 +1947,25 @@ class MailDetail(Screen): self.children[0].children[0].active = True if state.detailPageType == 'sent': state.kivyapp.root.ids.sc4.children[ - 2].children[1].ids.search_field.text = '' + 2].children[2].ids.search_field.text = '' sqlExecute( "UPDATE sent SET folder = 'trash' WHERE" " ackdata = ?;", str(state.mail_id)) - msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) - state.sent_count = str(int(state.sent_count) - 1) + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) if int(state.sent_count) else '0' + state.sent_count = str(int(state.sent_count) - 1) if int(state.sent_count) else '0' self.parent.screens[3].ids.ml.clear_widgets() self.parent.screens[3].loadSent(state.association) elif state.detailPageType == 'inbox': state.kivyapp.root.ids.sc1.children[ - 2].children[1].ids.search_field.text = '' + 2].children[2].ids.search_field.text = '' self.parent.screens[0].children[2].children[ - 1].ids.search_field.text = '' + 2].ids.search_field.text = '' sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE" " msgid = ?;", str(state.mail_id)) msg_count_objs.inbox_cnt.badge_text = str( - int(state.inbox_count) - 1) - state.inbox_count = str(int(state.inbox_count) - 1) + int(state.inbox_count) - 1) if int(state.inbox_count) else '0' + state.inbox_count = str(int(state.inbox_count) - 1) if int(state.inbox_count) else '0' self.parent.screens[0].ids.ml.clear_widgets() self.parent.screens[0].loadMessagelist(state.association) @@ -1984,13 +1984,13 @@ class MailDetail(Screen): msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) msg_count_objs.allmail_cnt.badge_text = str( - int(state.all_count) - 1) + int(state.all_count) - 1) if int(state.all_count) else '0' state.trash_count = str(int(state.trash_count) + 1) - state.all_count = str(int(state.all_count) - 1) + state.all_count = str(int(state.all_count) - 1) if int(state.all_count) else '0' self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) - self.parent.screens[16].ids.ml.clear_widgets() - self.parent.screens[16].init_ui(dt=0) + self.parent.screens[16].clear_widgets() + self.parent.screens[16].add_widget(Allmails()) Clock.schedule_once(self.callback_for_delete, 4) def callback_for_delete(self, dt=0): @@ -2182,11 +2182,13 @@ class Draft(Screen): def loadDraft(self, where="", what=""): """Load draft list for Draft messages.""" xAddress = 'fromaddress' + self.ids.identi_tag.children[0].text = '' self.draftDataQuery(xAddress, where, what) if state.msg_counter_objs: state.msg_counter_objs.draft_cnt.badge_text = str( len(self.queryreturn)) if self.queryreturn: + self.ids.identi_tag.children[0].text = 'Draft' src_mng_obj = state.kivyapp.root.children[2].children[0].ids src_mng_obj.draft_cnt.badge_text = state.draft_count self.set_mdList() @@ -2297,6 +2299,8 @@ class Draft(Screen): msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) + if int(state.draft_count) <= 0: + self.ids.identi_tag.children[0].text = '' self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') @@ -2376,8 +2380,10 @@ class Allmails(Screen): def loadMessagelist(self): """Load Inbox, Sent anf Draft list of messages.""" self.account = state.association + self.ids.identi_tag.children[0].text = '' self.allMessageQuery(0, 20) if self.all_mails: + self.ids.identi_tag.children[0].text = 'All Mails' state.kivyapp.get_inbox_count() state.kivyapp.get_sent_count() state.all_count = str( @@ -2510,6 +2516,8 @@ class Allmails(Screen): int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) + if int(state.all_count) <= 0: + self.ids.identi_tag.children[0].text = '' nav_lay_obj.sc5.clear_widgets() nav_lay_obj.sc5.add_widget(Trash()) nav_lay_obj.sc17.remove_widget(instance.parent.parent) From 03316496b7c3380c5ac408f86d049855dbcedac6 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 14 Dec 2019 12:53:51 +0200 Subject: [PATCH 261/306] Stop UDPSocket on socket.error 101 (Network is unreachable) --- src/network/udp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/udp.py b/src/network/udp.py index cf694567..d8c5f340 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -146,6 +146,9 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes retval = self.socket.sendto( self.write_buf, ('', self.port)) except socket.error as e: - logger.error("socket error on sendato: %s", e) + logger.error("socket error on sendto: %s", e) + if e.errno == 101: + self.announcing = False + self.socket.close() retval = 0 self.slice_write_buf(retval) From fc6e5674fea12768cdcf400b341a9f2dee344bf5 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 20 Dec 2019 19:37:31 +0530 Subject: [PATCH 262/306] kivy Fixes --- src/bitmessagekivy/mpybit.py | 319 +++++++++------------------ src/bitmessagekivy/uikivysignaler.py | 14 +- 2 files changed, 114 insertions(+), 219 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index c138831a..c937abd1 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -13,7 +13,6 @@ 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, @@ -93,7 +92,7 @@ class Inbox(Screen): @staticmethod def set_defaultAddress(): - """This method set default address""" + """This method set's default address""" if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] @@ -134,46 +133,31 @@ class Inbox(Screen): scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="No message found!" if state.searcing_text else "yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) # pylint: disable=too-many-arguments def inboxDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This method used for retrieving inbox data""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, - self.account, - "inbox", - where, - what, - False, - start_indx, - end_indx) + xAddress, self.account, "inbox", where, what, + False, start_indx, end_indx) def set_mdList(self, data): """This method is used to create the mdList""" total_message = len(self.ids.ml.children) for item in data: meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], + text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget( - AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - avatarImageFirstLetter( - item['secondary_text'].strip())))) - meny.bind( - on_press=partial( - self.inbox_detail, item['msgid'])) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) + meny.bind(on_press=partial(self.inbox_detail, item['msgid'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -183,16 +167,12 @@ class Inbox(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) - del_btn.bind( - on_press=partial( - self.delete, item['msgid'])) + del_btn.bind(on_press=partial(self.delete, item['msgid'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind( - on_press=partial( - self.archive, item['msgid'])) + ach_btn.bind(on_press=partial(self.archive, item['msgid'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) @@ -200,7 +180,7 @@ class Inbox(Screen): self.has_refreshed = True if total_message != update_message else False def check_scroll_y(self, instance, somethingelse): - """This method is used to load data on scroll""" + """Loads data on scroll""" if self.children[2].children[0].children[ 0].scroll_y <= -0.0 and self.has_refreshed: self.children[2].children[0].children[0].scroll_y = 0.06 @@ -273,8 +253,8 @@ class Inbox(Screen): def archive(self, data_index, instance, *args): """Archive inbox mail from inbox listing""" sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( - data_index)) + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", + str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -300,7 +280,6 @@ class Inbox(Screen): self.has_refreshed = True self.ids.refresh_layout.refresh_done() self.tick = 0 - Clock.schedule_once(refresh_callback, 1) # def set_root_layout(self): @@ -321,13 +300,16 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock schdule for method Myaddress accounts""" - # pylint: disable=unnecessary-lambda, deprecated-lambda self.addresses_list = state.kivyapp.variable_1 if state.searcing_text: self.ids.refresh_layout.scroll_y = 1.0 - filtered_list = filter( - lambda addr: self.filter_address( - addr), BMConfigParser().addresses()) + # filtered_list = filter( + # lambda addr: self.filter_address( + # addr), BMConfigParser().addresses()) + filtered_list = [ + x + for x in BMConfigParser().addresses() + if self.filter_address(x)] self.addresses_list = filtered_list self.addresses_list = [obj for obj in reversed(self.addresses_list)] self.ids.identi_tag.children[0].text = '' @@ -338,14 +320,10 @@ class MyAddress(Screen): self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="No address found!" if state.searcing_text else "yet no address is created by user!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) if not state.searcing_text and not self.is_add_created: try: @@ -362,8 +340,7 @@ class MyAddress(Screen): 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], + text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( @@ -415,10 +392,12 @@ class MyAddress(Screen): @staticmethod def filter_address(address): """Method will filter the my address list data""" - # pylint: disable=deprecated-lambda - if filter(lambda x: (state.searcing_text).lower() in x, [ - BMConfigParser().get( - address, 'label').lower(), address.lower()]): + # if filter(lambda x: (state.searcing_text).lower() in x, [ + # BMConfigParser().get( + # address, 'label').lower(), address.lower()]): + if [x for x in [BMConfigParser().get( + address, 'label').lower(), address.lower()] if ( + state.searcing_text).lower() in x]: return True return False @@ -460,23 +439,17 @@ class AddressBook(Screen): self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="No contact found!" if state.searcing_text else "No contact found yet...... ", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) def set_mdList(self, start_index, end_index): """Creating the mdList""" for item in self.queryreturn[start_index:end_index]: meny = TwoLineAvatarIconListItem( - text=item[0], - secondary_text=item[1], - theme_text_color='Custom', + text=item[0], secondary_text=item[1], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( @@ -606,15 +579,10 @@ class DropDownWidget(BoxLayout): if state.detailPageType == 'draft' \ and state.send_draft_mail: sqlExecute( - "UPDATE sent SET toaddress = ?" - ", fromaddress = ? , subject = ?" - ", message = ?, folder = 'sent'" - " WHERE ackdata = ?;", - toAddress, - fromAddress, - subject, - message, - str(state.send_draft_mail)) + "UPDATE sent SET toaddress = ?, fromaddress = ? ," + " subject = ?, message = ?, folder = 'sent' WHERE" + " ackdata = ?;", toAddress, fromAddress, subject, + message, str(state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) else: @@ -636,27 +604,15 @@ class DropDownWidget(BoxLayout): sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, - int(time.time()), - int(time.time()), - 0, - 'msgqueued', - 0, - 'sent', - encoding, + '', toAddress, ripe, fromAddress, subject, message, + ackdata, int(time.time()), int(time.time()), 0, + 'msgqueued', 0, 'sent', encoding, BMConfigParser().getint( 'bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[2].children[0].ids - if state.detailPageType == 'draft' \ - and state.send_draft_mail: + if state.detailPageType == 'draft' and state.send_draft_mail: state.draft_count = str(int(state.draft_count) - 1) state.msg_counter_objs.draft_cnt.badge_text = state.draft_count state.detailPageType = '' @@ -745,7 +701,7 @@ class MyTextInput(TextInput): self.parent.height = 400 def keyboard_on_key_down(self, window, keycode, text, modifiers): - """Key Down""" + """Keyboard on key Down""" if self.suggestion_text and keycode[1] == 'tab': self.insert_text(self.suggestion_text + ' ') return True @@ -774,7 +730,7 @@ class Payment(Screen): class Credits(Screen): - """Credits Module""" + """Module for screen screen""" available_credits = StringProperty('{0}'.format('0')) @@ -791,7 +747,8 @@ class NetworkStat(Screen): '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_4 = StringProperty( + 'Processed {0} public keys'.format('0')) text_variable_5 = StringProperty( 'Processed {0} object to be synced'.format('0')) @@ -840,10 +797,8 @@ class Random(Screen): if entered_label and entered_label not in lables: toast('Address Creating...') queues.addressGeneratorQueue.put(( - 'createRandomAddress', - 4, streamNumberForAddress, - label, 1, "", eighteenByteRipe, - nonceTrialsPerByte, + 'createRandomAddress', 4, streamNumberForAddress, label, 1, + "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) self.ids.label.text = '' self.parent.parent.children[1].opacity = 1 @@ -927,43 +882,31 @@ class Sent(Screen): self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="No message found!" if state.searcing_text else "yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) # pylint: disable=too-many-arguments def sentDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This method is used to retrieving data from sent table""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, - self.account, - "sent", - where, - what, - False, - start_indx, - end_indx) + xAddress, self.account, "sent", where, what, + False, start_indx, end_indx) 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: meny = TwoLineAvatarIconListItem( - text=item['text'], - secondary_text=item['secondary_text'], + text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) - meny.bind(on_press=partial( - self.sent_detail, item['ackdata'])) + meny.bind(on_press=partial(self.sent_detail, item['ackdata'])) carousel = Carousel(direction='right') carousel.height = meny.height carousel.size_hint_y = None @@ -973,14 +916,12 @@ class Sent(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete, item['ackdata'])) + del_btn.bind(on_press=partial(self.delete, item['ackdata'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial( - self.archive, item['ackdata'])) + ach_btn.bind(on_press=partial(self.archive, item['ackdata'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel, index=set_index) @@ -1088,8 +1029,8 @@ class Sent(Screen): def archive(self, data_index, instance, *args): """Archive sent mail from sent mail listing""" sqlExecute( - "UPDATE sent SET folder = 'trash'" - " WHERE ackdata = ?;", str(data_index)) + "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", + str(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -1134,13 +1075,9 @@ class Trash(Screen): self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="yet no trashed message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) def trashDataQuery(self, start_indx, end_indx): @@ -1222,10 +1159,8 @@ class Trash(Screen): width = .8 if platform == 'android' else .55 delete_msg_dialog = MDDialog( text='Are you sure you want to delete this' - ' message permanently from trash?', - title='', - size_hint=(width, .25), - text_button_ok='Yes', + ' message permanently from trash?', title='', + size_hint=(width, .25), text_button_ok='Yes', text_button_cancel='No', events_callback=self.callback_for_delete_msg) delete_msg_dialog.open() @@ -1241,11 +1176,13 @@ class Trash(Screen): """Deleting message from trash""" self.children[1].active = True if self.table_name == 'inbox': - sqlExecute("DELETE FROM inbox WHERE msgid = ?;", str( - self.delete_index)) + sqlExecute( + "DELETE FROM inbox WHERE msgid = ?;", + str(self.delete_index)) elif self.table_name == 'sent': - sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( - self.delete_index)) + sqlExecute( + "DELETE FROM sent WHERE ackdata = ?;", + str(self.delete_index)) msg_count_objs = state.kivyapp.root.children[2].children[0].ids if int(state.trash_count) > 0: msg_count_objs.trash_cnt.badge_text = str( @@ -1292,20 +1229,13 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods imgstatus = False count = 0 menu_items = [ - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', - 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, + {'viewclass': 'MDMenuItem', 'text': 'Example item'}, ] def build(self): @@ -1397,9 +1327,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods img.texture.save('{1}/images/default_identicon/{0}.png'.format( BMConfigParser().addresses()[0], android_path)) else: - img.texture.save( - './images/default_identicon/{}.png'.format( - BMConfigParser().addresses()[0])) + img.texture.save('./images/default_identicon/{}.png'.format( + BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' @@ -1565,18 +1494,16 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods @staticmethod def get_inbox_count(): """Getting inbox count""" - state.inbox_count = str( - sqlQuery( - "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" - " folder = 'inbox' ;".format(state.association))[0][0]) + state.inbox_count = str(sqlQuery( + "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and" + " folder = 'inbox' ;".format(state.association))[0][0]) @staticmethod def get_sent_count(): """Getting sent count""" - state.sent_count = str( - sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" - " folder = 'sent' ;".format(state.association))[0][0]) + state.sent_count = str(sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'sent' ;".format(state.association))[0][0]) def set_message_count(self): """Setting message count""" @@ -1593,12 +1520,10 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods " where fromaddress = '{0}' and folder = 'trash' )" "+(SELECT count(*) FROM inbox where toaddress = '{0}' and" " folder = 'trash') AS SumCount".format(state.association))[0][0]) - state.draft_count = str( - sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" - " folder = 'draft' ;".format(state.association))[0][0]) + state.draft_count = str(sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and" + " folder = 'draft' ;".format(state.association))[0][0]) state.all_count = str(int(state.sent_count) + int(state.inbox_count)) - if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count msg_counter_objs.inbox_cnt.badge_text = state.inbox_count @@ -1970,8 +1895,8 @@ class MailDetail(Screen): self.parent.screens[0].loadMessagelist(state.association) elif state.detailPageType == 'draft': - sqlExecute("DELETE FROM sent WHERE ackdata = ?;", str( - state.mail_id)) + sqlExecute( + "DELETE FROM sent WHERE ackdata = ?;", str(state.mail_id)) msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) @@ -2195,27 +2120,17 @@ class Draft(Screen): self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) # pylint: disable=too-many-arguments def draftDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): """This methosd is for retrieving draft messages""" self.queryreturn = kivy_helper_search.search_sql( - xAddress, - self.account, - "draft", - where, - what, - False, - start_indx, - end_indx) + xAddress, self.account, "draft", where, what, + False, start_indx, end_indx) def set_mdList(self): """This method is used to create mdlist""" @@ -2232,8 +2147,7 @@ class Draft(Screen): 'ackdata': mail[5]}) for item in data: meny = TwoLineAvatarIconListItem( - text='Draft', - secondary_text=item['text'], + text='Draft', secondary_text=item['text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( @@ -2249,8 +2163,7 @@ class Draft(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial( - self.delete_draft, item['ackdata'])) + del_btn.bind(on_press=partial(self.delete_draft, item['ackdata'])) carousel.add_widget(del_btn) carousel.add_widget(meny) carousel.index = 1 @@ -2323,23 +2236,10 @@ class Draft(Screen): ackdata = genAckPayload(streamNumber, stealthLevel) sqlExecute( '''INSERT INTO sent VALUES - (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, - int(time.time()), - int(time.time()), - 0, - 'msgqueued', - 0, - 'draft', - encoding, + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', toAddress, ripe, + fromAddress, subject, message, ackdata, int(time.time()), + int(time.time()), 0, 'msgqueued', 0, 'draft', encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) - state.msg_counter_objs = src_object.children[2].children[0].ids state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() @@ -2395,13 +2295,9 @@ class Allmails(Screen): self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) else: content = MDLabel( - font_style='Body1', - theme_text_color='Primary', + font_style='Body1', theme_text_color='Primary', text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + halign='center', bold=True, size_hint_y=None, valign='top') self.ids.ml.add_widget(content) def allMessageQuery(self, start_indx, end_indx): @@ -2483,12 +2379,12 @@ class Allmails(Screen): """Delete inbox mail from all mail listing""" if folder == 'inbox': sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", str( - unique_id)) + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", + str(unique_id)) else: sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", str( - unique_id)) + "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", + str(unique_id)) self.ids.ml.remove_widget(instance.parent.parent) try: msg_count_objs = self.parent.parent.parent.parent.parent.children[ @@ -2505,15 +2401,12 @@ class Allmails(Screen): nav_lay_obj.sc1.ids.ml.clear_widgets() nav_lay_obj.sc1.loadMessagelist(state.association) else: - msg_count_objs.send_cnt.badge_text = str( - int(state.sent_count) - 1) + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) nav_lay_obj.sc4.ids.ml.clear_widgets() nav_lay_obj.sc4.loadSent(state.association) - msg_count_objs.trash_cnt.badge_text = str( - int(state.trash_count) + 1) - msg_count_objs.allmail_cnt.badge_text = str( - int(state.all_count) - 1) + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) state.all_count = str(int(state.all_count) - 1) if int(state.all_count) <= 0: diff --git a/src/bitmessagekivy/uikivysignaler.py b/src/bitmessagekivy/uikivysignaler.py index cb9473e2..fe9c9884 100644 --- a/src/bitmessagekivy/uikivysignaler.py +++ b/src/bitmessagekivy/uikivysignaler.py @@ -1,12 +1,15 @@ - +""" +Ui Singnaler for kivy interface +""" from threading import Thread -import state + import queues +import state from semaphores import kivyuisignaler -from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure class UIkivySignaler(Thread): + """Kivy ui signaler""" def run(self): kivyuisignaler.acquire() @@ -14,13 +17,12 @@ class UIkivySignaler(Thread): try: command, data = queues.UISignalQueue.get() if command == 'writeNewAddressToTable': - label, address, streamNumber = data + address = data[1] state.kivyapp.variable_1.append(address) # elif command == 'rerenderAddressBook': # state.kivyapp.obj_1.refreshs() # Need to discuss this elif command == 'updateSentItemStatusByAckdata': state.kivyapp.status_dispatching(data) - except Exception as e: - print(e) + print e From 9119507b033372cdca432eb45c3d3d897455bd4b Mon Sep 17 00:00:00 2001 From: sandakersmann Date: Fri, 27 Dec 2019 18:23:02 +0100 Subject: [PATCH 263/306] Changed copyright year to 2020 --- COPYING | 2 +- LICENSE | 2 +- src/api.py | 2 +- src/bitmessagemain.py | 2 +- src/bitmessageqt/about.ui | 2 +- src/bitmessageqt/dialogs.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/COPYING b/COPYING index 2e0ae6c1..078bf213 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ Copyright (c) 2012-2016 Jonathan Warren -Copyright (c) 2012-2019 The Bitmessage Developers +Copyright (c) 2012-2020 The Bitmessage Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/LICENSE b/LICENSE index 3be738c0..6bb86242 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) Copyright (c) 2012-2016 Jonathan Warren -Copyright (c) 2012-2019 The Bitmessage Developers +Copyright (c) 2012-2020 The Bitmessage Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/src/api.py b/src/api.py index f9d0a518..3201fba5 100644 --- a/src/api.py +++ b/src/api.py @@ -2,7 +2,7 @@ # pylint: disable=too-many-statements # Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2019 The Bitmessage developers +# Copyright (c) 2012-2020 The Bitmessage developers """ This is not what you run to run the Bitmessage API. Instead, enable the API diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 176125cc..96885b5e 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -3,7 +3,7 @@ The PyBitmessage startup script """ # Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2019 The Bitmessage developers +# Copyright (c) 2012-2020 The Bitmessage developers # Distributed under the MIT/X11 software license. See the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bitmessageqt/about.ui b/src/bitmessageqt/about.ui index a912927a..7073bbd1 100644 --- a/src/bitmessageqt/about.ui +++ b/src/bitmessageqt/about.ui @@ -46,7 +46,7 @@ - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2019 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2020 The Bitmessage Developers</p></body></html> Qt::AlignLeft diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index b4bcd2fd..c667edb1 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -47,7 +47,7 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin): try: self.label_2.setText( self.label_2.text().replace( - '2019', str(last_commit.get('time').year) + '2020', str(last_commit.get('time').year) )) except AttributeError: pass From 168c4a5696510bb3c6256b519352a6b0413dd713 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 3 Dec 2019 12:59:27 +0100 Subject: [PATCH 264/306] Checkdeps fix - an exception can be triggered if too many requirements are fulfilled --- checkdeps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checkdeps.py b/checkdeps.py index 03782037..45dc2fc9 100755 --- a/checkdeps.py +++ b/checkdeps.py @@ -164,7 +164,7 @@ if (not compiler or prereqs) and OPSYS in PACKAGE_MANAGER: if not compiler: compilerToPackages() prereqToPackages() - if mandatory: + if prereqs and mandatory: sys.exit(1) else: print("All the dependencies satisfied, you can install PyBitmessage") From c35f48bd0bdd7581571be6ee111d6530c00246b8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 22 Sep 2019 15:35:10 +0300 Subject: [PATCH 265/306] Fix setting socksproxytype and return in proxyconfig_stem: socksproxytype is set to SOCKS5 temporary if proxyconfig succeeds. --- src/plugins/proxyconfig_stem.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index bdbfe8ca..e56aecc6 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -43,6 +43,7 @@ def connect_plugin(config): # pylint: disable=too-many-branches ): # remote proxy is choosen for outbound connections, # nothing to do here, but need to set socksproxytype to SOCKS5! + config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5') logwrite( 'sockshostname is set to remote address,' ' aborting stem proxy configuration') @@ -77,6 +78,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches logwrite('Started tor on port %s' % port) break + config.setTemp('bitmessagesettings', 'socksproxytype', 'SOCKS5') + if config.safeGetBoolean('bitmessagesettings', 'sockslisten'): # need a hidden service for inbound connections try: @@ -117,6 +120,5 @@ def connect_plugin(config): # pylint: disable=too-many-branches config.set( onionhostname, 'keytype', response.private_key_type) config.save() - config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5') - return True + return True From 44cb975a611dcca0f40f328f44f517962f013a52 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 18 Oct 2019 17:52:00 +0300 Subject: [PATCH 266/306] Fixed bug in plugin.get_plugins(), edited docstrings --- src/plugins/__init__.py | 7 +++++++ src/plugins/plugin.py | 27 ++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py index e69de29b..285009df 100644 --- a/src/plugins/__init__.py +++ b/src/plugins/__init__.py @@ -0,0 +1,7 @@ +""" +Simple plugin system based on setuptools +---------------------------------------- + + +""" +# .. include:: pybitmessage.plugins.plugin.rst diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index e671a73f..629de0a6 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -1,19 +1,28 @@ # -*- coding: utf-8 -*- """ -src/plugins/plugin.py -=================================== +Operating with plugins """ +import logging + import pkg_resources +logger = logging.getLogger('default') + + def get_plugins(group, point='', name=None, fallback=None): """ - Iterate through plugins (`connect_plugin` attribute of entry point) - which name starts with `point` or equals to `name`. - If `fallback` kwarg specified, plugin with that name yield last. + :param str group: plugin group + :param str point: plugin name prefix + :param name: exact plugin name + :param fallback: fallback plugin name + + Iterate through plugins (``connect_plugin`` attribute of entry point) + which name starts with ``point`` or equals to ``name``. + If ``fallback`` kwarg specified, plugin with that name yield last. """ for ep in pkg_resources.iter_entry_points('bitmessage.' + group): - if name and ep.name == name or ep.name.startswith(point): + if name and ep.name == name or not point or ep.name.startswith(point): try: plugin = ep.load().connect_plugin if ep.name == fallback: @@ -25,6 +34,8 @@ def get_plugins(group, point='', name=None, fallback=None): ValueError, pkg_resources.DistributionNotFound, pkg_resources.UnknownExtra): + logger.debug( + 'Problem while loading %s', ep.name, exc_info=True) continue try: yield _fallback @@ -33,6 +44,8 @@ def get_plugins(group, point='', name=None, fallback=None): def get_plugin(*args, **kwargs): - """Returns first available plugin `from get_plugins()` if any.""" + """ + :return: first available plugin from :func:`get_plugins` if any. + """ for plugin in get_plugins(*args, **kwargs): return plugin From 5160a68c28a3493e4c0bb55a4169cef350e2058e Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 18 Oct 2019 17:52:44 +0300 Subject: [PATCH 267/306] Moved start_proxyconfig to helper_startup; no more prints in helper_startup --- src/bitmessagemain.py | 32 ++++++---------------------- src/helper_startup.py | 49 ++++++++++++++++++++++++++++++++++++------- src/tests/core.py | 9 ++++---- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 96885b5e..48ed9738 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -39,7 +39,8 @@ import shutdown from bmconfigparser import BMConfigParser from debug import logger # this should go before any threads from helper_startup import ( - isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections + isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections, + start_proxyconfig ) from inventory import Inventory from knownnodes import readKnownNodes @@ -168,30 +169,9 @@ def signal_handler(signum, frame): class Main(object): """Main PyBitmessage class""" - @staticmethod - def start_proxyconfig(config): - """Check socksproxytype and start any proxy configuration plugin""" - proxy_type = config.safeGet('bitmessagesettings', 'socksproxytype') - if proxy_type not in ('none', 'SOCKS4a', 'SOCKS5'): - # pylint: disable=relative-import - from plugins.plugin import get_plugin - try: - proxyconfig_start = time.time() - if not get_plugin('proxyconfig', name=proxy_type)(config): - raise TypeError - except TypeError: - logger.error( - 'Failed to run proxy config plugin %s', - proxy_type, exc_info=True) - shutdown.doCleanShutdown() - sys.exit(2) - else: - logger.info( - 'Started proxy config plugin %s in %s sec', - proxy_type, time.time() - proxyconfig_start) - - def start(self): # pylint: disable=too-many-statements, too-many-branches, too-many-locals + def start(self): """Start main application""" + # pylint: disable=too-many-statements,too-many-branches,too-many-locals _fixSocket() config = BMConfigParser() @@ -350,7 +330,7 @@ class Main(object): # start network components if networking is enabled if state.enableNetwork: - self.start_proxyconfig(config) + start_proxyconfig() BMConnectionPool() asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True @@ -410,7 +390,7 @@ class Main(object): self.stop() elif not state.enableGUI: from tests import core as test_core # pylint: disable=relative-import - test_core_result = test_core.run(self) + test_core_result = test_core.run() state.enableGUI = True self.stop() test_core.cleanup() diff --git a/src/helper_startup.py b/src/helper_startup.py index 9aaad5ef..9711c339 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -2,11 +2,12 @@ Startup operations. """ # pylint: disable=too-many-branches,too-many-statements -from __future__ import print_function +import logging import os import platform import sys +import time from distutils.version import StrictVersion import defaults @@ -15,6 +16,13 @@ import paths import state from bmconfigparser import BMConfigParser +try: + from plugins.plugin import get_plugin +except ImportError: + get_plugin = None + + +logger = logging.getLogger('default') # The user may de-select Portable Mode in the settings if they want # the config files to stay in the application data folder. @@ -30,14 +38,14 @@ def loadConfig(): needToCreateKeysFile = config.safeGet( 'bitmessagesettings', 'settingsversion') is None if not needToCreateKeysFile: - print( + logger.info( 'Loading config files from directory specified' - ' on startup: %s' % state.appdata) + ' on startup: %s', state.appdata) else: config.read(paths.lookupExeFolder() + 'keys.dat') try: config.get('bitmessagesettings', 'settingsversion') - print('Loading config files from same directory as program.') + logger.info('Loading config files from same directory as program.') needToCreateKeysFile = False state.appdata = paths.lookupExeFolder() except: @@ -48,7 +56,8 @@ def loadConfig(): needToCreateKeysFile = config.safeGet( 'bitmessagesettings', 'settingsversion') is None if not needToCreateKeysFile: - print('Loading existing config files from', state.appdata) + logger.info( + 'Loading existing config files from %s', state.appdata) if needToCreateKeysFile: @@ -103,9 +112,10 @@ def loadConfig(): # Just use the same directory as the program and forget about # the appdata folder state.appdata = '' - print('Creating new config files in same directory as program.') + logger.info( + 'Creating new config files in same directory as program.') else: - print('Creating new config files in', state.appdata) + logger.info('Creating new config files in %s', state.appdata) if not os.path.exists(state.appdata): os.makedirs(state.appdata) if not sys.platform.startswith('win'): @@ -255,7 +265,7 @@ def updateConfig(): 'bitmessagesettings', 'hidetrayconnectionnotifications', 'false') if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1: config.set('bitmessagesettings', 'maxoutboundconnections', '8') - print('WARNING: your maximum outbound connections must be a number.') + logger.warning('Your maximum outbound connections must be a number.') # TTL is now user-specifiable. Let's add an option to save # whatever the user selects. @@ -278,3 +288,26 @@ def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): return False except Exception: pass + + +def start_proxyconfig(): + """Check socksproxytype and start any proxy configuration plugin""" + if not get_plugin: + return + config = BMConfigParser() + proxy_type = config.safeGet('bitmessagesettings', 'socksproxytype') + if proxy_type and proxy_type not in ('none', 'SOCKS4a', 'SOCKS5'): + try: + proxyconfig_start = time.time() + if not get_plugin('proxyconfig', name=proxy_type)(config): + raise TypeError() + except TypeError: + # cannot import shutdown here ): + logger.error( + 'Failed to run proxy config plugin %s', + proxy_type, exc_info=True) + os._exit(0) # pylint: disable=protected-access + else: + logger.info( + 'Started proxy config plugin %s in %s sec', + proxy_type, time.time() - proxyconfig_start) diff --git a/src/tests/core.py b/src/tests/core.py index d2456064..84971dc5 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -14,6 +14,7 @@ import unittest import knownnodes import state from bmconfigparser import BMConfigParser +from helper_startup import start_proxyconfig from helper_msgcoding import MsgEncode, MsgDecode from network import asyncore_pollchoose as asyncore from network.connectionpool import BMConnectionPool @@ -21,8 +22,8 @@ from network.node import Peer from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection from queues import excQueue + knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat') -program = None def pickle_knownnodes(): @@ -196,14 +197,12 @@ class TestCore(unittest.TestCase): self._check_bootstrap() self._initiate_bootstrap() BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem') - program.start_proxyconfig(BMConfigParser()) + start_proxyconfig() self._check_bootstrap() -def run(prog): +def run(): """Starts all tests defined in this module""" - global program # pylint: disable=global-statement - program = prog loader = unittest.TestLoader() loader.sortTestMethodsUsing = None suite = loader.loadTestsFromTestCase(TestCore) From e3ccc3c7c8e4d3662adb8e20e20f1d8a32687e83 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 3 Oct 2019 18:34:27 +0300 Subject: [PATCH 268/306] Support for socksproxytype plugins in Settings dialog --- src/bitmessageqt/settings.py | 64 +++++++++++++++++++----------------- src/bitmessageqt/settings.ui | 4 +-- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 7fb0ea91..8fe1ecba 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -1,3 +1,4 @@ +import ConfigParser import os import sys @@ -16,6 +17,7 @@ import tempfile import widgets from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlStoredProcedure +from helper_startup import start_proxyconfig from network.asyncore_pollchoose import set_rates from tr import _translate @@ -32,6 +34,16 @@ class SettingsDialog(QtGui.QDialog): self.net_restart_needed = False self.timer = QtCore.QTimer() + try: + import pkg_resources + except ImportError: + pass + else: + # Append proxy types defined in plugins + for ep in pkg_resources.iter_entry_points( + 'bitmessage.proxyconfig'): + self.comboBoxProxyType.addItem(ep.name) + self.lineEditMaxOutboundConnections.setValidator( QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) @@ -117,21 +129,16 @@ class SettingsDialog(QtGui.QDialog): self.checkBoxOnionOnly.setChecked( config.safeGetBoolean('bitmessagesettings', 'onionservicesonly')) - proxy_type = config.safeGet( - 'bitmessagesettings', 'socksproxytype', 'none') - if proxy_type == 'none': - self.comboBoxProxyType.setCurrentIndex(0) - self.lineEditSocksHostname.setEnabled(False) - self.lineEditSocksPort.setEnabled(False) - self.lineEditSocksUsername.setEnabled(False) - self.lineEditSocksPassword.setEnabled(False) - self.checkBoxAuthentication.setEnabled(False) - self.checkBoxSocksListen.setEnabled(False) - self.checkBoxOnionOnly.setEnabled(False) - elif proxy_type == 'SOCKS4a': - self.comboBoxProxyType.setCurrentIndex(1) - elif proxy_type == 'SOCKS5': - self.comboBoxProxyType.setCurrentIndex(2) + try: + # Get real value, not temporary + self._proxy_type = ConfigParser.SafeConfigParser.get( + config, 'bitmessagesettings', 'socksproxytype') + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + self._proxy_type = 'none' + self.comboBoxProxyType.setCurrentIndex( + 0 if self._proxy_type == 'none' + else self.comboBoxProxyType.findText(self._proxy_type)) + self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex()) self.lineEditSocksHostname.setText( config.get('bitmessagesettings', 'sockshostname')) @@ -219,7 +226,7 @@ class SettingsDialog(QtGui.QDialog): self.checkBoxAuthentication.setEnabled(False) self.checkBoxSocksListen.setEnabled(False) self.checkBoxOnionOnly.setEnabled(False) - elif comboBoxIndex in (1, 2): + else: self.lineEditSocksHostname.setEnabled(True) self.lineEditSocksPort.setEnabled(True) self.checkBoxAuthentication.setEnabled(True) @@ -321,27 +328,22 @@ class SettingsDialog(QtGui.QDialog): upnpThread = upnp.uPnPThread() upnpThread.start() - proxy_type = self.config.safeGet( - 'bitmessagesettings', 'socksproxytype', 'none') - if ( - proxy_type == 'none' and - self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' and - shared.statusIconColor != 'red' - ): - self.net_restart_needed = True - if ( - proxy_type[0:5] == 'SOCKS' and - self.comboBoxProxyType.currentText()[0:5] != 'SOCKS' - ): + proxytype_index = self.comboBoxProxyType.currentIndex() + if proxytype_index == 0: + if self._proxy_type != 'none' and shared.statusIconColor != 'red': + self.net_restart_needed = True + elif self.comboBoxProxyType.currentText() != self._proxy_type: self.net_restart_needed = True self.parent.statusbar.clearMessage() self.config.set( 'bitmessagesettings', 'socksproxytype', - str(self.comboBoxProxyType.currentText()) - if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' - else 'none' + 'none' if self.comboBoxProxyType.currentIndex() == 0 + else str(self.comboBoxProxyType.currentText()) ) + if proxytype_index > 2: # last literal proxytype in ui + start_proxyconfig() + self.config.set('bitmessagesettings', 'socksauthentication', str( self.checkBoxAuthentication.isChecked())) self.config.set('bitmessagesettings', 'sockshostname', str( diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 33278e94..0ffbf442 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -419,12 +419,12 @@ - SOCKS4a + SOCKS4a - SOCKS5 + SOCKS5 From 2bddae511a84fae6c4830ce7903e442c77de5673 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 21 Oct 2019 15:20:29 +0300 Subject: [PATCH 269/306] Fixed some mistakes in tor dependent tests and marked them for skipping until the finish of debug. --- requirements.txt | 1 - src/tests/core.py | 48 +++++++++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/requirements.txt b/requirements.txt index be429a9f..c55e5cf1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ python_prctl psutil pycrypto -stem diff --git a/src/tests/core.py b/src/tests/core.py index 84971dc5..d56076c3 100644 --- a/src/tests/core.py +++ b/src/tests/core.py @@ -14,14 +14,19 @@ import unittest import knownnodes import state from bmconfigparser import BMConfigParser -from helper_startup import start_proxyconfig from helper_msgcoding import MsgEncode, MsgDecode +from helper_startup import start_proxyconfig from network import asyncore_pollchoose as asyncore from network.connectionpool import BMConnectionPool from network.node import Peer from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection from queues import excQueue +try: + import stem.version as stem_version +except ImportError: + stem_version = None + knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat') @@ -171,12 +176,29 @@ class TestCore(unittest.TestCase): self.assertIsInstance(con, connection_base) self.assertNotEqual(peer.host, '127.0.0.1') return - else: # pylint: disable=useless-else-on-loop - self.fail( - 'Failed to connect during %s sec' % (time.time() - _started)) + self.fail( + 'Failed to connect during %s sec' % (time.time() - _started)) - def test_onionservicesonly(self): - """test onionservicesonly networking mode""" + def test_bootstrap(self): + """test bootstrapping""" + self._initiate_bootstrap() + self._check_bootstrap() + + @unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test') + def test_bootstrap_tor(self): + """test bootstrapping with tor""" + self._initiate_bootstrap() + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem') + start_proxyconfig() + self._check_bootstrap() + + @unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test') + def test_onionservicesonly(self): # this should start after bootstrap + """ + set onionservicesonly, wait for 3 connections and check them all + are onions + """ + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5') BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true') self._initiate_bootstrap() BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') @@ -185,21 +207,15 @@ class TestCore(unittest.TestCase): for n, peer in enumerate(BMConnectionPool().outboundConnections): if n > 2: return - if not peer.host.endswith('.onion'): + if ( + not peer.host.endswith('.onion') + and not peer.host.startswith('bootstrap') + ): self.fail( 'Found non onion hostname %s in outbound connections!' % peer.host) self.fail('Failed to connect to at least 3 nodes within 360 sec') - def test_bootstrap(self): - """test bootstrapping""" - self._initiate_bootstrap() - self._check_bootstrap() - self._initiate_bootstrap() - BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem') - start_proxyconfig() - self._check_bootstrap() - def run(): """Starts all tests defined in this module""" From 52d5c1ff03707829b5055ef71015c0da369fb09d Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 22 Oct 2019 10:10:41 +0300 Subject: [PATCH 270/306] Document proxyconfig_stem --- src/plugins/proxyconfig_stem.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index e56aecc6..cbc6395d 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -1,7 +1,15 @@ # -*- coding: utf-8 -*- """ -src/plugins/proxyconfig_stem.py -=================================== +Configure tor proxy and hidden service with +`stem `_ depending on *bitmessagesettings*: + + * try to start own tor instance on *socksport* if *sockshostname* + is unset or set to localhost; + * if *socksport* is already in use that instance is used only for + hidden service (if *sockslisten* is also set True); + * create ephemeral hidden service v3 if there is already *onionhostname*; + * otherwise use stem's 'BEST' version and save onion keys to the new + section using *onionhostname* as name for future use. """ import os import logging @@ -36,10 +44,16 @@ class DebugLogger(object): def connect_plugin(config): # pylint: disable=too-many-branches - """Run stem proxy configurator""" + """ + Run stem proxy configurator + + :param config: current configuration instance + :type config: :class:`pybitmessage.bmconfigparser.BMConfigParser` + :return: True if configuration was done successfully + """ logwrite = DebugLogger() - if config.safeGet('bitmessagesettings', 'sockshostname') not in ( - 'localhost', '127.0.0.1', '' + if config.safeGet('bitmessagesettings', 'sockshostname', '') not in ( + 'localhost', '127.0.0.1', '' ): # remote proxy is choosen for outbound connections, # nothing to do here, but need to set socksproxytype to SOCKS5! From 1c4d7655c3a58e067db4a872b747fe5a39c3c181 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 7 Dec 2019 21:33:30 +0200 Subject: [PATCH 271/306] Fix socksproxytype in the support message, made that a separate function getSOCKSProxyType(config) in the settings. --- src/bitmessageqt/settings.py | 24 ++++++++++++++++-------- src/bitmessageqt/support.py | 4 ++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 8fe1ecba..011d38ed 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -22,6 +22,19 @@ from network.asyncore_pollchoose import set_rates from tr import _translate +def getSOCKSProxyType(config): + """Get user socksproxytype setting from *config*""" + try: + result = ConfigParser.SafeConfigParser.get( + config, 'bitmessagesettings', 'socksproxytype') + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return + else: + if result.lower() in ('', 'none', 'false'): + result = None + return result + + class SettingsDialog(QtGui.QDialog): """The "Settings" dialog""" def __init__(self, parent=None, firstrun=False): @@ -129,14 +142,9 @@ class SettingsDialog(QtGui.QDialog): self.checkBoxOnionOnly.setChecked( config.safeGetBoolean('bitmessagesettings', 'onionservicesonly')) - try: - # Get real value, not temporary - self._proxy_type = ConfigParser.SafeConfigParser.get( - config, 'bitmessagesettings', 'socksproxytype') - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): - self._proxy_type = 'none' + self._proxy_type = getSOCKSProxyType(config) self.comboBoxProxyType.setCurrentIndex( - 0 if self._proxy_type == 'none' + 0 if not self._proxy_type else self.comboBoxProxyType.findText(self._proxy_type)) self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex()) @@ -330,7 +338,7 @@ class SettingsDialog(QtGui.QDialog): proxytype_index = self.comboBoxProxyType.currentIndex() if proxytype_index == 0: - if self._proxy_type != 'none' and shared.statusIconColor != 'red': + if self._proxy_type and shared.statusIconColor != 'red': self.net_restart_needed = True elif self.comboBoxProxyType.currentText() != self._proxy_type: self.net_restart_needed = True diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 2a1ddb18..d6d4543d 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -15,6 +15,7 @@ from openclpow import openclAvailable, openclEnabled import paths import proofofwork from pyelliptic.openssl import OpenSSL +from settings import getSOCKSProxyType import queues import network.stats import state @@ -118,8 +119,7 @@ def createSupportMessage(myapp): BMConfigParser().safeGet('bitmessagesettings', 'opencl') ) if openclEnabled() else "None" locale = getTranslationLanguage() - socks = BMConfigParser().safeGet( - 'bitmessagesettings', 'socksproxytype', "N/A") + socks = getSOCKSProxyType(BMConfigParser()) or "N/A" upnp = BMConfigParser().safeGet('bitmessagesettings', 'upnp', "N/A") connectedhosts = len(network.stats.connectedHostsList()) From 61f64f72c36b315ef8663176d6cc2474af4457ea Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 20 Dec 2019 10:53:31 +0200 Subject: [PATCH 272/306] Fixing port for hidden service --- src/plugins/proxyconfig_stem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index cbc6395d..494519f2 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -112,7 +112,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches onionkeytype = config.safeGet(onionhostname, 'keytype') response = controller.create_ephemeral_hidden_service( - config.safeGetInt('bitmessagesettings', 'onionport', 8444), + {config.safeGetInt('bitmessagesettings', 'onionport', 8444): + config.safeGetInt('bitmessagesettings', 'port', 8444)}, key_type=(onionkeytype or 'NEW'), key_content=(onionkey or onionhostname and 'ED25519-V3' or 'BEST') ) From d9ef4a8e8dede2de1c47998ba05584d6d2a64dcf Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 27 Dec 2019 18:02:43 +0530 Subject: [PATCH 273/306] fix spelling mistakes --- LICENSE | 4 ++-- android_instruction.rst | 4 ++-- checkdeps.py | 2 +- docs/contribute.dir/develop.dir/opsec.rst | 4 ++-- docs/contribute.dir/develop.dir/overview.rst | 8 ++++---- fabfile/README.md | 4 ++-- packages/README.md | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index 6bb86242..d6df32b5 100644 --- a/LICENSE +++ b/LICENSE @@ -22,7 +22,7 @@ SOFTWARE. ===== qidenticon.py identicon python implementation with QPixmap output by sendiulo -qidenticon.py is Licesensed under FreeBSD License. +qidenticon.py is Licensed under FreeBSD License. (http://www.freebsd.org/copyright/freebsd-license.html) Copyright 2013 "Sendiulo". All rights reserved. @@ -36,7 +36,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR I ===== based on identicon.py identicon python implementation. by Shin Adachi -identicon.py is Licesensed under FreeBSD License. +identicon.py is Licensed under FreeBSD License. (http://www.freebsd.org/copyright/freebsd-license.html) Copyright 1994-2009 Shin Adachi. All rights reserved. diff --git a/android_instruction.rst b/android_instruction.rst index fab55b55..e6c7797d 100644 --- a/android_instruction.rst +++ b/android_instruction.rst @@ -1,6 +1,6 @@ PyBitmessage(Android) -This sample aims to be as close to a real world example of a mobile. It has a more refined design and also provides a practical example of how a mobile app would interact and communicate with its adresses. +This sample aims to be as close to a real world example of a mobile. It has a more refined design and also provides a practical example of how a mobile app would interact and communicate with its addresses. Steps for trying out this sample: @@ -13,7 +13,7 @@ This sample uses the kivy as Kivy is an open source, cross-platform Python frame Kivy is written in Python and Cython, supports various input devices and has an extensive widget library. With the same codebase, you can target Windows, OS X, Linux, Android and iOS. All Kivy widgets are built with multitouch support. -Kivy in support take Buildozer which is a tool that automates the entire build process. It downloads and sets up all the prequisites for python-for-android, including the android SDK and NDK, then builds an apk that can be automatically pushed to the device. +Kivy in support take Buildozer which is a tool that automates the entire build process. It downloads and sets up all the prerequisite for python-for-android, including the android SDK and NDK, then builds an apk that can be automatically pushed to the device. Buildozer currently works only in Linux, and is an alpha release, but it already works well and can significantly simplify the apk build. diff --git a/checkdeps.py b/checkdeps.py index 45dc2fc9..c3dedc1d 100755 --- a/checkdeps.py +++ b/checkdeps.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 """ -Check dependendies and give recommendations about how to satisfy them +Check dependencies and give recommendations about how to satisfy them Limitations: diff --git a/docs/contribute.dir/develop.dir/opsec.rst b/docs/contribute.dir/develop.dir/opsec.rst index 87bf4f49..1af43668 100644 --- a/docs/contribute.dir/develop.dir/opsec.rst +++ b/docs/contribute.dir/develop.dir/opsec.rst @@ -21,12 +21,12 @@ If we are to make bold claims about protecting your privacy we should demonstrat - looking to audit - warrant canary -Digital foootprint +Digital footprint ------------------ Your internet use can reveal metadata you wouldn't expect. This can be connected with other information about you if you're not careful. - * Use separate addresses for different puprose + * Use separate addresses for different purposes * Don't make the same mistakes all the time * Your language use is unique. The more you type, the more you fingerprint yourself. The words you know and use often vs the words you don't know or use often. diff --git a/docs/contribute.dir/develop.dir/overview.rst b/docs/contribute.dir/develop.dir/overview.rst index 342c9dbb..8bbc8299 100644 --- a/docs/contribute.dir/develop.dir/overview.rst +++ b/docs/contribute.dir/develop.dir/overview.rst @@ -11,17 +11,17 @@ Bitmessage makes use of fabric_ to define tasks such as building documentation o Code style and linters ---------------------- -We aim to be PEP8 compliant but we recognise that we have a long way still to go. Currently we have style and lint exceptions specified at the most specific place we can. We are ignoring certain issues project-wide in order to avoid alert-blindess, avoid style and lint regressions and to allow continuous integration to hook into the output from the tools. While it is hoped that all new changes pass the checks, fixing some existing violations are mini-projects in themselves. Current thinking on ignorable violations is reflected in the options and comments in setup.cfg. Module and line-level lint warnings represent refactoring opportunities. +We aim to be PEP8 compliant but we recognize that we have a long way still to go. Currently we have style and lint exceptions specified at the most specific place we can. We are ignoring certain issues project-wide in order to avoid alert-blindness, avoid style and lint regressions and to allow continuous integration to hook into the output from the tools. While it is hoped that all new changes pass the checks, fixing some existing violations are mini-projects in themselves. Current thinking on ignorable violations is reflected in the options and comments in setup.cfg. Module and line-level lint warnings represent refactoring opportunities. Pull requests ------------- -There is a template at PULL_REQUEST_TEMPLATE.md that appears in the pull-request description. Please replace this text with something appropriate to your changes based off the ideas in the template. +There is a template at PULL_REQUEST_TEMPLATE.md that appears in the pull-request description. Please replace this text with something appropriate to your changes based on the ideas in the template. Bike-shedding ------------- -Beyond having well-documented, Pythonic code with static analysis tool checks, extensive test coverage and powerful devops tools, what else can we have? Without violating any linters there is room for making arbirary decisions solely for the sake of project consistency. These are the stuff of the pedant's PR comments. Rather than have such conversations in PR comments, we can lay out the result of discussion here. +Beyond having well-documented, Pythonic code with static analysis tool checks, extensive test coverage and powerful devops tools, what else can we have? Without violating any linters there is room for making arbitrary decisions solely for the sake of project consistency. These are the stuff of the pedant's PR comments. Rather than have such conversations in PR comments, we can lay out the result of discussion here. I'm putting up a strawman for each topic here, mostly based on my memory of reading related Stack Overflow articles etc. If contributors feel strongly (and we don't have anything better to do) then maybe we can convince each other to update this section. @@ -49,7 +49,7 @@ British vs American spelling Dependency graph ---------------- -These images are not very useful right now but the aim is to tweak the settings of one or more of them to be informative, and/or divide them up into smaller grapghs. +These images are not very useful right now but the aim is to tweak the settings of one or more of them to be informative, and/or divide them up into smaller graphs. To re-build them, run `fab build_docs:dep_graphs=true`. Note that the dot graph takes a lot of time. diff --git a/fabfile/README.md b/fabfile/README.md index 643aed8e..5e90147c 100644 --- a/fabfile/README.md +++ b/fabfile/README.md @@ -1,6 +1,6 @@ # Fabric -[Fabric](https://www.fabfile.org) is a Python library for performing devops tasks. You can thing of it a bit like a +[Fabric](https://www.fabfile.org) is a Python library for performing devops tasks. You can think of it a bit like a makefile on steroids for Python. Its api abstracts away the clunky way you would run shell commands in Python, check return values and manage stdio. Tasks may be targetted at particular hosts or group of hosts. @@ -46,7 +46,7 @@ Furthermore, you can use -- to run arbitrary shell commands rather than tasks: There are a number of advantages that should benefit us: - * Common tasks can be writen in Python and executed consistently + * Common tasks can be written in Python and executed consistently * Common tasks are now under source control * All developers can run the same commands, if the underlying command sequence for a task changes (after review, obv) the user does not have to care diff --git a/packages/README.md b/packages/README.md index ed2df3cc..2905ec20 100644 --- a/packages/README.md +++ b/packages/README.md @@ -15,7 +15,7 @@ OSX: https://github.com/Bitmessage/PyBitmessage/releases -Wors on OSX 10.7.5 or higher +Works on OSX 10.7.5 or higher Arch linux: From 21ae6cb9b00a17eb084ab994e5e6d4bed462f980 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 27 Dec 2019 19:42:57 +0530 Subject: [PATCH 274/306] curses fixes --- src/bitmessagecurses/__init__.py | 186 ++++++++++++++++--------------- 1 file changed, 96 insertions(+), 90 deletions(-) diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 80dc3f14..d8daeef7 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -1,8 +1,6 @@ """ -src/bitmessagecurses/__init__.py -================================ +Bitmessage commandline interface """ - # Copyright (c) 2014 Luke Montalvo # This file adds a alternative commandline interface, feel free to critique and fork # @@ -20,21 +18,22 @@ import time from textwrap import fill from threading import Timer -from addresses import addBMIfNotPresent, decodeAddress -from bmconfigparser import BMConfigParser from dialog import Dialog -from helper_ackPayload import genAckPayload -from helper_sql import sqlExecute, sqlQuery -from inventory import Inventory import l10n import network.stats -from pyelliptic.openssl import OpenSSL import queues import shared import shutdown +from addresses import addBMIfNotPresent, decodeAddress +from bmconfigparser import BMConfigParser +from helper_ackPayload import genAckPayload +from helper_sql import sqlExecute, sqlQuery +from inventory import Inventory +# pylint: disable=global-statement -quit = False # pylint: disable=redefined-builtin + +quit_ = False menutab = 1 menu = ["Inbox", "Send", "Sent", "Your Identities", "Subscriptions", "Address Book", "Blacklist", "Network Status"] naptime = 100 @@ -61,26 +60,31 @@ bwtype = "black" BROADCAST_STR = "[Broadcast subscribers]" -class printLog: # pylint: disable=no-self-use, no-init, old-style-class +class printLog(object): """Printing logs""" + # pylint: disable=no-self-use def write(self, output): - # pylint: disable=global-statement + """Write logs""" global log log += output def flush(self): + """Flush logs""" pass -class errLog: # pylint: disable=no-self-use, no-init, old-style-class +class errLog(object): """Error logs""" + # pylint: disable=no-self-use + def write(self, output): - # pylint: disable=global-statement + """Write error logs""" global log log += "!" + output def flush(self): + """Flush error logs""" pass @@ -138,14 +142,15 @@ def scrollbox(d, text, height=None, width=None): def resetlookups(): """Reset the Inventory Lookups""" - global inventorydata # pylint: disable=global-statement + global inventorydata inventorydata = Inventory().numberOfInventoryLookupsPerformed Inventory().numberOfInventoryLookupsPerformed = 0 Timer(1, resetlookups, ()).start() -def drawtab(stdscr): # pylint: disable=too-many-branches, too-many-statements +def drawtab(stdscr): """Method for drawing different tabs""" + # pylint: disable=too-many-branches, too-many-statements if menutab in range(1, len(menu) + 1): if menutab == 1: # Inbox stdscr.addstr(3, 5, "To", curses.A_BOLD) @@ -282,12 +287,12 @@ def drawtab(stdscr): # pylint: disable=too-many-branches, too-many-statem stdscr.addstr(13, 6, "Log", curses.A_BOLD) n = log.count('\n') if n > 0: - l = log.split('\n') + lg = log.split('\n') if n > 512: - del l[:(n - 256)] + del lg[:(n - 256)] logpad.erase() - n = len(l) - for i, item in enumerate(l): + n = len(lg) + for i, item in enumerate(lg): a = 0 if item and item[0] == '!': a = curses.color_pair(1) @@ -314,7 +319,8 @@ def dialogreset(stdscr): # pylint: disable=too-many-branches, too-many-statements def handlech(c, stdscr): - # pylint: disable=redefined-outer-name, too-many-nested-blocks, too-many-locals, global-statement + """Handle character given on the command-line interface""" + # pylint: disable=redefined-outer-name, too-many-nested-blocks, too-many-locals if c != curses.ERR: global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur if c in range(256): @@ -322,8 +328,8 @@ def handlech(c, stdscr): global menutab menutab = int(chr(c)) elif chr(c) == 'q': - global quit - quit = True + global quit_ + quit_ = True elif chr(c) == '\n': curses.curs_set(1) d = Dialog(dialog="dialog") @@ -363,10 +369,10 @@ def handlech(c, stdscr): inbox[inboxcur][7] = 1 else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "2": # Mark unread + elif t == "2": # Mark unread sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", inbox[inboxcur][0]) inbox[inboxcur][7] = 0 - elif t == "3": # Reply + elif t == "3": # Reply curses.curs_set(1) m = inbox[inboxcur] fromaddr = m[4] @@ -375,7 +381,7 @@ def handlech(c, stdscr): if fromaddr == item[2] and item[3] != 0: ischan = True break - if not addresses[i][1]: # pylint: disable=undefined-loop-variable + if not addresses[i][1]: # pylint: disable=undefined-loop-variable scrollbox(d, unicode( "Sending address disabled, please either enable it" "or choose a different address.")) @@ -396,7 +402,7 @@ def handlech(c, stdscr): sendMessage(fromaddr, toaddr, ischan, subject, body, True) dialogreset(stdscr) - elif t == "4": # Add to Address Book + elif t == "4": # Add to Address Book addr = inbox[inboxcur][4] if addr not in [item[1] for i, item in enumerate(addrbook)]: r, t = d.inputbox("Label for address \"" + addr + "\"") @@ -409,7 +415,7 @@ def handlech(c, stdscr): addrbook.reverse() else: scrollbox(d, unicode("The selected address is already in the Address Book.")) - elif t == "5": # Save message + elif t == "5": # Save message set_background_title(d, "Save \"" + inbox[inboxcur][5] + "\" as text file") r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt") if r == d.DIALOG_OK: @@ -418,12 +424,12 @@ def handlech(c, stdscr): if ret != []: for row in ret: msg, = row - fh = open(t, "a") # Open in append mode just in case + fh = open(t, "a") # Open in append mode just in case fh.write(msg) fh.close() else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "6": # Move to trash + elif t == "6": # Move to trash sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", inbox[inboxcur][0]) del inbox[inboxcur] scrollbox(d, unicode( @@ -431,7 +437,7 @@ def handlech(c, stdscr): " \nbut the message is still on disk if you are desperate to recover it.")) elif menutab == 2: a = "" - if addresses[addrcur][3] != 0: # if current address is a chan + if addresses[addrcur][3] != 0: # if current address is a chan a = addresses[addrcur][2] sendMessage(addresses[addrcur][2], a) elif menutab == 3: @@ -467,7 +473,7 @@ def handlech(c, stdscr): scrollbox(d, unicode(ascii(msg)), 30, 80) else: scrollbox(d, unicode("Could not fetch message.")) - elif t == "2": # Move to trash + elif t == "2": # Move to trash sqlExecute( "UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?", sentbox[sentcur][4], @@ -495,7 +501,7 @@ def handlech(c, stdscr): ("6", "Delete"), ("7", "Special address behavior")]) if r == d.DIALOG_OK: - if t == "1": # Create new address + if t == "1": # Create new address set_background_title(d, "Create new address") scrollbox( d, unicode( @@ -598,12 +604,12 @@ def handlech(c, stdscr): str(passphrase), shorten)) else: scrollbox(d, unicode("Passphrases do not match")) - elif t == "2": # Send a message + elif t == "2": # Send a message a = "" - if addresses[addrcur][3] != 0: # if current address is a chan + if addresses[addrcur][3] != 0: # if current address is a chan a = addresses[addrcur][2] sendMessage(addresses[addrcur][2], a) - elif t == "3": # Rename address label + elif t == "3": # Rename address label a = addresses[addrcur][2] label = addresses[addrcur][0] r, t = d.inputbox("New address label", init=label) @@ -613,35 +619,35 @@ def handlech(c, stdscr): # Write config BMConfigParser().save() addresses[addrcur][0] = label - elif t == "4": # Enable address + elif t == "4": # Enable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "true") # Set config + BMConfigParser().set(a, "enabled", "true") # Set config # Write config BMConfigParser().save() # Change color if BMConfigParser().safeGetBoolean(a, 'chan'): - addresses[addrcur][3] = 9 # orange + addresses[addrcur][3] = 9 # orange elif BMConfigParser().safeGetBoolean(a, 'mailinglist'): - addresses[addrcur][3] = 5 # magenta + addresses[addrcur][3] = 5 # magenta else: - addresses[addrcur][3] = 0 # black + addresses[addrcur][3] = 0 # black addresses[addrcur][1] = True - shared.reloadMyAddressHashes() # Reload address hashes - elif t == "5": # Disable address + shared.reloadMyAddressHashes() # Reload address hashes + elif t == "5": # Disable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "false") # Set config - addresses[addrcur][3] = 8 # Set color to gray + BMConfigParser().set(a, "enabled", "false") # Set config + addresses[addrcur][3] = 8 # Set color to gray # Write config BMConfigParser().save() addresses[addrcur][1] = False - shared.reloadMyAddressHashes() # Reload address hashes - elif t == "6": # Delete address + shared.reloadMyAddressHashes() # Reload address hashes + elif t == "6": # Delete address r, t = d.inputbox("Type in \"I want to delete this address\"", width=50) if r == d.DIALOG_OK and t == "I want to delete this address": BMConfigParser().remove_section(addresses[addrcur][2]) BMConfigParser().save() del addresses[addrcur] - elif t == "7": # Special address behavior + elif t == "7": # Special address behavior a = addresses[addrcur][2] set_background_title(d, "Special address behavior") if BMConfigParser().safeGetBoolean(a, "chan"): @@ -658,9 +664,9 @@ def handlech(c, stdscr): if t == "1" and m: BMConfigParser().set(a, "mailinglist", "false") if addresses[addrcur][1]: - addresses[addrcur][3] = 0 # Set color to black + addresses[addrcur][3] = 0 # Set color to black else: - addresses[addrcur][3] = 8 # Set color to gray + addresses[addrcur][3] = 8 # Set color to gray elif t == "2" and m is False: try: mn = BMConfigParser().get(a, "mailinglistname") @@ -671,7 +677,7 @@ def handlech(c, stdscr): mn = t BMConfigParser().set(a, "mailinglist", "true") BMConfigParser().set(a, "mailinglistname", mn) - addresses[addrcur][3] = 6 # Set color to magenta + addresses[addrcur][3] = 6 # Set color to magenta # Write config BMConfigParser().save() elif menutab == 5: @@ -877,7 +883,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 10, 60) if r != d.DIALOG_OK: - global menutab # pylint: disable=global-statement + global menutab menutab = 6 return recv = t @@ -890,7 +896,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F if r != d.DIALOG_OK: return broadcast = False - if t == "2": # Broadcast + if t == "2": # Broadcast broadcast = True if subject == "" or reply: r, t = d.inputbox("Message subject", width=60, init=subject) @@ -906,9 +912,9 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F if not broadcast: recvlist = [] - for i, item in enumerate(recv.replace(",", ";").split(";")): + for _, item in enumerate(recv.replace(",", ";").split(";")): recvlist.append(item.strip()) - list(set(recvlist)) # Remove exact duplicates + list(set(recvlist)) # Remove exact duplicates for addr in recvlist: if addr != "": # pylint: disable=redefined-outer-name @@ -968,16 +974,16 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "msgqueued", - 0, # retryNumber + 0, # retryNumber "sent", - 2, # encodingType + 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) queues.workerQueue.put(("sendmessage", addr)) - else: # Broadcast + else: # Broadcast if recv == "": set_background_title(d, "Empty sender error") scrollbox(d, unicode("You must specify an address to send the message from.")) @@ -995,13 +1001,13 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "broadcastqueued", - 0, # retryNumber - "sent", # folder - 2, # encodingType + 0, # retryNumber + "sent", # folder + 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) queues.workerQueue.put(('sendbroadcast', '')) @@ -1039,12 +1045,12 @@ def loadInbox(): fromlabel = "" if BMConfigParser().has_section(fromaddr): fromlabel = BMConfigParser().get(fromaddr, "label") - if fromlabel == "": # Check Address Book + if fromlabel == "": # Check Address Book qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) if qr != []: for r in qr: fromlabel, = r - if fromlabel == "": # Check Subscriptions + if fromlabel == "": # Check Subscriptions qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", fromaddr) if qr != []: for r in qr: @@ -1170,7 +1176,7 @@ def loadSubscriptions(): def loadBlackWhiteList(): """load black/white list""" - global bwtype # pylint: disable=global-statement + global bwtype bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist") if bwtype == "black": ret = sqlQuery("SELECT label, address, enabled FROM blacklist") @@ -1183,10 +1189,10 @@ def loadBlackWhiteList(): def runwrapper(): + """Main method""" sys.stdout = printlog # sys.stderr = errlog - # Load messages from database loadInbox() loadSent() loadAddrBook() @@ -1195,7 +1201,7 @@ def runwrapper(): stdscr = curses.initscr() - global logpad # pylint: disable=global-statement + global logpad logpad = curses.newpad(1024, curses.COLS) stdscr.nodelay(0) @@ -1207,26 +1213,27 @@ def runwrapper(): def run(stdscr): + """Main loop""" # Schedule inventory lookup data resetlookups() # Init color pairs if curses.has_colors(): - curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) # red - curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) # green - curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) # yellow - curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK) # blue - curses.init_pair(5, curses.COLOR_MAGENTA, curses.COLOR_BLACK) # magenta - curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) # cyan - curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK) # white + curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) # red + curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) # green + curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) # yellow + curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK) # blue + curses.init_pair(5, curses.COLOR_MAGENTA, curses.COLOR_BLACK) # magenta + curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) # cyan + curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK) # white if curses.can_change_color(): - curses.init_color(8, 500, 500, 500) # gray + curses.init_color(8, 500, 500, 500) # gray curses.init_pair(8, 8, 0) - curses.init_color(9, 844, 465, 0) # orange + curses.init_color(9, 844, 465, 0) # orange curses.init_pair(9, 9, 0) else: - curses.init_pair(8, curses.COLOR_WHITE, curses.COLOR_BLACK) # grayish - curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish + curses.init_pair(8, curses.COLOR_WHITE, curses.COLOR_BLACK) # grayish + curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish # Init list of address in 'Your Identities' tab configSections = BMConfigParser().addresses() @@ -1235,18 +1242,18 @@ def run(stdscr): addresses.append([BMConfigParser().get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) # Set address color if not isEnabled: - addresses[len(addresses) - 1].append(8) # gray + addresses[len(addresses) - 1].append(8) # gray elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'): - addresses[len(addresses) - 1].append(9) # orange + addresses[len(addresses) - 1].append(9) # orange elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'): - addresses[len(addresses) - 1].append(5) # magenta + addresses[len(addresses) - 1].append(5) # magenta else: - addresses[len(addresses) - 1].append(0) # black + addresses[len(addresses) - 1].append(0) # black addresses.reverse() stdscr.clear() redraw(stdscr) - while quit is False: + while quit_ is False: drawtab(stdscr) handlech(stdscr.getch(), stdscr) @@ -1259,5 +1266,4 @@ def doShutdown(): shutdown.doCleanShutdown() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ - - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access From 4a369f70c1fe8907e84014dcd753a0d92efdc6e1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 23 Dec 2019 15:19:03 +0530 Subject: [PATCH 275/306] formatting and docstring --- src/class_objectProcessor.py | 12 +++++++----- src/class_smtpDeliver.py | 3 +-- src/helper_sent.py | 3 ++- src/multiqueue.py | 4 ++-- src/proofofwork.py | 3 +-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 2c741661..1a2f7751 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -149,11 +149,13 @@ class objectProcessor(threading.Thread): 'ackreceived', int(time.time()), data[readPosition:]) queues.UISignalQueue.put(( 'updateSentItemStatusByAckdata', - (data[readPosition:], - tr._translate( - "MainWindow", - "Acknowledgement of the message received %1" - ).arg(l10n.formatTimestamp())) + ( + data[readPosition:], + tr._translate( + "MainWindow", + "Acknowledgement of the message received %1" + ).arg(l10n.formatTimestamp()) + ) )) else: logger.debug('This object is not an acknowledgement bound for me.') diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 58cd4631..14df14c9 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -1,6 +1,5 @@ """ -src/class_smtpDeliver.py -======================== +SMTP client thread for delivering emails """ # pylint: disable=unused-variable diff --git a/src/helper_sent.py b/src/helper_sent.py index 5a345fe7..bc3362e8 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -2,7 +2,8 @@ Insert values into sent table """ -from helper_sql import * +from helper_sql import sqlExecute + def insert(t): """Perform an insert into the `sent` table""" diff --git a/src/multiqueue.py b/src/multiqueue.py index 8c64d33d..d7c10847 100644 --- a/src/multiqueue.py +++ b/src/multiqueue.py @@ -1,6 +1,6 @@ """ -src/multiqueue.py -================= +A queue with multiple internal subqueues. +Elements are added into a random subqueue, and retrieval rotates """ import Queue diff --git a/src/proofofwork.py b/src/proofofwork.py index bb16951c..e43e0f02 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -1,7 +1,6 @@ # pylint: disable=too-many-branches,too-many-statements,protected-access """ -src/proofofwork.py -================== +Proof of work calculation """ import ctypes From b16515dc09de901ab2d153588d01a3bf776c5a2b Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 15:13:03 +0530 Subject: [PATCH 276/306] arithmetic docstring and formatting --- src/pyelliptic/arithmetic.py | 28 +++++++++++++++++++++++----- src/pyelliptic/ecc.py | 3 +-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/pyelliptic/arithmetic.py b/src/pyelliptic/arithmetic.py index 95c85b93..83e634ad 100644 --- a/src/pyelliptic/arithmetic.py +++ b/src/pyelliptic/arithmetic.py @@ -1,5 +1,6 @@ -# pylint: disable=missing-docstring,too-many-function-args - +""" +Arithmetic Expressions +""" import hashlib import re @@ -11,6 +12,7 @@ G = (Gx, Gy) def inv(a, n): + """Inversion""" lm, hm = 1, 0 low, high = a % n, n while low > 1: @@ -21,6 +23,7 @@ def inv(a, n): def get_code_string(base): + """Returns string according to base value""" if base == 2: return '01' elif base == 10: @@ -36,6 +39,7 @@ def get_code_string(base): def encode(val, base, minlen=0): + """Returns the encoded string""" code_string = get_code_string(base) result = "" while val > 0: @@ -47,6 +51,7 @@ def encode(val, base, minlen=0): def decode(string, base): + """Returns the decoded string""" code_string = get_code_string(base) result = 0 if base == 16: @@ -59,10 +64,13 @@ def decode(string, base): def changebase(string, frm, to, minlen=0): + """Change base of the string""" return encode(decode(string, frm), to, minlen) def base10_add(a, b): + """Adding the numbers that are of base10""" + # pylint: disable=too-many-function-args if a is None: return b[0], b[1] if b is None: @@ -78,6 +86,7 @@ def base10_add(a, b): def base10_double(a): + """Double the numbers that are of base10""" if a is None: return None m = ((3 * a[0] * a[0] + A) * inv(2 * a[1], P)) % P @@ -87,6 +96,7 @@ def base10_double(a): def base10_multiply(a, n): + """Multiply the numbers that are of base10""" if n == 0: return G if n == 1: @@ -99,28 +109,35 @@ def base10_multiply(a, n): def hex_to_point(h): + """Converting hexadecimal to point value""" return (decode(h[2:66], 16), decode(h[66:], 16)) def point_to_hex(p): + """Converting point value to hexadecimal""" return '04' + encode(p[0], 16, 64) + encode(p[1], 16, 64) def multiply(privkey, pubkey): - return point_to_hex(base10_multiply(hex_to_point(pubkey), decode(privkey, 16))) + """Multiplying keys""" + return point_to_hex(base10_multiply( + hex_to_point(pubkey), decode(privkey, 16))) def privtopub(privkey): + """Converting key from private to public""" return point_to_hex(base10_multiply(G, decode(privkey, 16))) def add(p1, p2): + """Adding two public keys""" if len(p1) == 32: return encode(decode(p1, 16) + decode(p2, 16) % P, 16, 32) return point_to_hex(base10_add(hex_to_point(p1), hex_to_point(p2))) def hash_160(string): + """Hashed version of public key""" intermed = hashlib.sha256(string).digest() ripemd160 = hashlib.new('ripemd160') ripemd160.update(intermed) @@ -128,17 +145,18 @@ def hash_160(string): def dbl_sha256(string): + """Double hashing (SHA256)""" return hashlib.sha256(hashlib.sha256(string).digest()).digest() def bin_to_b58check(inp): + """Convert binary to base58""" inp_fmtd = '\x00' + inp leadingzbytes = len(re.match('^\x00*', inp_fmtd).group(0)) checksum = dbl_sha256(inp_fmtd)[:4] return '1' * leadingzbytes + changebase(inp_fmtd + checksum, 256, 58) -# Convert a public key (in hex) to a Bitcoin address - def pubkey_to_address(pubkey): + """Convert a public key (in hex) to a Bitcoin address""" return bin_to_b58check(hash_160(changebase(pubkey, 16, 256))) diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index 2de0bfe9..803a6de2 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -1,8 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -src/pyelliptic/ecc.py -===================== +Asymmetric cryptography using elliptic curves """ # pylint: disable=protected-access From 36c24cc09a44854203e9d3758b8f914a10d63876 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 15:13:29 +0530 Subject: [PATCH 277/306] cipher quality fixes --- src/pyelliptic/cipher.py | 10 ++++------ src/pyelliptic/ecc.py | 19 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index d02b743a..4057e169 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -1,10 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -src/pyelliptic/cipher.py -======================== +Symmetric Encryption """ - # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. @@ -14,7 +12,7 @@ from openssl import OpenSSL # pylint: disable=redefined-builtin class Cipher(object): """ - Symmetric encryption + Main class for encryption import pyelliptic iv = pyelliptic.Cipher.gen_IV('aes-256-cfb') @@ -67,7 +65,7 @@ class Cipher(object): if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer), OpenSSL.byref(i), inp, len(input)) == 0: raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...") - return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index + return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index def final(self): """Returning the final value""" @@ -76,7 +74,7 @@ class Cipher(object): if (OpenSSL.EVP_CipherFinal_ex(self.ctx, OpenSSL.byref(buffer), OpenSSL.byref(i))) == 0: raise Exception("[OpenSSL] EVP_CipherFinal_ex FAIL ...") - return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index + return buffer.raw[0:i.value] # pylint: disable=invalid-slice-index def ciphering(self, input): """ diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index 803a6de2..a7f5a6b7 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -3,8 +3,7 @@ """ Asymmetric cryptography using elliptic curves """ -# pylint: disable=protected-access - +# pylint: disable=protected-access, too-many-branches, too-many-locals # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. @@ -172,7 +171,8 @@ class ECC(object): if OpenSSL.EC_POINT_get_affine_coordinates_GFp( group, pub_key, pub_key_x, pub_key_y, 0) == 0: - raise Exception("[OpenSSL] EC_POINT_get_affine_coordinates_GFp FAIL ...") + raise Exception( + "[OpenSSL] EC_POINT_get_affine_coordinates_GFp FAIL ...") privkey = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(priv_key)) pubkeyx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(pub_key_x)) @@ -275,7 +275,6 @@ class ECC(object): def raw_check_key(self, privkey, pubkey_x, pubkey_y, curve=None): """Check key validity, key is supplied as binary data""" - # pylint: disable=too-many-branches if curve is None: curve = self.curve elif isinstance(curve, str): @@ -323,7 +322,6 @@ class ECC(object): """ Sign the input with ECDSA method and returns the signature """ - # pylint: disable=too-many-branches,too-many-locals try: size = len(inputb) buff = OpenSSL.malloc(inputb, size) @@ -393,7 +391,6 @@ class ECC(object): Verify the signature with the input and the local public key. Returns a boolean """ - # pylint: disable=too-many-branches try: bsig = OpenSSL.malloc(sig, len(sig)) binputb = OpenSSL.malloc(inputb, len(inputb)) @@ -436,10 +433,13 @@ class ECC(object): 0, digest, dgst_len.contents, bsig, len(sig), key) if ret == -1: - return False # Fail to Check + # Fail to Check + return False if ret == 0: - return False # Bad signature ! - return True # Good + # Bad signature ! + return False + # Good + return True finally: OpenSSL.EC_KEY_free(key) @@ -487,7 +487,6 @@ class ECC(object): """ Decrypt data with ECIES method using the local private key """ - # pylint: disable=too-many-locals blocksize = OpenSSL.get_cipher(ciphername).get_blocksize() iv = data[:blocksize] i = blocksize From 814aae5166b858f85af11b51ae27b666b24c7389 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 15:14:07 +0530 Subject: [PATCH 278/306] eccblind quality fixes --- src/pyelliptic/eccblind.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pyelliptic/eccblind.py b/src/pyelliptic/eccblind.py index 2ca2581a..5b9b045e 100644 --- a/src/pyelliptic/eccblind.py +++ b/src/pyelliptic/eccblind.py @@ -1,6 +1,7 @@ #!/usr/bin/env python """ -ECC blind signature functionality based on "An Efficient Blind Signature Scheme +ECC blind signature functionality based on +"An Efficient Blind Signature Scheme Based on the Elliptic CurveDiscrete Logarithm Problem" by Morteza Nikooghadama and Ali Zakerolhosseini , http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf @@ -8,7 +9,6 @@ http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pd # variable names are based on the math in the paper, so they don't conform # to PEP8 -# pylint: disable=invalid-name from .openssl import OpenSSL @@ -72,8 +72,7 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes # F = (x0, y0) x0 = OpenSSL.BN_new() y0 = OpenSSL.BN_new() - OpenSSL.EC_POINT_get_affine_coordinates_GFp(group, F, x0, y0, - ctx) + OpenSSL.EC_POINT_get_affine_coordinates_GFp(group, F, x0, y0, ctx) return x0 def __init__(self, curve="secp256k1", pubkey=None): @@ -82,7 +81,8 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes if pubkey: self.group, self.G, self.n, self.Q = pubkey else: - self.group = OpenSSL.EC_GROUP_new_by_curve_name(OpenSSL.get_curve(curve)) + self.group = OpenSSL.EC_GROUP_new_by_curve_name( + OpenSSL.get_curve(curve)) # Order n self.n = OpenSSL.BN_new() OpenSSL.EC_GROUP_get_order(self.group, self.n, self.ctx) From 8659c5313d54ea8c1f899f8a4e0bc8c02ae5dab3 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 15:14:31 +0530 Subject: [PATCH 279/306] openssl pylint issue fixes --- src/pyelliptic/openssl.py | 127 +++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 49 deletions(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 152a780c..f769f0e3 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -2,22 +2,20 @@ # See LICENSE for details. # # Software slightly changed by Jonathan Warren -# pylint: disable=protected-access """ This module loads openssl libs with ctypes and incapsulates needed openssl functionality in class _OpenSSL. """ - +# pylint: disable=protected-access import sys import ctypes OpenSSL = None -class CipherName: +class CipherName(object): """Class returns cipher name, pointer and blocksize""" - # pylint: disable=old-style-class def __init__(self, name, pointer, blocksize): self._name = name self._pointer = pointer @@ -73,11 +71,11 @@ def get_version(library): return (version, hexversion, cflags) -class _OpenSSL: +class _OpenSSL(object): """ Wrapper for OpenSSL using ctypes """ - # pylint: disable=too-many-statements, too-many-instance-attributes, old-style-class + # pylint: disable=too-many-statements, too-many-instance-attributes def __init__(self, library): """ Build the wrapper @@ -140,7 +138,8 @@ class _OpenSSL: self.EC_KEY_get0_group.restype = ctypes.c_void_p self.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] - self.EC_POINT_get_affine_coordinates_GFp = self._lib.EC_POINT_get_affine_coordinates_GFp + self.EC_POINT_get_affine_coordinates_GFp = \ + self._lib.EC_POINT_get_affine_coordinates_GFp self.EC_POINT_get_affine_coordinates_GFp.restype = ctypes.c_int self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, @@ -163,7 +162,8 @@ class _OpenSSL: self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - self.EC_POINT_set_affine_coordinates_GFp = self._lib.EC_POINT_set_affine_coordinates_GFp + self.EC_POINT_set_affine_coordinates_GFp = \ + self._lib.EC_POINT_set_affine_coordinates_GFp self.EC_POINT_set_affine_coordinates_GFp.restype = ctypes.c_int self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, @@ -297,7 +297,8 @@ class _OpenSSL: self.EVP_CipherUpdate = self._lib.EVP_CipherUpdate self.EVP_CipherUpdate.restype = ctypes.c_int self.EVP_CipherUpdate.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] + ctypes.c_void_p, ctypes.c_void_p, + ctypes.c_void_p, ctypes.c_int] self.EVP_CipherFinal_ex = self._lib.EVP_CipherFinal_ex self.EVP_CipherFinal_ex.restype = ctypes.c_int @@ -330,12 +331,14 @@ class _OpenSSL: self.ECDSA_sign = self._lib.ECDSA_sign self.ECDSA_sign.restype = ctypes.c_int self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + ctypes.c_int, ctypes.c_void_p, + ctypes.c_void_p, ctypes.c_void_p] self.ECDSA_verify = self._lib.ECDSA_verify self.ECDSA_verify.restype = ctypes.c_int self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] + ctypes.c_int, ctypes.c_void_p, + ctypes.c_int, ctypes.c_void_p] if self._hexversion >= 0x10100000 and not self._libreSSL: self.EVP_MD_CTX_new = self._lib.EVP_MD_CTX_new @@ -393,7 +396,8 @@ class _OpenSSL: self.HMAC = self._lib.HMAC self.HMAC.restype = ctypes.c_void_p self.HMAC.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, - ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] + ctypes.c_void_p, ctypes.c_int, + ctypes.c_void_p, ctypes.c_void_p] try: self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC @@ -530,17 +534,29 @@ class _OpenSSL: def _set_ciphers(self): self.cipher_algo = { - 'aes-128-cbc': CipherName('aes-128-cbc', self.EVP_aes_128_cbc, 16), - 'aes-256-cbc': CipherName('aes-256-cbc', self.EVP_aes_256_cbc, 16), - 'aes-128-cfb': CipherName('aes-128-cfb', self.EVP_aes_128_cfb128, 16), - 'aes-256-cfb': CipherName('aes-256-cfb', self.EVP_aes_256_cfb128, 16), - 'aes-128-ofb': CipherName('aes-128-ofb', self._lib.EVP_aes_128_ofb, 16), - 'aes-256-ofb': CipherName('aes-256-ofb', self._lib.EVP_aes_256_ofb, 16), - # 'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), - # 'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), - 'bf-cfb': CipherName('bf-cfb', self.EVP_bf_cfb64, 8), - 'bf-cbc': CipherName('bf-cbc', self.EVP_bf_cbc, 8), - 'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size + 'aes-128-cbc': CipherName( + 'aes-128-cbc', self.EVP_aes_128_cbc, 16), + 'aes-256-cbc': CipherName( + 'aes-256-cbc', self.EVP_aes_256_cbc, 16), + 'aes-128-cfb': CipherName( + 'aes-128-cfb', self.EVP_aes_128_cfb128, 16), + 'aes-256-cfb': CipherName( + 'aes-256-cfb', self.EVP_aes_256_cfb128, 16), + 'aes-128-ofb': CipherName( + 'aes-128-ofb', self._lib.EVP_aes_128_ofb, 16), + 'aes-256-ofb': CipherName( + 'aes-256-ofb', self._lib.EVP_aes_256_ofb, 16), + # 'aes-128-ctr': CipherName( + # 'aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), + # 'aes-256-ctr': CipherName( + # 'aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), + 'bf-cfb': CipherName( + 'bf-cfb', self.EVP_bf_cfb64, 8), + 'bf-cbc': CipherName( + 'bf-cbc', self.EVP_bf_cbc, 8), + # 128 is the initialisation size not block size + 'rc4': CipherName( + 'rc4', self.EVP_rc4, 128), } def _set_curves(self): @@ -600,14 +616,13 @@ class _OpenSSL: raise Exception("Unknown curve") return self.curves[name] - def get_curve_by_id(self, id): + def get_curve_by_id(self, id_): """ returns the name of a elliptic curve with his id """ - # pylint: disable=redefined-builtin res = None for i in self.curves: - if self.curves[i] == id: + if self.curves[i] == id_: res = i break if res is None: @@ -618,32 +633,31 @@ class _OpenSSL: """ OpenSSL random function """ - # pylint: disable=redefined-builtin - buffer = self.malloc(0, size) - # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is - # evidently possible that it returned an error and not-actually-random data. However, in - # tests on various operating systems, while generating hundreds of gigabytes of random - # strings of various sizes I could not get an error to occur. Also Bitcoin doesn't check - # the return value of RAND_bytes either. + buffer_ = self.malloc(0, size) + # This pyelliptic library, by default, didn't check the return value + # of RAND_bytes. It is evidently possible that it returned an error + # and not-actually-random data. However, in tests on various + # operating systems, while generating hundreds of gigabytes of random + # strings of various sizes I could not get an error to occur. + # Also Bitcoin doesn't check the return value of RAND_bytes either. # Fixed in Bitmessage version 0.4.2 (in source code on 2013-10-13) - while self.RAND_bytes(buffer, size) != 1: + while self.RAND_bytes(buffer_, size) != 1: import time time.sleep(1) - return buffer.raw + return buffer_.raw def malloc(self, data, size): """ returns a create_string_buffer (ctypes) """ - # pylint: disable=redefined-builtin - buffer = None + buffer_ = None if data != 0: if sys.version_info.major == 3 and isinstance(data, type('')): data = data.encode() - buffer = self.create_string_buffer(data, size) + buffer_ = self.create_string_buffer(data, size) else: - buffer = self.create_string_buffer(size) - return buffer + buffer_ = self.create_string_buffer(size) + return buffer_ def loadOpenSSL(): @@ -657,12 +671,24 @@ def loadOpenSSL(): if getattr(sys, 'frozen', None): if 'darwin' in sys.platform: libdir.extend([ - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.1.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.2.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.1.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.0.9.8.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.1.1.0.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.1.0.2.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.1.0.1.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.1.0.0.dylib'), + path.join( + environ['RESOURCEPATH'], '..', + 'Frameworks', 'libcrypto.0.9.8.dylib'), ]) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append(path.join(sys._MEIPASS, 'libeay32.dll')) @@ -682,7 +708,8 @@ def loadOpenSSL(): path.join(sys._MEIPASS, 'libssl.so.0.9.8'), ]) if 'darwin' in sys.platform: - libdir.extend(['libcrypto.dylib', '/usr/local/opt/openssl/lib/libcrypto.dylib']) + libdir.extend([ + 'libcrypto.dylib', '/usr/local/opt/openssl/lib/libcrypto.dylib']) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append('libeay32.dll') else: @@ -690,7 +717,8 @@ def loadOpenSSL(): libdir.append('libssl.so') libdir.append('libcrypto.so.1.0.0') libdir.append('libssl.so.1.0.0') - if 'linux' in sys.platform or 'darwin' in sys.platform or 'bsd' in sys.platform: + if 'linux' in sys.platform or 'darwin' in sys.platform \ + or 'bsd' in sys.platform: libdir.append(find_library('ssl')) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append(find_library('libeay32')) @@ -700,7 +728,8 @@ def loadOpenSSL(): return except: pass - raise Exception("Couldn't find and load the OpenSSL library. You must install it.") + raise Exception( + "Couldn't find and load the OpenSSL library. You must install it.") loadOpenSSL() From 624d96fbb943d18161974277d2f6e865353d4bec Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:43:52 +0530 Subject: [PATCH 280/306] indicator_libmessaging docstring and formatting --- src/plugins/indicator_libmessaging.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/indicator_libmessaging.py b/src/plugins/indicator_libmessaging.py index ab2e833e..60bf5e7e 100644 --- a/src/plugins/indicator_libmessaging.py +++ b/src/plugins/indicator_libmessaging.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """ -src/plugins/indicator_libmessaging.py -===================================== +Indicator plugin using libmessaging """ import gi @@ -37,7 +36,7 @@ class IndicatorLibmessaging(object): if self.app: self.app.unregister() - def activate(self, app, source): # pylint: disable=unused-argument + def activate(self, app, source): # pylint: disable=unused-argument """Activate the libmessaging indicator plugin""" self.form.appIndicatorInbox( self.new_message_item if source == 'messages' From 7b0bf845857a309dddd4ac22535ebfb57c47e090 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:44:13 +0530 Subject: [PATCH 281/306] menu_qrcode docstring and formatting --- src/plugins/menu_qrcode.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py index 2e65bd88..63644db6 100644 --- a/src/plugins/menu_qrcode.py +++ b/src/plugins/menu_qrcode.py @@ -1,8 +1,5 @@ # -*- coding: utf-8 -*- """ -src/plugins/menu_qrcode.py -========================== - A menu plugin showing QR-Code for bitmessage address in modal dialog. """ @@ -15,10 +12,11 @@ from pybitmessage.tr import _translate # http://stackoverflow.com/questions/20452486 -class Image(qrcode.image.base.BaseImage): # pylint: disable=abstract-method +class Image(qrcode.image.base.BaseImage): # pylint: disable=abstract-method """Image output class for qrcode using QPainter""" - def __init__(self, border, width, box_size): # pylint: disable=super-init-not-called + def __init__(self, border, width, box_size): + # pylint: disable=super-init-not-called self.border = border self.width = width self.box_size = box_size From ea50485de25b86bc430cc4e696929cba79e12863 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:44:33 +0530 Subject: [PATCH 282/306] notification_notify2 pylint fixes --- src/plugins/notification_notify2.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py index b4cd045d..84ecbdde 100644 --- a/src/plugins/notification_notify2.py +++ b/src/plugins/notification_notify2.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """ -src/plugins/notification_notify2.py -=================================== +Notification plugin using notify2 """ import gi @@ -11,7 +10,7 @@ from gi.repository import Notify Notify.init('pybitmessage') -def connect_plugin(title, subtitle, category, label, icon): +def connect_plugin(title, subtitle, category, _, icon): """Plugin for notify2""" if not icon: icon = 'mail-message-new' if category == 2 else 'pybitmessage' From e24f4de40e858a9828714fbf9b0dc6e082c697ef Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:45:29 +0530 Subject: [PATCH 283/306] proxyconfig_stem quality fixes --- src/plugins/proxyconfig_stem.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index 494519f2..bc760ef1 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -22,9 +22,8 @@ import stem.process import stem.version -class DebugLogger(object): +class DebugLogger(object): # pylint: disable=too-few-public-methods """Safe logger wrapper for tor and plugin's logs""" - # pylint: disable=too-few-public-methods def __init__(self): self._logger = logging.getLogger('default') self._levels = { @@ -108,7 +107,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches onionhostname = config.safeGet('bitmessagesettings', 'onionhostname') onionkey = config.safeGet(onionhostname, 'privsigningkey') if onionhostname and not onionkey: - logwrite('The hidden service found in config ): %s' % onionhostname) + logwrite('The hidden service found in config ): %s' % + onionhostname) onionkeytype = config.safeGet(onionhostname, 'keytype') response = controller.create_ephemeral_hidden_service( @@ -124,7 +124,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches if not onionkey: logwrite('Started hidden service %s.onion' % response.service_id) - # only save new service keys if onionhostname was not set previously + # only save new service keys + # if onionhostname was not set previously if not onionhostname: onionhostname = response.service_id + '.onion' config.set( From 208090ce5d1d9fe13b7635d1404343ef2a06eede Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:45:52 +0530 Subject: [PATCH 284/306] sound_canberra docstring and formatting --- src/plugins/sound_canberra.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/sound_canberra.py b/src/plugins/sound_canberra.py index dbb4baed..20bd054d 100644 --- a/src/plugins/sound_canberra.py +++ b/src/plugins/sound_canberra.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """ -src/plugins/proxyconfig_stem.py -=================================== +Sound theme plugin using pycanberra """ from pybitmessage.bitmessageqt import sound @@ -18,7 +17,7 @@ _theme = { } -def connect_plugin(category, label=None): # pylint: disable=unused-argument +def connect_plugin(category, label=None): # pylint: disable=unused-argument """This function implements the entry point.""" try: _canberra.play(0, pycanberra.CA_PROP_EVENT_ID, _theme[category], None) From 8338a9ee74f4579611bc2fc83998263f7e350cdd Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:46:12 +0530 Subject: [PATCH 285/306] sound_gstreamer docstring fixes --- src/plugins/sound_gstreamer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/sound_gstreamer.py b/src/plugins/sound_gstreamer.py index 32a0aa65..8f3606dd 100644 --- a/src/plugins/sound_gstreamer.py +++ b/src/plugins/sound_gstreamer.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """ -src/plugins/sound_gstreamer.py -=================================== +Sound notification plugin using gstreamer """ import gi gi.require_version('Gst', '1.0') From a31d6c8422aff2266416cc8fef1697f2120d463a Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 21 Dec 2019 12:46:31 +0530 Subject: [PATCH 286/306] sound_playfile quality fixes --- src/plugins/sound_playfile.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py index 6396c319..e36d9922 100644 --- a/src/plugins/sound_playfile.py +++ b/src/plugins/sound_playfile.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """ -src/plugins/sound_playfile.py -=================================== +Sound notification plugin using external executable or winsound (on Windows) """ try: @@ -23,7 +22,7 @@ except ImportError: def connect_plugin(sound_file): """This function implements the entry point.""" - global play_cmd # pylint: disable=global-statement + global play_cmd # pylint: disable=global-statement ext = os.path.splitext(sound_file)[-1] try: From 81872c7f2f8f092190f2bbd3a02f9c8065343e40 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 19 Dec 2019 16:54:53 +0530 Subject: [PATCH 287/306] network code quality fixes --- src/network/networkthread.py | 5 ++- src/network/objectracker.py | 27 ++++++++----- src/network/proxy.py | 6 +-- src/network/randomtrackingdict.py | 30 +++++++------- src/network/receivequeuethread.py | 11 +++++- src/network/socks4a.py | 3 +- src/network/socks5.py | 7 ++-- src/network/stats.py | 10 +++-- src/network/tcp.py | 25 ++++++------ src/network/tls.py | 65 +++++++++++++++++++------------ src/network/udp.py | 14 +++---- 11 files changed, 117 insertions(+), 86 deletions(-) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index ba560906..61ff6c09 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -1,3 +1,6 @@ +""" +A thread to handle network concerns +""" import network.asyncore_pollchoose as asyncore import state from network.connectionpool import BMConnectionPool @@ -6,7 +9,7 @@ from threads import StoppableThread class BMNetworkThread(StoppableThread): - """A thread to handle network concerns""" + """Main network thread""" name = "Asyncore" def run(self): diff --git a/src/network/objectracker.py b/src/network/objectracker.py index b97aee46..ca29c023 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -1,6 +1,5 @@ """ -src/network/objectracker.py -=========================== +Module for tracking objects """ import time from threading import RLock @@ -50,15 +49,18 @@ class ObjectTracker(object): """Init bloom filter for tracking. WIP.""" if haveBloom: # lock? - self.invBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, - error_rate=ObjectTracker.invErrorRate) + self.invBloom = BloomFilter( + capacity=ObjectTracker.invInitialCapacity, + error_rate=ObjectTracker.invErrorRate) def initAddrBloom(self): - """Init bloom filter for tracking addrs, WIP. This either needs to be moved to addrthread.py or removed.""" + """Init bloom filter for tracking addrs, WIP. + This either needs to be moved to addrthread.py or removed.""" if haveBloom: # lock? - self.addrBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, - error_rate=ObjectTracker.invErrorRate) + self.addrBloom = BloomFilter( + capacity=ObjectTracker.invInitialCapacity, + error_rate=ObjectTracker.invErrorRate) def clean(self): """Clean up tracking to prevent memory bloat""" @@ -71,7 +73,10 @@ class ObjectTracker(object): # release memory deadline = time.time() - ObjectTracker.trackingExpires with self.objectsNewToThemLock: - self.objectsNewToThem = {k: v for k, v in self.objectsNewToThem.iteritems() if v >= deadline} + self.objectsNewToThem = { + k: v + for k, v in self.objectsNewToThem.iteritems() + if v >= deadline} self.lastCleaned = time.time() def hasObj(self, hashid): @@ -102,10 +107,12 @@ class ObjectTracker(object): del i.objectsNewToMe[hashid] except KeyError: if streamNumber in i.streams and ( - not Dandelion().hasHash(hashid) or Dandelion().objectChildStem(hashid) == i): + not Dandelion().hasHash(hashid) or + Dandelion().objectChildStem(hashid) == i): with i.objectsNewToThemLock: i.objectsNewToThem[hashid] = time.time() - # update stream number, which we didn't have when we just received the dinv + # update stream number, + # which we didn't have when we just received the dinv # also resets expiration of the stem mode Dandelion().setHashStream(hashid, streamNumber) diff --git a/src/network/proxy.py b/src/network/proxy.py index e0bb5e78..38676d66 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -1,6 +1,5 @@ """ -src/network/proxy.py -==================== +Set proxy if avaiable otherwise exception """ # pylint: disable=protected-access import logging @@ -122,8 +121,7 @@ class Proxy(AdvancedDispatcher): BMConfigParser().safeGet( "bitmessagesettings", "socksusername"), BMConfigParser().safeGet( - "bitmessagesettings", "sockspassword") - ) + "bitmessagesettings", "sockspassword")) else: self.auth = None self.connect( diff --git a/src/network/randomtrackingdict.py b/src/network/randomtrackingdict.py index 6c3300ab..e87bf156 100644 --- a/src/network/randomtrackingdict.py +++ b/src/network/randomtrackingdict.py @@ -1,8 +1,6 @@ """ -src/randomtrackingdict.py -========================= +Track randomize ordered dict """ - import random from threading import RLock from time import time @@ -14,10 +12,12 @@ class RandomTrackingDict(object): """ Dict with randomised order and tracking. - Keeps a track of how many items have been requested from the dict, and timeouts. Resets after all objects have been - retrieved and timed out. The main purpose of this isn't as much putting related code together as performance - optimisation and anonymisation of downloading of objects from other peers. If done using a standard dict or array, - it takes too much CPU (and looks convoluted). Randomisation helps with anonymity. + Keeps a track of how many items have been requested from the dict, + and timeouts. Resets after all objects have been retrieved and timed out. + The main purpose of this isn't as much putting related code together + as performance optimisation and anonymisation of downloading of objects + from other peers. If done using a standard dict or array, it takes + too much CPU (and looks convoluted). Randomisation helps with anonymity. """ # pylint: disable=too-many-instance-attributes maxPending = 10 @@ -85,13 +85,14 @@ class RandomTrackingDict(object): def setMaxPending(self, maxPending): """ - Sets maximum number of objects that can be retrieved from the class simultaneously as long as there is no - timeout + Sets maximum number of objects that can be retrieved from the class + simultaneously as long as there is no timeout """ self.maxPending = maxPending def setPendingTimeout(self, pendingTimeout): - """Sets how long to wait for a timeout if max pending is reached (or all objects have been retrieved)""" + """Sets how long to wait for a timeout if max pending is reached + (or all objects have been retrieved)""" self.pendingTimeout = pendingTimeout def setLastObject(self): @@ -99,7 +100,8 @@ class RandomTrackingDict(object): self.lastObject = time() def randomKeys(self, count=1): - """Retrieve count random keys from the dict that haven't already been retrieved""" + """Retrieve count random keys from the dict + that haven't already been retrieved""" if self.len == 0 or ((self.pendingLen >= self.maxPending or self.pendingLen == self.len) and self.lastPoll + self.pendingTimeout > time()): @@ -109,13 +111,15 @@ class RandomTrackingDict(object): with self.lock: # reset if we've requested all # and if last object received too long time ago - if self.pendingLen == self.len and self.lastObject + self.pendingTimeout < time(): + if self.pendingLen == self.len and self.lastObject + \ + self.pendingTimeout < time(): self.pendingLen = 0 self.setLastObject() available = self.len - self.pendingLen if count > available: count = available - randomIndex = helper_random.randomsample(range(self.len - self.pendingLen), count) + randomIndex = helper_random.randomsample( + range(self.len - self.pendingLen), count) retval = [self.indexDict[i] for i in randomIndex] for i in sorted(randomIndex, reverse=True): diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index cd904065..1f5533b3 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -1,3 +1,6 @@ +""" +Process data incoming from network +""" import errno import Queue import socket @@ -10,6 +13,8 @@ from threads import StoppableThread class ReceiveQueueThread(StoppableThread): + """This thread processes data received from the network + (which is done by the asyncore thread)""" def __init__(self, num=0): super(ReceiveQueueThread, self).__init__(name="ReceiveQueue_%i" % num) @@ -32,12 +37,14 @@ class ReceiveQueueThread(StoppableThread): try: connection = BMConnectionPool().getConnectionByAddr(dest) - except KeyError: # connection object not found + # connection object not found + except KeyError: receiveDataQueue.task_done() continue try: connection.process() - except UnknownStateError: # state isn't implemented + # state isn't implemented + except UnknownStateError: pass except socket.error as err: if err.errno == errno.EBADF: diff --git a/src/network/socks4a.py b/src/network/socks4a.py index f0b234f5..42eab4b7 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -1,6 +1,5 @@ """ -src/network/socks4a.py -================================= +SOCKS4a proxy module """ # pylint: disable=attribute-defined-outside-init import socket diff --git a/src/network/socks5.py b/src/network/socks5.py index f0241744..fc33f4df 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -1,7 +1,5 @@ """ -src/network/socks5.py -===================== - +SOCKS5 proxy module """ # pylint: disable=attribute-defined-outside-init @@ -155,7 +153,8 @@ class Socks5(Proxy): return True def proxy_sock_name(self): - """Handle return value when using SOCKS5 for DNS resolving instead of connecting.""" + """Handle return value when using SOCKS5 + for DNS resolving instead of connecting.""" return socket.inet_ntoa(self.__proxysockname[0]) diff --git a/src/network/stats.py b/src/network/stats.py index d760ace2..82e6c87f 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -1,6 +1,5 @@ """ -src/network/stats.py -==================== +Network statistics """ import time @@ -34,7 +33,9 @@ def uploadSpeed(): currentTimestamp = time.time() if int(lastSentTimestamp) < int(currentTimestamp): currentSentBytes = asyncore.sentBytes - currentSentSpeed = int((currentSentBytes - lastSentBytes) / (currentTimestamp - lastSentTimestamp)) + currentSentSpeed = int( + (currentSentBytes - lastSentBytes) / ( + currentTimestamp - lastSentTimestamp)) lastSentBytes = currentSentBytes lastSentTimestamp = currentTimestamp return currentSentSpeed @@ -53,7 +54,8 @@ def downloadSpeed(): if int(lastReceivedTimestamp) < int(currentTimestamp): currentReceivedBytes = asyncore.receivedBytes currentReceivedSpeed = int( - (currentReceivedBytes - lastReceivedBytes) / (currentTimestamp - lastReceivedTimestamp)) + (currentReceivedBytes - lastReceivedBytes) / ( + currentTimestamp - lastReceivedTimestamp)) lastReceivedBytes = currentReceivedBytes lastReceivedTimestamp = currentTimestamp return currentReceivedSpeed diff --git a/src/network/tcp.py b/src/network/tcp.py index 3097765f..d611b1ca 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -1,9 +1,7 @@ +""" +TCP protocol handler +""" # pylint: disable=too-many-ancestors -""" -src/network/tcp.py -================== -""" - import logging import math import random @@ -31,7 +29,7 @@ from network.socks4a import Socks4aConnection from network.socks5 import Socks5Connection from network.tls import TLSDispatcher from node import Peer -from queues import UISignalQueue, invQueue, receiveDataQueue +from queues import invQueue, receiveDataQueue, UISignalQueue logger = logging.getLogger('default') @@ -39,7 +37,6 @@ logger = logging.getLogger('default') class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes """ - .. todo:: Look to understand and/or fix the non-parent-init-called """ @@ -85,7 +82,8 @@ class TCPConnection(BMProto, TLSDispatcher): not protocol.checkSocksIP(self.destination.host) ) except socket.error: - pass # it's probably a hostname + # it's probably a hostname + pass self.network_group = protocol.network_group(self.destination.host) ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called self.bm_proto_reset() @@ -140,10 +138,9 @@ class TCPConnection(BMProto, TLSDispatcher): if not self.isOutbound and not self.local: shared.clientHasReceivedIncomingConnections = True UISignalQueue.put(('setStatusIcon', 'green')) - UISignalQueue.put(( - 'updateNetworkStatusTab', - (self.isOutbound, True, self.destination) - )) + UISignalQueue.put( + ('updateNetworkStatusTab', ( + self.isOutbound, True, self.destination))) self.antiIntersectionDelay(True) self.fullyEstablished = True if self.isOutbound: @@ -215,8 +212,8 @@ class TCPConnection(BMProto, TLSDispatcher): bigInvList[objHash] = 0 objectCount = 0 payload = b'' - # Now let us start appending all of these hashes together. They will be - # sent out in a big inv message to our new peer. + # Now let us start appending all of these hashes together. + # They will be sent out in a big inv message to our new peer. for obj_hash, _ in bigInvList.items(): payload += obj_hash objectCount += 1 diff --git a/src/network/tls.py b/src/network/tls.py index d5c4e23a..f756591c 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -1,7 +1,6 @@ """ SSL/TLS negotiation. """ - import logging import os import socket @@ -10,6 +9,7 @@ import sys from network.advanceddispatcher import AdvancedDispatcher import network.asyncore_pollchoose as asyncore + from queues import receiveDataQueue import paths @@ -24,7 +24,8 @@ if sys.version_info >= (2, 7, 13): # ssl.PROTOCOL_TLS1.2 sslProtocolVersion = ssl.PROTOCOL_TLS # pylint: disable=no-member elif sys.version_info >= (2, 7, 9): - # this means any SSL/TLS. SSLv2 and 3 are excluded with an option after context is created + # this means any SSL/TLS. + # SSLv2 and 3 are excluded with an option after context is created sslProtocolVersion = ssl.PROTOCOL_SSLv23 else: # this means TLSv1, there is no way to set "TLSv1 or higher" or @@ -33,7 +34,8 @@ else: # ciphers -if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000 and not ssl.OPENSSL_VERSION.startswith("LibreSSL"): +if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000 and not \ + ssl.OPENSSL_VERSION.startswith("LibreSSL"): sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0" else: sslProtocolCiphers = "AECDH-AES256-SHA" @@ -41,19 +43,19 @@ else: class TLSDispatcher(AdvancedDispatcher): """TLS functionality for classes derived from AdvancedDispatcher""" - # pylint: disable=too-many-instance-attributes - # pylint: disable=too-many-arguments,super-init-not-called,unused-argument - def __init__( - self, address=None, sock=None, certfile=None, keyfile=None, - server_side=False, ciphers=sslProtocolCiphers - ): + # pylint: disable=too-many-instance-attributes, too-many-arguments + # pylint: disable=super-init-not-called + def __init__(self, _=None, sock=None, certfile=None, keyfile=None, + server_side=False, ciphers=sslProtocolCiphers): self.want_read = self.want_write = True if certfile is None: - self.certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem') + self.certfile = os.path.join( + paths.codePath(), 'sslkeys', 'cert.pem') else: self.certfile = certfile if keyfile is None: - self.keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem') + self.keyfile = os.path.join( + paths.codePath(), 'sslkeys', 'key.pem') else: self.keyfile = keyfile self.server_side = server_side @@ -68,20 +70,23 @@ class TLSDispatcher(AdvancedDispatcher): # pylint: disable=attribute-defined-outside-init self.isSSL = True self.tlsStarted = True - # Once the connection has been established, it's safe to wrap the - # socket. + # Once the connection has been established, + # it's safe to wrap the socket. if sys.version_info >= (2, 7, 9): context = ssl.create_default_context( - purpose=ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH) + purpose=ssl.Purpose.SERVER_AUTH + if self.server_side else ssl.Purpose.CLIENT_AUTH) context.set_ciphers(self.ciphers) context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE # also exclude TLSv1 and TLSv1.1 in the future context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\ - ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE + ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\ + ssl.OP_CIPHER_SERVER_PREFERENCE self.sslSocket = context.wrap_socket( - self.socket, server_side=self.server_side, do_handshake_on_connect=False) + self.socket, server_side=self.server_side, + do_handshake_on_connect=False) else: self.sslSocket = ssl.wrap_socket( self.socket, server_side=self.server_side, @@ -115,12 +120,15 @@ class TLSDispatcher(AdvancedDispatcher): def readable(self): """Handle readable check for TLS-enabled sockets""" try: - # during TLS handshake, and after flushing write buffer, return status of last handshake attempt + # during TLS handshake, and after flushing write buffer, + # return status of last handshake attempt if self.tlsStarted and not self.tlsDone and not self.write_buf: # print "tls readable, %r" % (self.want_read) return self.want_read - # prior to TLS handshake, receiveDataThread should emulate synchronous behaviour - elif not self.fullyEstablished and (self.expectBytes == 0 or not self.write_buf_empty()): + # prior to TLS handshake, + # receiveDataThread should emulate synchronous behaviour + elif not self.fullyEstablished and ( + self.expectBytes == 0 or not self.write_buf_empty()): return False return AdvancedDispatcher.readable(self) except AttributeError: @@ -135,10 +143,14 @@ class TLSDispatcher(AdvancedDispatcher): try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: - # logger.debug("%s:%i TLS handshaking (read)", self.destination.host, self.destination.port) + # logger.debug( + # "%s:%i TLS handshaking (read)", self.destination.host, + # self.destination.port) self.tls_handshake() else: - # logger.debug("%s:%i Not TLS handshaking (read)", self.destination.host, self.destination.port) + # logger.debug( + # "%s:%i Not TLS handshaking (read)", self.destination.host, + # self.destination.port) return AdvancedDispatcher.handle_read(self) except AttributeError: return AdvancedDispatcher.handle_read(self) @@ -161,10 +173,14 @@ class TLSDispatcher(AdvancedDispatcher): try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: - # logger.debug("%s:%i TLS handshaking (write)", self.destination.host, self.destination.port) + # logger.debug( + # "%s:%i TLS handshaking (write)", self.destination.host, + # self.destination.port) self.tls_handshake() else: - # logger.debug("%s:%i Not TLS handshaking (write)", self.destination.host, self.destination.port) + # logger.debug( + # "%s:%i Not TLS handshaking (write)", self.destination.host, + # self.destination.port) return AdvancedDispatcher.handle_write(self) except AttributeError: return AdvancedDispatcher.handle_write(self) @@ -188,7 +204,8 @@ class TLSDispatcher(AdvancedDispatcher): # print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError as err: - # print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) + # print "%s:%i: handshake fail" % ( + # self.destination.host, self.destination.port) self.want_read = self.want_write = False if err.args[0] == ssl.SSL_ERROR_WANT_READ: # print "want read" diff --git a/src/network/udp.py b/src/network/udp.py index d8c5f340..d5f1cccd 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -1,13 +1,12 @@ """ -src/network/udp.py -================== +UDP protocol handler """ import logging -import time import socket +import time -import state import protocol +import state from bmproto import BMProto from node import Peer from objectracker import ObjectTracker @@ -79,7 +78,7 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes if not self.local: return True remoteport = False - for seenTime, stream, services, ip, port in addresses: + for seenTime, stream, _, ip, port in addresses: decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue @@ -96,9 +95,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes "received peer discovery from %s:%i (port %i):", self.destination.host, self.destination.port, remoteport) if self.local: - state.discoveredPeers[ - Peer(self.destination.host, remoteport) - ] = time.time() + state.discoveredPeers[Peer(self.destination.host, remoteport)] = \ + time.time() return True def bm_command_portcheck(self): From 6fad4f56657c4f44d1bc30298928b12fe5011bbc Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 24 Dec 2019 18:23:22 +0530 Subject: [PATCH 288/306] filesystem quality fixes --- src/storage/filesystem.py | 70 ++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index 43ba03fc..571a16c1 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -1,6 +1,5 @@ """ -src/storage/filesystem.py -========================= +Module for using filesystem (directory with files) for inventory storage """ from binascii import hexlify, unhexlify from os import listdir, makedirs, path, remove, rmdir @@ -12,8 +11,9 @@ from paths import lookupAppdataFolder from storage import InventoryStorage, InventoryItem -class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ancestors, abstract-method - """Module for using filesystem (directory with files) for inventory storage""" +class FilesystemInventory(InventoryStorage): + """Filesystem for inventory storage""" + # pylint: disable=too-many-ancestors, abstract-method topDir = "inventory" objectDir = "objects" metadataFilename = "metadata" @@ -21,21 +21,23 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances def __init__(self): super(FilesystemInventory, self).__init__() - self.baseDir = path.join(lookupAppdataFolder(), FilesystemInventory.topDir) + self.baseDir = path.join( + lookupAppdataFolder(), FilesystemInventory.topDir) for createDir in [self.baseDir, path.join(self.baseDir, "objects")]: if path.exists(createDir): if not path.isdir(createDir): - raise IOError("%s exists but it's not a directory" % (createDir)) + raise IOError( + "%s exists but it's not a directory" % createDir) else: makedirs(createDir) - # Guarantees that two receiveDataThreads don't receive and process the same message + # Guarantees that two receiveDataThreads + # don't receive and process the same message # concurrently (probably sent by a malicious individual) self.lock = RLock() self._inventory = {} self._load() def __contains__(self, hashval): - retval = False for streamDict in self._inventory.values(): if hashval in streamDict: return True @@ -48,7 +50,12 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances except KeyError: continue if retval.payload is None: - retval = InventoryItem(retval.type, retval.stream, self.getData(hashval), retval.expires, retval.tag) + retval = InventoryItem( + retval.type, + retval.stream, + self.getData(hashval), + retval.expires, + retval.tag) return retval raise KeyError(hashval) @@ -56,7 +63,10 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances with self.lock: value = InventoryItem(*value) try: - makedirs(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashval))) + makedirs(path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hashval))) except OSError: pass try: @@ -69,7 +79,11 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances ), "w", ) as f: - f.write("%s,%s,%s,%s," % (value.type, value.stream, value.expires, hexlify(value.tag))) + f.write("%s,%s,%s,%s," % ( + value.type, + value.stream, + value.expires, + hexlify(value.tag))) with open( path.join( self.baseDir, @@ -115,7 +129,10 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances except IOError: pass try: - rmdir(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashval))) + rmdir(path.join( + self.baseDir, + FilesystemInventory.objectDir, + hexlify(hashval))) except IOError: pass @@ -135,7 +152,8 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances newInventory = {} for hashId in self.object_list(): try: - objectType, streamNumber, expiresTime, tag = self.getMetadata(hashId) + objectType, streamNumber, expiresTime, tag = self.getMetadata( + hashId) try: newInventory[streamNumber][hashId] = InventoryItem( objectType, streamNumber, None, expiresTime, tag) @@ -155,7 +173,8 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances def object_list(self): """Return inventory vectors (hashes) from a directory""" - return [unhexlify(x) for x in listdir(path.join(self.baseDir, FilesystemInventory.objectDir))] + return [unhexlify(x) for x in listdir(path.join( + self.baseDir, FilesystemInventory.objectDir))] def getData(self, hashId): """Get object data""" @@ -185,15 +204,20 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances ), "r", ) as f: - objectType, streamNumber, expiresTime, tag, undef = string.split(f.read(), ",", 4) - return [int(objectType), int(streamNumber), int(expiresTime), unhexlify(tag)] + objectType, streamNumber, expiresTime, tag = string.split( + f.read(), ",", 4)[:4] + return [ + int(objectType), + int(streamNumber), + int(expiresTime), + unhexlify(tag)] except IOError: raise KeyError def by_type_and_tag(self, objectType, tag): """Get a list of objects filtered by object type and tag""" retval = [] - for stream, streamDict in self._inventory: + for streamDict in self._inventory.values(): for hashId, item in streamDict: if item.type == objectType and item.tag == tag: try: @@ -201,7 +225,12 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances item.payload = self.getData(hashId) except IOError: continue - retval.append(InventoryItem(item.type, item.stream, item.payload, item.expires, item.tag)) + retval.append(InventoryItem( + item.type, + item.stream, + item.payload, + item.expires, + item.tag)) return retval def hashes_by_stream(self, stream): @@ -215,7 +244,8 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances """Return unexpired hashes in the inventory for a particular stream""" t = int(time.time()) try: - return [x for x, value in self._inventory[stream].items() if value.expires > t] + return [x for x, value in self._inventory[stream].items() + if value.expires > t] except KeyError: return [] @@ -227,7 +257,7 @@ class FilesystemInventory(InventoryStorage): # pylint: disable=too-many-ances """Clean out old items from the inventory""" minTime = int(time.time()) - (60 * 60 * 30) deletes = [] - for stream, streamDict in self._inventory.items(): + for streamDict in self._inventory.values(): for hashId, item in streamDict.items(): if item.expires < minTime: deletes.append(hashId) From 108b231c1c612710683ce24954a07c6db7db3450 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 24 Dec 2019 18:23:37 +0530 Subject: [PATCH 289/306] sqlite quality fixes --- src/storage/sqlite.py | 51 ++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 0c2b4afa..7f41abc5 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -1,6 +1,5 @@ """ -src/storage/sqlite.py -========================= +Sqlite Inventory """ import sqlite3 import time @@ -10,7 +9,7 @@ from helper_sql import sqlQuery, SqlBulkExecute, sqlExecute from storage import InventoryStorage, InventoryItem -class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors +class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors """Inventory using SQLite""" def __init__(self): super(SqliteInventory, self).__init__() @@ -20,9 +19,11 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors # cache for existing objects, used for quick lookups if we have an object. # This is used for example whenever we receive an inv message from a peer # to check to see what items are new to us. - # We don't delete things out of it; instead, the singleCleaner thread clears and refills it. + # We don't delete things out of it; instead, + # the singleCleaner thread clears and refills it. self._objects = {} - # Guarantees that two receiveDataThreads don't receive and process the same message concurrently + # Guarantees that two receiveDataThreads don't receive + # and process the same message concurrently # (probably sent by a malicious individual) self.lock = RLock() @@ -30,7 +31,9 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors with self.lock: if hash_ in self._objects: return True - rows = sqlQuery('SELECT streamnumber FROM inventory WHERE hash=?', sqlite3.Binary(hash_)) + rows = sqlQuery( + 'SELECT streamnumber FROM inventory WHERE hash=?', + sqlite3.Binary(hash_)) if not rows: return False self._objects[hash_] = rows[0][0] @@ -41,8 +44,8 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors if hash_ in self._inventory: return self._inventory[hash_] rows = sqlQuery( - 'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', - sqlite3.Binary(hash_)) + 'SELECT objecttype, streamnumber, payload, expirestime, tag' + ' FROM inventory WHERE hash=?', sqlite3.Binary(hash_)) if not rows: raise KeyError(hash_) return InventoryItem(*rows[0]) @@ -64,35 +67,49 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors def __len__(self): with self.lock: - return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0] + return len(self._inventory) + sqlQuery( + 'SELECT count(*) FROM inventory')[0][0] def by_type_and_tag(self, objectType, tag): + """Return objects filtered by object type and tag""" with self.lock: - values = [value for value in self._inventory.values() if value.type == objectType and value.tag == tag] + values = [value for value in self._inventory.values() + if value.type == objectType and value.tag == tag] values += (InventoryItem(*value) for value in sqlQuery( - 'SELECT objecttype, streamnumber, payload, expirestime, tag \ - FROM inventory WHERE objecttype=? AND tag=?', objectType, sqlite3.Binary(tag))) + 'SELECT objecttype, streamnumber, payload, expirestime, tag' + ' FROM inventory WHERE objecttype=? AND tag=?', + objectType, sqlite3.Binary(tag))) return values def unexpired_hashes_by_stream(self, stream): + """Return unexpired inventory vectors filtered by stream""" with self.lock: t = int(time.time()) - hashes = [x for x, value in self._inventory.items() if value.stream == stream and value.expires > t] + hashes = [x for x, value in self._inventory.items() + if value.stream == stream and value.expires > t] hashes += (str(payload) for payload, in sqlQuery( - 'SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) + 'SELECT hash FROM inventory WHERE streamnumber=?' + ' AND expirestime>?', stream, t)) return hashes def flush(self): + """Flush cache""" with self.lock: - # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + # If you use both the inventoryLock and the sqlLock, + # always use the inventoryLock OUTSIDE of the sqlLock. with SqlBulkExecute() as sql: for objectHash, value in self._inventory.items(): - sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', sqlite3.Binary(objectHash), *value) + sql.execute( + 'INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', + sqlite3.Binary(objectHash), *value) self._inventory.clear() def clean(self): + """Free memory / perform garbage collection""" with self.lock: - sqlExecute('DELETE FROM inventory WHERE expirestime Date: Tue, 24 Dec 2019 18:23:48 +0530 Subject: [PATCH 290/306] storage quality fixes --- src/storage/storage.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/storage/storage.py b/src/storage/storage.py index 482937e7..0391979a 100644 --- a/src/storage/storage.py +++ b/src/storage/storage.py @@ -1,21 +1,22 @@ """ -src/storage/storage.py -====================== +Storing inventory items """ import collections -InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') +InventoryItem = collections.namedtuple( + 'InventoryItem', 'type stream payload expires tag') -class Storage(object): - """Base class for storing inventory (extendable for other items to store)""" +class Storage(object): # pylint: disable=too-few-public-methods + """Base class for storing inventory + (extendable for other items to store)""" pass class InventoryStorage(Storage, collections.MutableMapping): """Module used for inventory storage""" - def __init__(self): - # pylint: disable=super-init-not-called + + def __init__(self): # pylint: disable=super-init-not-called self.numberOfInventoryLookupsPerformed = 0 def __contains__(self, _): @@ -53,8 +54,20 @@ class InventoryStorage(Storage, collections.MutableMapping): raise NotImplementedError -class MailboxStorage(Storage, collections.MutableMapping): # pylint: disable=abstract-method +class MailboxStorage(Storage, collections.MutableMapping): """Method for storing mails""" - def __init__(self): - # pylint: disable=super-init-not-called - pass + + def __delitem__(self, key): + raise NotImplementedError + + def __getitem__(self, key): + raise NotImplementedError + + def __iter__(self): + raise NotImplementedError + + def __len__(self): + raise NotImplementedError + + def __setitem__(self, key, value): + raise NotImplementedError From f0bc74e65844f7a9a33dd3bc1d63a168cb97b2eb Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 6 Jan 2020 17:14:47 +0530 Subject: [PATCH 291/306] Network fixes --- src/network/__init__.py | 3 + src/network/addrthread.py | 1 + src/network/advanceddispatcher.py | 35 +++--- src/network/announcethread.py | 7 +- src/network/assemble.py | 17 ++- src/network/asyncore_pollchoose.py | 164 ++++++++++------------------- src/network/bmobject.py | 49 +++++---- src/network/bmproto.py | 82 ++++++++------- src/network/connectionchooser.py | 8 +- src/network/constants.py | 18 ++-- src/network/dandelion.py | 10 +- src/network/downloadthread.py | 5 +- src/network/invthread.py | 20 ++-- 13 files changed, 205 insertions(+), 214 deletions(-) diff --git a/src/network/__init__.py b/src/network/__init__.py index 51c4c4da..70613539 100644 --- a/src/network/__init__.py +++ b/src/network/__init__.py @@ -1,3 +1,6 @@ +""" +Network subsystem packages +""" from addrthread import AddrThread from announcethread import AnnounceThread from connectionpool import BMConnectionPool diff --git a/src/network/addrthread.py b/src/network/addrthread.py index 8a0396f8..3bf448d8 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -12,6 +12,7 @@ from threads import StoppableThread class AddrThread(StoppableThread): + """(Node) address broadcasting thread""" name = "AddrBroadcaster" def run(self): diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index eeb50bdf..982be819 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,9 +1,7 @@ """ -src/network/advanceddispatcher.py -================================= +Improved version of asyncore dispatcher """ # pylint: disable=attribute-defined-outside-init - import socket import threading import time @@ -14,7 +12,8 @@ from threads import BusyError, nonBlocking class ProcessingError(Exception): - """General class for protocol parser exception, use as a base for others.""" + """General class for protocol parser exception, + use as a base for others.""" pass @@ -24,7 +23,8 @@ class UnknownStateError(ProcessingError): class AdvancedDispatcher(asyncore.dispatcher): - """Improved version of asyncore dispatcher, with buffers and protocol state.""" + """Improved version of asyncore dispatcher, + with buffers and protocol state.""" # pylint: disable=too-many-instance-attributes _buf_len = 131072 # 128kB @@ -72,7 +72,8 @@ class AdvancedDispatcher(asyncore.dispatcher): del self.read_buf[0:length] def process(self): - """Process (parse) data that's in the buffer, as long as there is enough data and the connection is open.""" + """Process (parse) data that's in the buffer, + as long as there is enough data and the connection is open.""" while self.connected and not state.shutdown: try: with nonBlocking(self.processingLock): @@ -104,8 +105,9 @@ class AdvancedDispatcher(asyncore.dispatcher): if asyncore.maxUploadRate > 0: self.uploadChunk = int(asyncore.uploadBucket) self.uploadChunk = min(self.uploadChunk, len(self.write_buf)) - return asyncore.dispatcher.writable(self) and \ - (self.connecting or (self.connected and self.uploadChunk > 0)) + return asyncore.dispatcher.writable(self) and ( + self.connecting or ( + self.connected and self.uploadChunk > 0)) def readable(self): """Is the read buffer ready to accept data from the network?""" @@ -114,13 +116,15 @@ class AdvancedDispatcher(asyncore.dispatcher): self.downloadChunk = int(asyncore.downloadBucket) try: if self.expectBytes > 0 and not self.fullyEstablished: - self.downloadChunk = min(self.downloadChunk, self.expectBytes - len(self.read_buf)) + self.downloadChunk = min( + self.downloadChunk, self.expectBytes - len(self.read_buf)) if self.downloadChunk < 0: self.downloadChunk = 0 except AttributeError: pass - return asyncore.dispatcher.readable(self) and \ - (self.connecting or self.accepting or (self.connected and self.downloadChunk > 0)) + return asyncore.dispatcher.readable(self) and ( + self.connecting or self.accepting or ( + self.connected and self.downloadChunk > 0)) def handle_read(self): """Append incoming data to the read buffer.""" @@ -144,20 +148,21 @@ class AdvancedDispatcher(asyncore.dispatcher): try: asyncore.dispatcher.handle_connect_event(self) except socket.error as e: - if e.args[0] not in asyncore._DISCONNECTED: # pylint: disable=protected-access + # pylint: disable=protected-access + if e.args[0] not in asyncore._DISCONNECTED: raise def handle_connect(self): """Method for handling connection established implementations.""" self.lastTx = time.time() - def state_close(self): + def state_close(self): # pylint: disable=no-self-use """Signal to the processing loop to end.""" - # pylint: disable=no-self-use return False def handle_close(self): - """Callback for connection being closed, but can also be called directly when you want connection to close.""" + """Callback for connection being closed, + but can also be called directly when you want connection to close.""" with self.readLock: self.read_buf = bytearray() with self.writeLock: diff --git a/src/network/announcethread.py b/src/network/announcethread.py index c11a2cc6..17c8bcd3 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -1,8 +1,6 @@ """ -src/network/announcethread.py -================================= +Announce myself (node address) """ - import time import state @@ -40,6 +38,7 @@ class AnnounceThread(StoppableThread): stream, Peer( '127.0.0.1', - BMConfigParser().safeGetInt('bitmessagesettings', 'port')), + BMConfigParser().safeGetInt( + 'bitmessagesettings', 'port')), time.time()) connection.append_write_buf(assemble_addr([addr])) diff --git a/src/network/assemble.py b/src/network/assemble.py index 2d31914c..32fad3e4 100644 --- a/src/network/assemble.py +++ b/src/network/assemble.py @@ -1,7 +1,6 @@ """ Create bitmessage protocol command packets """ - import struct import addresses @@ -13,20 +12,20 @@ from protocol import CreatePacket, encodeHost def assemble_addr(peerList): """Create address command""" if isinstance(peerList, Peer): - peerList = (peerList) + peerList = [peerList] if not peerList: return b'' retval = b'' for i in range(0, len(peerList), MAX_ADDR_COUNT): - payload = addresses.encodeVarint( - len(peerList[i:i + MAX_ADDR_COUNT])) + payload = addresses.encodeVarint(len(peerList[i:i + MAX_ADDR_COUNT])) for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]: - payload += struct.pack( - '>Q', timestamp) # 64-bit time + # 64-bit time + payload += struct.pack('>Q', timestamp) payload += struct.pack('>I', stream) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node + # service bit flags offered by this node + payload += struct.pack('>q', 1) payload += encodeHost(peer.host) - payload += struct.pack('>H', peer.port) # remote port + # remote port + payload += struct.pack('>H', peer.port) retval += CreatePacket('addr', payload) return retval diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 3337c0f0..41757f37 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -1,56 +1,11 @@ +""" +Basic infrastructure for asynchronous socket service clients and servers. +""" # -*- Mode: Python -*- # Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp # Author: Sam Rushing -# pylint: disable=too-many-statements,too-many-branches,no-self-use,too-many-lines,attribute-defined-outside-init -# pylint: disable=global-statement -""" -src/network/asyncore_pollchoose.py -================================== - -# ====================================================================== -# Copyright 1996 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -Basic infrastructure for asynchronous socket service clients and servers. - -There are only two ways to have a program on a single processor do "more -than one thing at a time". Multi-threaded programming is the simplest and -most popular way to do it, but there is another very different technique, -that lets you have nearly all the advantages of multi-threading, without -actually using multiple threads. it's really only practical if your program -is largely I/O bound. If your program is CPU bound, then pre-emptive -scheduled threads are probably what you really need. Network servers are -rarely CPU-bound, however. - -If your operating system supports the select() system call in its I/O -library (and nearly all do), then you can use it to juggle multiple -communication channels at once; doing other work while your I/O is taking -place in the "background." Although this strategy can seem strange and -complex, especially at first, it is in many ways easier to understand and -control than multi-threaded programming. The module documented here solves -many of the difficult problems for you, making the task of building -sophisticated high-performance network servers and clients a snap. -""" - +# pylint: disable=too-many-branches,too-many-lines,global-statement +# pylint: disable=redefined-builtin,no-self-use import os import select import socket @@ -58,8 +13,9 @@ import sys import time import warnings from errno import ( - EADDRINUSE, EAGAIN, EALREADY, EBADF, ECONNABORTED, ECONNREFUSED, ECONNRESET, EHOSTUNREACH, EINPROGRESS, EINTR, - EINVAL, EISCONN, ENETUNREACH, ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode + EADDRINUSE, EAGAIN, EALREADY, EBADF, ECONNABORTED, ECONNREFUSED, + ECONNRESET, EHOSTUNREACH, EINPROGRESS, EINTR, EINVAL, EISCONN, ENETUNREACH, + ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode ) from threading import current_thread @@ -107,7 +63,8 @@ def _strerror(err): class ExitNow(Exception): - """We don't use directly but may be necessary as we replace asyncore due to some library raising or expecting it""" + """We don't use directly but may be necessary as we replace + asyncore due to some library raising or expecting it""" pass @@ -152,7 +109,8 @@ def write(obj): def set_rates(download, upload): """Set throttling rates""" - global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp + global maxDownloadRate, maxUploadRate, downloadBucket + global uploadBucket, downloadTimestamp, uploadTimestamp maxDownloadRate = float(download) * 1024 maxUploadRate = float(upload) * 1024 @@ -182,7 +140,8 @@ def update_received(download=0): currentTimestamp = time.time() receivedBytes += download if maxDownloadRate > 0: - bucketIncrease = maxDownloadRate * (currentTimestamp - downloadTimestamp) + bucketIncrease = \ + maxDownloadRate * (currentTimestamp - downloadTimestamp) downloadBucket += bucketIncrease if downloadBucket > maxDownloadRate: downloadBucket = int(maxDownloadRate) @@ -242,7 +201,6 @@ def readwrite(obj, flags): def select_poller(timeout=0.0, map=None): """A poller which uses select(), available on most platforms.""" - # pylint: disable=redefined-builtin if map is None: map = socket_map @@ -298,7 +256,6 @@ def select_poller(timeout=0.0, map=None): def poll_poller(timeout=0.0, map=None): """A poller which uses poll(), available on most UNIXen.""" - # pylint: disable=redefined-builtin if map is None: map = socket_map @@ -356,7 +313,6 @@ poll2 = poll3 = poll_poller def epoll_poller(timeout=0.0, map=None): """A poller which uses epoll(), supported on Linux 2.5.44 and newer.""" - # pylint: disable=redefined-builtin if map is None: map = socket_map @@ -412,7 +368,7 @@ def epoll_poller(timeout=0.0, map=None): def kqueue_poller(timeout=0.0, map=None): """A poller which uses kqueue(), BSD specific.""" - # pylint: disable=redefined-builtin,no-member + # pylint: disable=no-member,too-many-statements if map is None: map = socket_map @@ -440,14 +396,20 @@ def kqueue_poller(timeout=0.0, map=None): poller_flags |= select.KQ_EV_ENABLE else: poller_flags |= select.KQ_EV_DISABLE - updates.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=poller_flags)) + updates.append( + select.kevent( + fd, filter=select.KQ_FILTER_READ, + flags=poller_flags)) if kq_filter & 2 != obj.poller_filter & 2: poller_flags = select.KQ_EV_ADD if kq_filter & 2: poller_flags |= select.KQ_EV_ENABLE else: poller_flags |= select.KQ_EV_DISABLE - updates.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=poller_flags)) + updates.append( + select.kevent( + fd, filter=select.KQ_FILTER_WRITE, + flags=poller_flags)) obj.poller_filter = kq_filter if not selectables: @@ -481,7 +443,6 @@ def kqueue_poller(timeout=0.0, map=None): def loop(timeout=30.0, use_poll=False, map=None, count=None, poller=None): """Poll in a loop, until count or timeout is reached""" - # pylint: disable=redefined-builtin if map is None: map = socket_map @@ -520,9 +481,9 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, poller=None): count = count - 1 -class dispatcher: +class dispatcher(object): """Dispatcher for socket objects""" - # pylint: disable=too-many-public-methods,too-many-instance-attributes,old-style-class + # pylint: disable=too-many-public-methods,too-many-instance-attributes debug = False connected = False @@ -537,7 +498,6 @@ class dispatcher: minTx = 1500 def __init__(self, sock=None, map=None): - # pylint: disable=redefined-builtin if map is None: self._map = socket_map else: @@ -586,8 +546,7 @@ class dispatcher: def add_channel(self, map=None): """Add a channel""" - # pylint: disable=redefined-builtin - + # pylint: disable=attribute-defined-outside-init if map is None: map = self._map map[self._fileno] = self @@ -596,8 +555,6 @@ class dispatcher: def del_channel(self, map=None): """Delete a channel""" - # pylint: disable=redefined-builtin - fd = self._fileno if map is None: map = self._map @@ -605,12 +562,14 @@ class dispatcher: del map[fd] if self._fileno: try: - kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) - except (AttributeError, KeyError, TypeError, IOError, OSError): + kqueue_poller.pollster.control([select.kevent( + fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) + except(AttributeError, KeyError, TypeError, IOError, OSError): pass try: - kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)], 0) - except (AttributeError, KeyError, TypeError, IOError, OSError): + kqueue_poller.pollster.control([select.kevent( + fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)], 0) + except(AttributeError, KeyError, TypeError, IOError, OSError): pass try: epoll_poller.pollster.unregister(fd) @@ -627,8 +586,10 @@ class dispatcher: self.poller_filter = 0 self.poller_registered = False - def create_socket(self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM): + def create_socket( + self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM): """Create a socket""" + # pylint: disable=attribute-defined-outside-init self.family_and_type = family, socket_type sock = socket.socket(family, socket_type) sock.setblocking(0) @@ -636,20 +597,16 @@ class dispatcher: def set_socket(self, sock, map=None): """Set socket""" - # pylint: disable=redefined-builtin - self.socket = sock self._fileno = sock.fileno() self.add_channel(map) def set_reuse_addr(self): """try to re-use a server port if possible""" - try: self.socket.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEADDR, - self.socket.getsockopt(socket.SOL_SOCKET, - socket.SO_REUSEADDR) | 1 + socket.SOL_SOCKET, socket.SO_REUSEADDR, self.socket.getsockopt( + socket.SOL_SOCKET, socket.SO_REUSEADDR) | 1 ) except socket.error: pass @@ -704,13 +661,16 @@ class dispatcher: raise socket.error(err, errorcode[err]) def accept(self): - """Accept incoming connections. Returns either an address pair or None.""" + """Accept incoming connections. + Returns either an address pair or None.""" try: conn, addr = self.socket.accept() except TypeError: return None except socket.error as why: - if why.args[0] in (EWOULDBLOCK, WSAEWOULDBLOCK, ECONNABORTED, EAGAIN, ENOTCONN): + if why.args[0] in ( + EWOULDBLOCK, WSAEWOULDBLOCK, ECONNABORTED, + EAGAIN, ENOTCONN): return None else: raise @@ -769,11 +729,12 @@ class dispatcher: try: retattr = getattr(self.socket, attr) except AttributeError: - raise AttributeError("%s instance has no attribute '%s'" - % (self.__class__.__name__, attr)) + raise AttributeError( + "%s instance has no attribute '%s'" + % (self.__class__.__name__, attr)) else: - msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s " \ - "instead" % {'me': self.__class__.__name__, 'attr': attr} + msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s"\ + " instead" % {'me': self.__class__.__name__, 'attr': attr} warnings.warn(msg, DeprecationWarning, stacklevel=2) return retattr @@ -855,13 +816,8 @@ class dispatcher: self.log_info( 'uncaptured python exception, closing channel %s (%s:%s %s)' % ( - self_repr, - t, - v, - tbinfo - ), - 'error' - ) + self_repr, t, v, tbinfo), + 'error') self.handle_close() def handle_accept(self): @@ -902,11 +858,8 @@ class dispatcher_with_send(dispatcher): adds simple buffered output capability, useful for simple clients. [for more sophisticated usage use asynchat.async_chat] """ - # pylint: disable=redefined-builtin def __init__(self, sock=None, map=None): - # pylint: disable=redefined-builtin - dispatcher.__init__(self, sock, map) self.out_buffer = b'' @@ -941,7 +894,8 @@ def compact_traceback(): """Return a compact traceback""" t, v, tb = sys.exc_info() tbinfo = [] - if not tb: # Must have a traceback + # Must have a traceback + if not tb: raise AssertionError("traceback does not exist") while tb: tbinfo.append(( @@ -961,7 +915,6 @@ def compact_traceback(): def close_all(map=None, ignore_all=False): """Close all connections""" - # pylint: disable=redefined-builtin if map is None: map = socket_map @@ -998,13 +951,13 @@ def close_all(map=None, ignore_all=False): if os.name == 'posix': import fcntl - class file_wrapper: + class file_wrapper: # pylint: disable=old-style-class """ - Here we override just enough to make a file look like a socket for the purposes of asyncore. + Here we override just enough to make a file look + like a socket for the purposes of asyncore. The passed fd is automatically os.dup()'d """ - # pylint: disable=old-style-class def __init__(self, fd): self.fd = os.dup(fd) @@ -1019,12 +972,11 @@ if os.name == 'posix': def getsockopt(self, level, optname, buflen=None): """Fake getsockopt()""" - if (level == socket.SOL_SOCKET and - optname == socket.SO_ERROR and + if (level == socket.SOL_SOCKET and optname == socket.SO_ERROR and not buflen): return 0 - raise NotImplementedError("Only asyncore specific behaviour " - "implemented.") + raise NotImplementedError( + "Only asyncore specific behaviour implemented.") read = recv write = send @@ -1041,8 +993,6 @@ if os.name == 'posix': """A dispatcher for file_wrapper objects""" def __init__(self, fd, map=None): - # pylint: disable=redefined-builtin - dispatcher.__init__(self, None, map) self.connected = True try: diff --git a/src/network/bmobject.py b/src/network/bmobject.py index ac6429e4..12b997d7 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -1,7 +1,6 @@ """ BMObject and it's exceptions. """ - import logging import time @@ -15,12 +14,14 @@ logger = logging.getLogger('default') class BMObjectInsufficientPOWError(Exception): - """Exception indicating the object doesn't have sufficient proof of work.""" + """Exception indicating the object + doesn't have sufficient proof of work.""" errorCodes = ("Insufficient proof of work") class BMObjectInvalidDataError(Exception): - """Exception indicating the data being parsed does not match the specification.""" + """Exception indicating the data being parsed + does not match the specification.""" errorCodes = ("Data invalid") @@ -30,7 +31,8 @@ class BMObjectExpiredError(Exception): class BMObjectUnwantedStreamError(Exception): - """Exception indicating the object is in a stream we didn't advertise as being interested in.""" + """Exception indicating the object is in a stream + we didn't advertise as being interested in.""" errorCodes = ("Object in unwanted stream") @@ -44,9 +46,8 @@ class BMObjectAlreadyHaveError(Exception): errorCodes = ("Already have this object") -class BMObject(object): +class BMObject(object): # pylint: disable=too-many-instance-attributes """Bitmessage Object as a class.""" - # pylint: disable=too-many-instance-attributes # max TTL, 28 days and 3 hours maxTTL = 28 * 24 * 60 * 60 + 10800 @@ -81,31 +82,36 @@ class BMObject(object): raise BMObjectInsufficientPOWError() def checkEOLSanity(self): - """Check if object's lifetime isn't ridiculously far in the past or future.""" + """Check if object's lifetime + isn't ridiculously far in the past or future.""" # EOL sanity check if self.expiresTime - int(time.time()) > BMObject.maxTTL: logger.info( - 'This object\'s End of Life time is too far in the future. Ignoring it. Time is %i', - self.expiresTime) + 'This object\'s End of Life time is too far in the future.' + ' Ignoring it. Time is %i', self.expiresTime) # .. todo:: remove from download queue raise BMObjectExpiredError() if self.expiresTime - int(time.time()) < BMObject.minTTL: logger.info( - 'This object\'s End of Life time was too long ago. Ignoring the object. Time is %i', - self.expiresTime) + 'This object\'s End of Life time was too long ago.' + ' Ignoring the object. Time is %i', self.expiresTime) # .. todo:: remove from download queue raise BMObjectExpiredError() def checkStream(self): """Check if object's stream matches streams we are interested in""" if self.streamNumber not in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %i isn\'t one we are interested in.', self.streamNumber) + logger.debug( + 'The streamNumber %i isn\'t one we are interested in.', + self.streamNumber) raise BMObjectUnwantedStreamError() def checkAlreadyHave(self): """ - Check if we already have the object (so that we don't duplicate it in inventory or advertise it unnecessarily) + Check if we already have the object + (so that we don't duplicate it in inventory + or advertise it unnecessarily) """ # if it's a stem duplicate, pretend we don't have it if Dandelion().hasHash(self.inventoryHash): @@ -114,7 +120,8 @@ class BMObject(object): raise BMObjectAlreadyHaveError() def checkObjectByType(self): - """Call a object type specific check (objects can have additional checks based on their types)""" + """Call a object type specific check + (objects can have additional checks based on their types)""" if self.objectType == protocol.OBJECT_GETPUBKEY: self.checkGetpubkey() elif self.objectType == protocol.OBJECT_PUBKEY: @@ -125,20 +132,21 @@ class BMObject(object): self.checkBroadcast() # other objects don't require other types of tests - def checkMessage(self): + def checkMessage(self): # pylint: disable=no-self-use """"Message" object type checks.""" - # pylint: disable=no-self-use return def checkGetpubkey(self): """"Getpubkey" object type checks.""" if len(self.data) < 42: - logger.info('getpubkey message doesn\'t contain enough data. Ignoring.') + logger.info( + 'getpubkey message doesn\'t contain enough data. Ignoring.') raise BMObjectInvalidError() def checkPubkey(self): """"Pubkey" object type checks.""" - if len(self.data) < 146 or len(self.data) > 440: # sanity check + # sanity check + if len(self.data) < 146 or len(self.data) > 440: logger.info('pubkey object too short or too long. Ignoring.') raise BMObjectInvalidError() @@ -146,8 +154,9 @@ class BMObject(object): """"Broadcast" object type checks.""" if len(self.data) < 180: logger.debug( - 'The payload length of this broadcast packet is unreasonably low.' - ' Someone is probably trying funny business. Ignoring message.') + 'The payload length of this broadcast' + ' packet is unreasonably low. Someone is probably' + ' trying funny business. Ignoring message.') raise BMObjectInvalidError() # this isn't supported anymore diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d620daa3..d5d3dbe3 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -1,8 +1,7 @@ """ -src/network/bmproto.py -================================== +Bitmessage Protocol """ -# pylint: disable=attribute-defined-outside-init +# pylint: disable=attribute-defined-outside-init, too-few-public-methods import base64 import hashlib import logging @@ -19,17 +18,16 @@ import state from bmconfigparser import BMConfigParser from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher -from network.constants import ( - ADDRESS_ALIVE, - MAX_MESSAGE_SIZE, - MAX_OBJECT_COUNT, - MAX_OBJECT_PAYLOAD_SIZE, - MAX_TIME_OFFSET) -from network.dandelion import Dandelion from network.bmobject import ( BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, - BMObjectInvalidError, BMObjectAlreadyHaveError) + BMObjectInvalidError, BMObjectAlreadyHaveError +) +from network.constants import ( + ADDRESS_ALIVE, MAX_MESSAGE_SIZE, MAX_OBJECT_COUNT, + MAX_OBJECT_PAYLOAD_SIZE, MAX_TIME_OFFSET +) +from network.dandelion import Dandelion from network.proxy import ProxyError from node import Node, Peer from objectracker import missingObjects, ObjectTracker @@ -59,7 +57,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # pylint: disable=too-many-instance-attributes, too-many-public-methods timeOffsetWrongCount = 0 - def __init__(self, address=None, sock=None): # pylint: disable=unused-argument, super-init-not-called + def __init__(self, address=None, sock=None): + # pylint: disable=unused-argument, super-init-not-called AdvancedDispatcher.__init__(self, sock) self.isOutbound = False # packet/connection from a local IP @@ -163,7 +162,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def decode_payload_varint(self): """Decode a varint from the payload""" - value, offset = addresses.decodeVarint(self.payload[self.payloadOffset:]) + value, offset = addresses.decodeVarint( + self.payload[self.payloadOffset:]) self.payloadOffset += offset return value @@ -185,8 +185,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return Node(services, host, port) - def decode_payload_content(self, pattern="v"): # pylint: disable=too-many-branches, too-many-statements - + # pylint: disable=too-many-branches, too-many-statements + def decode_payload_content(self, pattern="v"): """ Decode the payload depending on pattern: @@ -202,7 +202,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): , = end of array """ - def decode_simple(self, char="v"): # pylint: disable=inconsistent-return-statements + # pylint: disable=inconsistent-return-statements + def decode_simple(self, char="v"): """Decode the payload using one char pattern""" if char == "v": return self.decode_payload_varint() @@ -312,8 +313,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def bm_command_error(self): """Decode an error message and log it""" - fatalStatus, banTime, inventoryVector, errorText = \ - self.decode_payload_content("vvlsls") + err_values = self.decode_payload_content("vvlsls") + fatalStatus = err_values[0] + # banTime = err_values[1] + # inventoryVector = err_values[2] + errorText = err_values[3] logger.error( '%s:%i error: %i, %s', self.destination.host, self.destination.port, fatalStatus, errorText) @@ -408,8 +412,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): except KeyError: pass - if self.object.inventoryHash in Inventory() and Dandelion().hasHash(self.object.inventoryHash): - Dandelion().removeHash(self.object.inventoryHash, "cycle detection") + if self.object.inventoryHash in Inventory() and Dandelion().hasHash( + self.object.inventoryHash): + Dandelion().removeHash( + self.object.inventoryHash, "cycle detection") Inventory()[self.object.inventoryHash] = ( self.object.objectType, self.object.streamNumber, @@ -428,27 +434,30 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def bm_command_addr(self): """Incoming addresses, process them""" - addresses = self._decode_addr() # pylint: disable=redefined-outer-name - for i in addresses: - seenTime, stream, services, ip, port = i + # pylint: disable=redefined-outer-name + addresses = self._decode_addr() + for seenTime, stream, _, ip, port in addresses: decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if ( - decodedIP and time.time() - seenTime > 0 and - seenTime > time.time() - ADDRESS_ALIVE and - port > 0 + decodedIP and time.time() - seenTime > 0 and + seenTime > time.time() - ADDRESS_ALIVE and + port > 0 ): peer = Peer(decodedIP, port) try: - if knownnodes.knownNodes[stream][peer]["lastseen"] > seenTime: + if knownnodes.knownNodes[stream][peer]["lastseen"] > \ + seenTime: continue except KeyError: pass - if len(knownnodes.knownNodes[stream]) < BMConfigParser().safeGetInt("knownnodes", "maxnodes"): + if len(knownnodes.knownNodes[stream]) < \ + BMConfigParser().safeGetInt("knownnodes", "maxnodes"): with knownnodes.knownNodesLock: try: - knownnodes.knownNodes[stream][peer]["lastseen"] = seenTime + knownnodes.knownNodes[stream][peer]["lastseen"] = \ + seenTime except (TypeError, KeyError): knownnodes.knownNodes[stream][peer] = { "lastseen": seenTime, @@ -539,7 +548,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): length=self.payloadLength, expectBytes=0) return False - def peerValidityChecks(self): # pylint: disable=too-many-return-statements + # pylint: disable=too-many-return-statements + def peerValidityChecks(self): """Check the validity of the peer""" if self.remoteProtocolVersion < 3: self.append_write_buf(protocol.assembleErrorMessage( @@ -551,8 +561,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return False if self.timeOffset > MAX_TIME_OFFSET: self.append_write_buf(protocol.assembleErrorMessage( - errorText="Your time is too far in the future compared to mine." - " Closing connection.", fatal=2)) + errorText="Your time is too far in the future" + " compared to mine. Closing connection.", fatal=2)) logger.info( "%s's time is too far in the future (%s seconds)." " Closing connection to it.", self.destination, self.timeOffset) @@ -574,8 +584,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): errorText="We don't have shared stream interests." " Closing connection.", fatal=2)) logger.debug( - 'Closed connection to %s because there is no overlapping interest' - ' in streams.', self.destination) + 'Closed connection to %s because there is no overlapping' + ' interest in streams.', self.destination) return False if self.destination in connectionpool.BMConnectionPool().inboundConnections: try: @@ -584,8 +594,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): errorText="Too many connections from your IP." " Closing connection.", fatal=2)) logger.debug( - 'Closed connection to %s because we are already connected' - ' to that IP.', self.destination) + 'Closed connection to %s because we are already' + ' connected to that IP.', self.destination) return False except: pass diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 9d2f85d6..badd98b7 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -1,3 +1,6 @@ +""" +Select which node to connect to +""" # pylint: disable=too-many-branches import logging import random # nosec @@ -12,6 +15,7 @@ logger = logging.getLogger('default') def getDiscoveredPeer(): + """Get a peer from the local peer discovery list""" try: peer = random.choice(state.discoveredPeers.keys()) except (IndexError, KeyError): @@ -24,6 +28,7 @@ def getDiscoveredPeer(): def chooseConnection(stream): + """Returns an appropriate connection""" haveOnion = BMConfigParser().safeGet( "bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' onionOnly = BMConfigParser().safeGetBoolean( @@ -49,7 +54,8 @@ def chooseConnection(stream): logger.warning('Error in %s', peer) rating = 0 if haveOnion: - # do not connect to raw IP addresses--keep all traffic within Tor overlay + # do not connect to raw IP addresses + # --keep all traffic within Tor overlay if onionOnly and not peer.host.endswith('.onion'): continue # onion addresses have a higher priority when SOCKS diff --git a/src/network/constants.py b/src/network/constants.py index a3414ef3..f8f4120f 100644 --- a/src/network/constants.py +++ b/src/network/constants.py @@ -3,9 +3,15 @@ Network protocol constants """ -ADDRESS_ALIVE = 10800 #: address is online if online less than this many seconds ago -MAX_ADDR_COUNT = 1000 #: protocol specification says max 1000 addresses in one addr command -MAX_MESSAGE_SIZE = 1600100 #: ~1.6 MB which is the maximum possible size of an inv message. -MAX_OBJECT_PAYLOAD_SIZE = 2**18 #: 2**18 = 256kB is the maximum size of an object payload -MAX_OBJECT_COUNT = 50000 #: protocol specification says max 50000 objects in one inv command -MAX_TIME_OFFSET = 3600 #: maximum time offset +#: address is online if online less than this many seconds ago +ADDRESS_ALIVE = 10800 +#: protocol specification says max 1000 addresses in one addr command +MAX_ADDR_COUNT = 1000 +#: ~1.6 MB which is the maximum possible size of an inv message. +MAX_MESSAGE_SIZE = 1600100 +#: 2**18 = 256kB is the maximum size of an object payload +MAX_OBJECT_PAYLOAD_SIZE = 2**18 +#: protocol specification says max 50000 objects in one inv command +MAX_OBJECT_COUNT = 50000 +#: maximum time offset +MAX_TIME_OFFSET = 3600 diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 0f68cc24..03f45bd7 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,10 +1,9 @@ """ -src/network/dandelion.py -======================== +Dandelion class definition, tracks stages """ import logging from collections import namedtuple -from random import choice, sample, expovariate +from random import choice, expovariate, sample from threading import RLock from time import time @@ -28,7 +27,7 @@ logger = logging.getLogger('default') @Singleton -class Dandelion(): # pylint: disable=old-style-class +class Dandelion: # pylint: disable=old-style-class """Dandelion class for tracking stem/fluff stages.""" def __init__(self): # currently assignable child stems @@ -123,7 +122,8 @@ class Dandelion(): # pylint: disable=old-style-class self.stem.remove(connection) # active mappings to pointing to the removed node for k in ( - k for k, v in self.nodeMap.iteritems() if v == connection + k for k, v in self.nodeMap.iteritems() + if v == connection ): self.nodeMap[k] = None for k, v in { diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index e882f6de..0ae83b5b 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,7 +1,6 @@ """ `DownloadThread` class definition """ - import time import addresses @@ -30,7 +29,9 @@ class DownloadThread(StoppableThread): """Expire pending downloads eventually""" deadline = time.time() - self.requestExpires try: - toDelete = [k for k, v in missingObjects.iteritems() if v < deadline] + toDelete = [ + k for k, v in missingObjects.iteritems() + if v < deadline] except RuntimeError: pass else: diff --git a/src/network/invthread.py b/src/network/invthread.py index d5690486..e68b7692 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,6 +1,5 @@ """ -src/network/invthread.py -======================== +Thread to send inv annoucements """ import Queue import random @@ -34,7 +33,7 @@ def handleExpiredDandelion(expired): class InvThread(StoppableThread): - """A thread to send inv annoucements.""" + """Main thread that sends inv annoucements""" name = "InvBroadcaster" @@ -43,12 +42,13 @@ class InvThread(StoppableThread): """Locally generated inventory items require special handling""" Dandelion().addHash(hashId, stream=stream) for connection in BMConnectionPool().connections(): - if state.dandelion and connection != Dandelion().objectChildStem(hashId): + if state.dandelion and connection != \ + Dandelion().objectChildStem(hashId): continue connection.objectsNewToThem[hashId] = time() - def run(self): # pylint: disable=too-many-branches - while not state.shutdown: # pylint: disable=too-many-nested-blocks + def run(self): # pylint: disable=too-many-branches + while not state.shutdown: # pylint: disable=too-many-nested-blocks chunk = [] while True: # Dandelion fluff trigger by expiration @@ -92,15 +92,17 @@ class InvThread(StoppableThread): random.shuffle(fluffs) connection.append_write_buf(protocol.CreatePacket( 'inv', - addresses.encodeVarint(len(fluffs)) + ''.join(fluffs))) + addresses.encodeVarint( + len(fluffs)) + ''.join(fluffs))) if stems: random.shuffle(stems) connection.append_write_buf(protocol.CreatePacket( 'dinv', - addresses.encodeVarint(len(stems)) + ''.join(stems))) + addresses.encodeVarint( + len(stems)) + ''.join(stems))) invQueue.iterate() - for i in range(len(chunk)): + for _ in range(len(chunk)): invQueue.task_done() if Dandelion().refresh < time(): From 22e22633c213f5b4b01f5e56ef76c8e7639c17e5 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 10 Jan 2020 19:37:51 +0530 Subject: [PATCH 292/306] Added License --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/LICENSE b/LICENSE index d6df32b5..2c718643 100644 --- a/LICENSE +++ b/LICENSE @@ -47,3 +47,24 @@ Redistribution and use in source and binary forms, with or without modification, 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +===== based on asyncore_pollchoose.py asyncore_pollchoose python implementation. by Sam Rushing + +Copyright 1996 by Sam Rushing. All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the name of Sam +Rushing not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN +NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. From e3c56686748e05d2c8e56a5138899b0cb7db5815 Mon Sep 17 00:00:00 2001 From: navjot Date: Mon, 13 Jan 2020 17:12:19 +0530 Subject: [PATCH 293/306] fixed search issue in myaddress --- src/bitmessagekivy/mpybit.py | 35 +++++++++++++++++++---------------- src/state.py | 2 -- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index c937abd1..2b2f9d56 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1574,10 +1574,11 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def closeSearchScreen(self): """Function for close search screen""" self.set_common_header() - address_label = self.current_address_label( - BMConfigParser().get( - state.association, 'label'), state.association) - self.root.ids.toolbar.title = address_label + 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 @@ -1662,8 +1663,12 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods 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()) + if len(self.root.ids.sc17.ids.ml.children) <= 2: + self.root.ids.sc17.clear_widgets() + self.root.ids.sc17.add_widget(Allmails()) + else: + self.root.ids.sc17.ids.ml.clear_widgets() + self.root.ids.sc17.loadMessagelist() try: self.root.ids.sc17.children[1].active = False except Exception: @@ -1860,10 +1865,6 @@ class MailDetail(Screen): self.message = data[0][3] if len(data[0]) == 6: self.status = data[0][4] - state.write_msg = {'to_addr': self.to_addr, - 'from_addr': self.from_addr, - 'subject': self.subject, - 'message': self.message} def delete_mail(self): """Method for mail delete""" @@ -1945,14 +1946,16 @@ class MailDetail(Screen): def write_msg(self, navApp): """Write on draft mail""" state.send_draft_mail = state.mail_id + data = sqlQuery( + "select toaddress, fromaddress, subject, message from sent where" + " ackdata = ?;", str(state.mail_id)) composer_ids = ( self.parent.parent.parent.parent.parent.ids.sc3.children[1].ids) - composer_ids.ti.text = state.write_msg['from_addr'] - composer_ids.btn.text = state.write_msg['from_addr'] - composer_ids.txt_input.text = state.write_msg['to_addr'] - composer_ids.subject.text = state.write_msg[ - 'subject'] if state.write_msg['subject'] != '(no subject)' else '' - composer_ids.body.text = state.write_msg['message'] + 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() diff --git a/src/state.py b/src/state.py index 8abd211d..16bc016e 100644 --- a/src/state.py +++ b/src/state.py @@ -118,8 +118,6 @@ is_allmail = False in_composer = False -write_msg = {} - availabe_credit = 0 in_sent_method = False From b6a81f1252531ff6ebe5b6563e6f17778f905eba Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 15 Jan 2020 16:17:26 +0530 Subject: [PATCH 294/306] Formatting and fix License --- LICENSE | 24 ++++++++++++++++++++++++ src/addresses.py | 2 +- src/bitmessagemain.py | 4 ++-- src/bmconfigparser.py | 6 ++++-- src/class_singleWorker.py | 3 ++- src/class_smtpDeliver.py | 8 +++++--- src/class_smtpServer.py | 6 ++++-- src/class_sqlThread.py | 2 +- src/depends.py | 3 ++- src/namecoin.py | 23 +---------------------- src/shared.py | 4 ++-- src/tr.py | 5 +++-- 12 files changed, 51 insertions(+), 39 deletions(-) diff --git a/LICENSE b/LICENSE index 2c718643..c2eeff82 100644 --- a/LICENSE +++ b/LICENSE @@ -68,3 +68,27 @@ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +===== based on namecoin.py namecoin.py python implementation by Daniel Kraft + +Copyright (C) 2013 by Daniel Kraft + +This file is part of the Bitmessage project. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/addresses.py b/src/addresses.py index bb0c9ec5..04e80383 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -180,7 +180,7 @@ def decodeAddress(address): returns (status, address version number, stream number, data (almost certainly a ripe hash)) """ - # pylint: disable=too-many-return-statements,too-many-statements,too-many-return-statements,too-many-branches + # pylint: disable=too-many-return-statements,too-many-statements,too-many-branches address = str(address).strip() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 48ed9738..17c08fc0 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -412,7 +412,7 @@ class Main(object): # wait until grandchild ready while True: time.sleep(1) - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass @@ -433,7 +433,7 @@ class Main(object): # wait until child ready while True: time.sleep(1) - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access except AttributeError: # fork not implemented pass diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 1851144d..c08ba062 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -58,7 +58,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): raise ValueError("Invalid value %s" % value) return ConfigParser.ConfigParser.set(self, section, option, value) - def get(self, section, option, raw=False, variables=None): # pylint: disable=arguments-differ + def get(self, section, option, raw=False, variables=None): + # pylint: disable=arguments-differ try: if section == "bitmessagesettings" and option == "timeformat": return ConfigParser.ConfigParser.get( @@ -109,8 +110,9 @@ class BMConfigParser(ConfigParser.SafeConfigParser): ValueError, AttributeError): return default - def items(self, section, raw=False, variables=None): # pylint: disable=arguments-differ + def items(self, section, raw=False, variables=None): """Return section variables as parent, but override the "raw" argument to always True""" + # pylint: disable=arguments-differ return ConfigParser.ConfigParser.items(self, section, True, variables) @staticmethod diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index d035c092..e3f93ec6 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -1,7 +1,8 @@ """ Thread for performing PoW """ -# pylint: disable=protected-access,too-many-branches,too-many-statements,no-self-use,too-many-lines,too-many-locals +# pylint: disable=protected-access,too-many-branches,too-many-statements +# pylint: disable=no-self-use,too-many-lines,too-many-locals from __future__ import division diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 14df14c9..4f8422cc 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -22,8 +22,9 @@ class smtpDeliver(StoppableThread): _instance = None def stopThread(self): + # pylint: disable=no-member try: - queues.UISignallerQueue.put(("stopThread", "data")) # pylint: disable=no-member + queues.UISignallerQueue.put(("stopThread", "data")) except: pass super(smtpDeliver, self).stopThread() @@ -37,6 +38,7 @@ class smtpDeliver(StoppableThread): def run(self): # pylint: disable=too-many-branches,too-many-statements,too-many-locals + # pylint: disable=deprecated-lambda while state.shutdown == 0: command, data = queues.UISignalQueue.get() if command == 'writeNewAddressToTable': @@ -59,9 +61,9 @@ class smtpDeliver(StoppableThread): msg = MIMEText(body, 'plain', 'utf-8') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = fromAddress + '@' + SMTPDOMAIN - toLabel = map( # pylint: disable=deprecated-lambda + toLabel = map( lambda y: BMConfigParser().safeGet(y, "label"), - filter( # pylint: disable=deprecated-lambda + filter( lambda x: x == toAddress, BMConfigParser().addresses()) ) if toLabel: diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index cdf867a9..453ca640 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -76,8 +76,9 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): # print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr) self.channel = smtpServerChannel(self, conn, addr) - def send(self, fromAddress, toAddress, subject, message): # pylint: disable=arguments-differ + def send(self, fromAddress, toAddress, subject, message): """Send a bitmessage""" + # pylint: disable=arguments-differ streamNumber, ripe = decodeAddress(toAddress)[2:] stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') ackdata = genAckPayload(streamNumber, stealthLevel) @@ -114,8 +115,9 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): return ret - def process_message(self, peer, mailfrom, rcpttos, data): # pylint: disable=too-many-locals, too-many-branches + def process_message(self, peer, mailfrom, rcpttos, data): """Process an email""" + # pylint: disable=too-many-locals, too-many-branches # print 'Receiving message from:', peer p = re.compile(".*<([^>]+)>") if not hasattr(self.channel, "auth") or not self.channel.auth: diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 3d59803c..78d70f79 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -27,7 +27,7 @@ class sqlThread(threading.Thread): def __init__(self): threading.Thread.__init__(self, name="SQL") - def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements + def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements """Process SQL queries from `.helper_sql.sqlSubmitQueue`""" self.conn = sqlite3.connect(state.appdata + 'messages.dat') self.conn.text_factory = str diff --git a/src/depends.py b/src/depends.py index 68fba01a..03e297f1 100755 --- a/src/depends.py +++ b/src/depends.py @@ -231,12 +231,13 @@ def check_sqlite(): conn.close() -def check_openssl(): # pylint: disable=too-many-branches, too-many-return-statements +def check_openssl(): """Do openssl dependency check. Here we are checking for openssl with its all dependent libraries and version checking. """ + # pylint: disable=too-many-branches, too-many-return-statements # pylint: disable=protected-access, redefined-outer-name ctypes = try_import('ctypes') if not ctypes: diff --git a/src/namecoin.py b/src/namecoin.py index c9238f63..63ca5653 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -1,28 +1,7 @@ -# pylint: disable=too-many-branches,protected-access """ -Copyright (C) 2013 by Daniel Kraft - Namecoin queries """ -# This file is part of the Bitmessage project. - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. +# pylint: disable=too-many-branches,protected-access import base64 import httplib diff --git a/src/shared.py b/src/shared.py index 90cea89d..dfc86ab6 100644 --- a/src/shared.py +++ b/src/shared.py @@ -118,7 +118,7 @@ def decodeWalletImportFormat(WIFstring): ' 6 characters of the PRIVATE key: %s', str(WIFstring)[:6] ) - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access # return "" elif privkey[0] == '\x80': # checksum passed return privkey[1:] @@ -128,7 +128,7 @@ def decodeWalletImportFormat(WIFstring): ' the checksum passed but the key doesn\'t begin with hex 80.' ' Here is the PRIVATE key: %s', WIFstring ) - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access def reloadMyAddressHashes(): diff --git a/src/tr.py b/src/tr.py index 87e67219..ac76ef4b 100644 --- a/src/tr.py +++ b/src/tr.py @@ -25,7 +25,8 @@ class translateClass: return self.text -def _translate(context, text, disambiguation=None, encoding=None, n=None): # pylint: disable=unused-argument +def _translate(context, text, disambiguation=None, encoding=None, n=None): + # pylint: disable=unused-argument return translateText(context, text, n) @@ -45,7 +46,7 @@ def translateText(context, text, n=None): ' or by searching Google for \'PyQt Download\'.'\ ' If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' print 'Error message:', err - os._exit(0) # pylint: disable=protected-access + os._exit(0) # pylint: disable=protected-access if n is None: return QtGui.QApplication.translate(context, text) return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) From 46032753509d20362b23aa38336ca6e0560f93ed Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 20 Jan 2020 15:48:19 +0530 Subject: [PATCH 295/306] too-many values to unpack issue resolved --- src/class_addressGenerator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 9ac39538..a6292628 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -117,7 +117,7 @@ class addressGenerator(StoppableThread): defaults.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': queues.UISignalQueue.put(( - 'updateStatusBar' + 'updateStatusBar', "" )) # This next section is a little bit strange. We're going # to generate keys over and over until we find one @@ -193,7 +193,7 @@ class addressGenerator(StoppableThread): queues.apiAddressGeneratorReturnQueue.put(address) queues.UISignalQueue.put(( - 'updateStatusBar' + 'updateStatusBar', "" )) queues.UISignalQueue.put(('writeNewAddressToTable', ( label, address, streamNumber))) From 3211fca9532aabf87df8db1f934d4a7a912412e1 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 17 Jan 2020 18:57:36 +0530 Subject: [PATCH 296/306] formatting and shorten line length --- src/addresses.py | 4 +- src/api.py | 107 ++++++++++++++++++++-------------- src/bitmessagemain.py | 29 +++++---- src/bmconfigparser.py | 7 ++- src/build_osx.py | 10 +++- src/class_addressGenerator.py | 3 +- src/class_objectProcessor.py | 9 ++- src/class_singleWorker.py | 10 +++- 8 files changed, 109 insertions(+), 70 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index 04e80383..2895e256 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -2,7 +2,6 @@ Operations with addresses """ # pylint: disable=redefined-outer-name,inconsistent-return-statements - import hashlib from binascii import hexlify, unhexlify from struct import pack, unpack @@ -180,7 +179,8 @@ def decodeAddress(address): returns (status, address version number, stream number, data (almost certainly a ripe hash)) """ - # pylint: disable=too-many-return-statements,too-many-statements,too-many-branches + # pylint: disable=too-many-return-statements,too-many-statements + # pylint: disable=too-many-branches address = str(address).strip() diff --git a/src/api.py b/src/api.py index 3201fba5..6652657f 100644 --- a/src/api.py +++ b/src/api.py @@ -1,15 +1,11 @@ -# pylint: disable=too-many-locals,too-many-lines,no-self-use,too-many-public-methods,too-many-branches -# pylint: disable=too-many-statements - -# Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2020 The Bitmessage developers - """ This is not what you run to run the Bitmessage API. Instead, enable the API ( https://bitmessage.org/wiki/API ) and optionally enable daemon mode ( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py. """ - +# Copyright (c) 2012-2016 Jonathan Warren +# Copyright (c) 2012-2020 The Bitmessage developers +# pylint: disable=too-many-lines,no-self-use,unused-variable,unused-argument import base64 import errno import hashlib @@ -33,7 +29,13 @@ import queues import shared import shutdown import state -from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError +from addresses import ( + addBMIfNotPresent, + calculateInventoryHash, + decodeAddress, + decodeVarint, + varintDecodeError +) from bmconfigparser import BMConfigParser from debug import logger from helper_ackPayload import genAckPayload @@ -136,9 +138,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): """ This is one of several classes that constitute the API - This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros). + This class was written by Vaibhav Bhatia. + Modified by Jonathan Warren (Atheros). http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ """ + # pylint: disable=too-many-public-methods def do_POST(self): """ @@ -175,7 +179,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # SimpleXMLRPCDispatcher. To maintain backwards compatibility, # check to see if a subclass implements _dispatch and dispatch # using that method if present. - response = self.server._marshaled_dispatch( # pylint: disable=protected-access + # pylint: disable=protected-access + response = self.server._marshaled_dispatch( data, getattr(self, '_dispatch', None) ) except BaseException: # This should only happen if the module is buggy @@ -213,8 +218,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): _, encstr = self.headers.get('Authorization').split() emailid, password = encstr.decode('base64').split(':') return ( - emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and - password == BMConfigParser().get('bitmessagesettings', 'apipassword') + emailid == BMConfigParser().get( + 'bitmessagesettings', 'apiusername') and + password == BMConfigParser().get( + 'bitmessagesettings', 'apipassword') ) else: logger.warning( @@ -251,10 +258,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if status == 'invalidcharacters': raise APIError(9, 'Invalid characters in address: ' + address) if status == 'versiontoohigh': - raise APIError(10, 'Address version number too high (or zero) in address: ' + address) + raise APIError( + 10, + 'Address version number too high (or zero) in address: ' + + address) if status == 'varintmalformed': raise APIError(26, 'Malformed varint in address: ' + address) - raise APIError(7, 'Could not decode address: %s : %s' % (address, status)) + raise APIError( + 7, 'Could not decode address: %s : %s' % (address, status)) if addressVersionNumber < 2 or addressVersionNumber > 4: raise APIError( 11, 'The address version number currently must be 2, 3 or 4.' @@ -272,10 +283,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleListAddresses(self, method): """Handle a request to list addresses""" - data = '{"addresses":[' for addressInKeysFile in BMConfigParser().addresses(): - status, addressVersionNumber, streamNumber, hash01 = decodeAddress( # pylint: disable=unused-variable + status, addressVersionNumber, streamNumber, hash01 = decodeAddress( addressInKeysFile) if len(data) > 20: data += ',' @@ -379,16 +389,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * + totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * + totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * + smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -406,6 +419,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleCreateDeterministicAddresses(self, params): """Handle a request to create a deterministic address""" + # pylint: disable=too-many-branches, too-many-statements if not params: raise APIError(0, 'I need parameters!') @@ -461,7 +475,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * + totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') @@ -470,9 +485,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): streamNumber, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * + totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * + smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if not passphrase: @@ -606,9 +623,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = str_chan + ' ' + passphrase except BaseException: label = str_chan + ' ' + repr(passphrase) - - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress( # pylint: disable=unused-variable - suppliedAddress) + status, addressVersionNumber, streamNumber, toRipe = ( + self._verifyAddress(suppliedAddress)) suppliedAddress = addBMIfNotPresent(suppliedAddress) queues.apiAddressGeneratorReturnQueue.queue.clear() queues.addressGeneratorQueue.put(( @@ -631,8 +647,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - # pylint: disable=unused-variable - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) + status, addressVersionNumber, streamNumber, toRipe = ( + self._verifyAddress(address)) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -653,8 +669,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - # pylint: disable=unused-variable - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) + status, addressVersionNumber, streamNumber, toRipe = ( + self._verifyAddress(address)) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -666,7 +682,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.reloadMyAddressHashes() return 'success' - def HandleGetAllInboxMessages(self, params): # pylint: disable=unused-argument + def HandleGetAllInboxMessages(self, params): """Handle a request to get all inbox messages""" queryreturn = sqlQuery( @@ -694,7 +710,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllInboxMessageIds(self, params): # pylint: disable=unused-argument + def HandleGetAllInboxMessageIds(self, params): """Handle a request to get all inbox message IDs""" queryreturn = sqlQuery( @@ -753,7 +769,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessages(self, params): # pylint: disable=unused-argument + def HandleGetAllSentMessages(self, params): """Handle a request to get all sent messages""" queryreturn = sqlQuery( @@ -782,7 +798,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessageIds(self, params): # pylint: disable=unused-argument + def HandleGetAllSentMessageIds(self, params): """Handle a request to get all sent message IDs""" queryreturn = sqlQuery( @@ -873,7 +889,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, \ - encodingtype, status, ackdata = row # pylint: disable=unused-variable + encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: @@ -952,7 +968,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid) return 'Trashed sent message (assuming message existed).' - def HandleSendMessage(self, params): + def HandleSendMessage(self, params): # pylint: disable=too-many-locals """Handle a request to send a message""" if not params: @@ -983,7 +999,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 28 * 24 * 60 * 60 toAddress = addBMIfNotPresent(toAddress) fromAddress = addBMIfNotPresent(fromAddress) - # pylint: disable=unused-variable status, addressVersionNumber, streamNumber, toRipe = \ self._verifyAddress(toAddress) self._verifyAddress(fromAddress) @@ -1157,10 +1172,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' - def ListSubscriptions(self, params): # pylint: disable=unused-argument + def ListSubscriptions(self, params): """Handle a request to list susbcriptions""" - # pylint: disable=unused-variable queryreturn = sqlQuery( "SELECT label, address, enabled FROM subscriptions") data = {'subscriptions': []} @@ -1195,12 +1209,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): ) with shared.printLock: print( - '(For msg message via API) Doing proof of work. Total required difficulty:', + '(For msg message via API) Doing proof of work.' + 'Total required difficulty:', float( requiredAverageProofOfWorkNonceTrialsPerByte ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', - float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes, + float( + requiredPayloadLengthExtraBytes + ) / defaults.networkDefaultPayloadLengthExtraBytes, ) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() @@ -1209,8 +1226,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce try: print( - 'POW took', int(time.time() - powStartTime), 'seconds.', - nonce / (time.time() - powStartTime), 'nonce trials per second.', + 'POW took', int(time.time() - powStartTime), + 'seconds.', nonce / (time.time() - powStartTime), + 'nonce trials per second.', ) except BaseException: pass @@ -1237,7 +1255,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata) return 'Trashed sent message (assuming message existed).' - def HandleDissimatePubKey(self, params): # pylint: disable=unused-argument + def HandleDissimatePubKey(self, params): """Handle a request to disseminate a public key""" # The device issuing this command to PyBitmessage supplies a pubkey @@ -1266,7 +1284,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): pubkeyReadPosition += 8 else: pubkeyReadPosition += 4 - # pylint: disable=unused-variable addressVersion, addressVersionLength = decodeVarint( payload[pubkeyReadPosition:pubkeyReadPosition + 10]) pubkeyReadPosition += addressVersionLength @@ -1325,7 +1342,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleClientStatus(self, params): # pylint: disable=unused-argument + def HandleClientStatus(self, params): """Handle a request to get the status of the client""" connections_num = len(network.stats.connectedHostsList()) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 17c08fc0..770173b9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -9,7 +9,6 @@ The PyBitmessage startup script # Right now, PyBitmessage only support connecting to stream 1. It doesn't # yet contain logic to expand into further streams. - import os import sys @@ -46,14 +45,15 @@ from inventory import Inventory from knownnodes import readKnownNodes # Network objects and threads from network import ( - BMConnectionPool, Dandelion, - AddrThread, AnnounceThread, BMNetworkThread, InvThread, ReceiveQueueThread, - DownloadThread, UploadThread) + BMConnectionPool, Dandelion, AddrThread, AnnounceThread, BMNetworkThread, + InvThread, ReceiveQueueThread, DownloadThread, UploadThread +) from singleinstance import singleinstance # Synchronous threads from threads import ( - set_thread_name, - addressGenerator, objectProcessor, singleCleaner, singleWorker, sqlThread) + set_thread_name, addressGenerator, objectProcessor, singleCleaner, + singleWorker, sqlThread +) def connectToStream(streamNumber): @@ -90,7 +90,8 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): - """Converting an IP address in packed binary format to string format""" + """Converting an IP address in packed + binary format to string format""" if family == socket.AF_INET: if len(host) != 4: raise ValueError("invalid IPv4 host") @@ -112,7 +113,8 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): - """Converting an IP address in string format to a packed binary format""" + """Converting an IP address in string format + to a packed binary format""" buf = "\0" * 28 lengthBuf = pack("I", len(buf)) if stringToAddress(str(host), @@ -153,8 +155,8 @@ def signal_handler(signum, frame): if thread.name not in ("PyBitmessage", "MainThread"): return logger.error("Got signal %i", signum) - # there are possible non-UI variants to run bitmessage which should shutdown - # especially test-mode + # there are possible non-UI variants to run bitmessage + # which should shutdown especially test-mode if shared.thisapp.daemon or not state.enableGUI: shutdown.doCleanShutdown() else: @@ -386,10 +388,13 @@ class Main(object): while state.shutdown == 0: time.sleep(1) if ( - state.testmode and time.time() - state.last_api_response >= 30): + state.testmode and time.time() - + state.last_api_response >= 30 + ): self.stop() elif not state.enableGUI: - from tests import core as test_core # pylint: disable=relative-import + # pylint: disable=relative-import + from tests import core as test_core test_core_result = test_core.run() state.enableGUI = True self.stop() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index c08ba062..abef971a 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -47,6 +47,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): Singleton class inherited from :class:`ConfigParser.SafeConfigParser` with additional methods specific to bitmessage config. """ + # pylint: disable=too-many-ancestors _temp = {} @@ -95,7 +96,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return False def safeGetInt(self, section, field, default=0): - """Return value as integer, default on exceptions, 0 if default missing""" + """Return value as integer, default on exceptions, + 0 if default missing""" try: return self.getint(section, field) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, @@ -111,7 +113,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return default def items(self, section, raw=False, variables=None): - """Return section variables as parent, but override the "raw" argument to always True""" + """Return section variables as parent, + but override the "raw" argument to always True""" # pylint: disable=arguments-differ return ConfigParser.ConfigParser.items(self, section, True, variables) diff --git a/src/build_osx.py b/src/build_osx.py index 7ab74dc2..c929f48a 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -13,8 +13,14 @@ DATA_FILES = [ ('bitmsghash', ['bitmsghash/bitmsghash.cl', 'bitmsghash/bitmsghash.so']), ('translations', glob('translations/*.qm')), ('ui', glob('bitmessageqt/*.ui')), - ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??.qm')), - ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??_??.qm')), + ( + 'translations', + glob(os.path.join(str(QtCore.QLibraryInfo.location( + QtCore.QLibraryInfo.TranslationsPath)), 'qt_??.qm'))), + ( + 'translations', + glob(os.path.join(str(QtCore.QLibraryInfo.location( + QtCore.QLibraryInfo.TranslationsPath)), 'qt_??_??.qm'))), ] setup( diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 9e19cf50..5fbf7633 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -36,7 +36,8 @@ class addressGenerator(StoppableThread): Process the requests for addresses generation from `.queues.addressGeneratorQueue` """ - # pylint: disable=too-many-locals, too-many-branches, protected-access, too-many-statements + # pylint: disable=too-many-locals, too-many-branches + # pylint: disable=protected-access, too-many-statements while state.shutdown == 0: queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 1a2f7751..a2151482 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -1,6 +1,9 @@ """ -The objectProcessor thread, of which there is only one, processes the network objects +The objectProcessor thread, of which there is only one, +processes the network objects """ +# pylint: disable=too-many-locals,too-many-return-statements +# pylint: disable=too-many-branches,too-many-statements import hashlib import logging import random @@ -34,7 +37,6 @@ import tr from fallback import RIPEMD160Hash import l10n -# pylint: disable=too-many-locals, too-many-return-statements, too-many-branches, too-many-statements logger = logging.getLogger('default') @@ -647,7 +649,8 @@ class objectProcessor(threading.Thread): if decodeAddress(toAddress)[1] >= 3 \ and not BMConfigParser().safeGetBoolean(toAddress, 'chan'): # If I'm not friendly with this person: - if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress): + if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist( + fromAddress): requiredNonceTrialsPerByte = BMConfigParser().getint( toAddress, 'noncetrialsperbyte') requiredPayloadLengthExtraBytes = BMConfigParser().getint( diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index e3f93ec6..6d7514d4 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -24,7 +24,9 @@ import queues import shared import state import tr -from addresses import calculateInventoryHash, decodeAddress, decodeVarint, encodeVarint +from addresses import ( + calculateInventoryHash, decodeAddress, decodeVarint, encodeVarint +) from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlQuery from inventory import Inventory @@ -237,11 +239,13 @@ class singleWorker(StoppableThread): return payload def doPOWForMyV2Pubkey(self, adressHash): - """ This function also broadcasts out the pubkey message once it is done with the POW""" + """ This function also broadcasts out the pubkey + message once it is done with the POW""" # Look up my stream number based on my address hash myAddress = shared.myAddressesByHash[adressHash] # status - _, addressVersionNumber, streamNumber, adressHash = decodeAddress(myAddress) + _, addressVersionNumber, streamNumber, adressHash = ( + decodeAddress(myAddress)) # 28 days from now plus or minus five minutes TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300)) From 6139efc377a24efa6238080efaef1caa5f6802a6 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 24 Jan 2020 19:46:05 +0530 Subject: [PATCH 297/306] Imported packages sequencing and formatting 2 --- src/messagetypes/__init__.py | 2 +- src/network/announcethread.py | 1 - src/network/bmproto.py | 10 +++++----- src/network/receivequeuethread.py | 2 +- src/network/socks4a.py | 2 +- src/network/tls.py | 5 ++--- src/plugins/menu_qrcode.py | 2 +- src/plugins/proxyconfig_stem.py | 2 +- src/plugins/sound_canberra.py | 3 +-- src/pyelliptic/__init__.py | 4 ++-- src/pyelliptic/openssl.py | 4 ++-- src/storage/filesystem.py | 6 +++--- src/storage/sqlite.py | 4 ++-- 13 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index af6bcdaa..4cae718c 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,6 +1,6 @@ import logging from importlib import import_module -from os import path, listdir +from os import listdir, path from string import lower import messagetypes diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 17c8bcd3..19038ab6 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -4,7 +4,6 @@ Announce myself (node address) import time import state - from bmconfigparser import BMConfigParser from network.assemble import assemble_addr from network.connectionpool import BMConnectionPool diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d5d3dbe3..2dcd1208 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -19,9 +19,9 @@ from bmconfigparser import BMConfigParser from inventory import Inventory from network.advanceddispatcher import AdvancedDispatcher from network.bmobject import ( - BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, - BMObjectExpiredError, BMObjectUnwantedStreamError, - BMObjectInvalidError, BMObjectAlreadyHaveError + BMObject, BMObjectAlreadyHaveError, BMObjectExpiredError, + BMObjectInsufficientPOWError, BMObjectInvalidDataError, + BMObjectInvalidError, BMObjectUnwantedStreamError ) from network.constants import ( ADDRESS_ALIVE, MAX_MESSAGE_SIZE, MAX_OBJECT_COUNT, @@ -30,8 +30,8 @@ from network.constants import ( from network.dandelion import Dandelion from network.proxy import ProxyError from node import Node, Peer -from objectracker import missingObjects, ObjectTracker -from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue +from objectracker import ObjectTracker, missingObjects +from queues import addrQueue, invQueue, objectProcessorQueue, portCheckerQueue from randomtrackingdict import RandomTrackingDict logger = logging.getLogger('default') diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 1f5533b3..bf1d8300 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -6,8 +6,8 @@ import Queue import socket import state -from network.connectionpool import BMConnectionPool from network.advanceddispatcher import UnknownStateError +from network.connectionpool import BMConnectionPool from queues import receiveDataQueue from threads import StoppableThread diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 42eab4b7..0d4310bc 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -5,7 +5,7 @@ SOCKS4a proxy module import socket import struct -from proxy import Proxy, ProxyError, GeneralProxyError +from proxy import GeneralProxyError, Proxy, ProxyError class Socks4aError(ProxyError): diff --git a/src/network/tls.py b/src/network/tls.py index f756591c..1b325696 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -7,11 +7,10 @@ import socket import ssl import sys -from network.advanceddispatcher import AdvancedDispatcher import network.asyncore_pollchoose as asyncore - -from queues import receiveDataQueue import paths +from network.advanceddispatcher import AdvancedDispatcher +from queues import receiveDataQueue logger = logging.getLogger('default') diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py index 63644db6..ea322a49 100644 --- a/src/plugins/menu_qrcode.py +++ b/src/plugins/menu_qrcode.py @@ -6,7 +6,7 @@ A menu plugin showing QR-Code for bitmessage address in modal dialog. import urllib import qrcode -from PyQt4 import QtGui, QtCore +from PyQt4 import QtCore, QtGui from pybitmessage.tr import _translate diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index bc760ef1..7e8dc089 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -11,8 +11,8 @@ Configure tor proxy and hidden service with * otherwise use stem's 'BEST' version and save onion keys to the new section using *onionhostname* as name for future use. """ -import os import logging +import os import random # noseq import tempfile diff --git a/src/plugins/sound_canberra.py b/src/plugins/sound_canberra.py index 20bd054d..9fea8197 100644 --- a/src/plugins/sound_canberra.py +++ b/src/plugins/sound_canberra.py @@ -3,9 +3,8 @@ Sound theme plugin using pycanberra """ -from pybitmessage.bitmessageqt import sound - import pycanberra +from pybitmessage.bitmessageqt import sound _canberra = pycanberra.Canberra() diff --git a/src/pyelliptic/__init__.py b/src/pyelliptic/__init__.py index 65279ded..dbc1b2af 100644 --- a/src/pyelliptic/__init__.py +++ b/src/pyelliptic/__init__.py @@ -9,11 +9,11 @@ For modern cryptography with ECC, AES, HMAC, Blowfish, ... This is an abandoned package maintained inside of the PyBitmessage. """ -from .openssl import OpenSSL +from .cipher import Cipher from .ecc import ECC from .eccblind import ECCBlind -from .cipher import Cipher from .hash import hmac_sha256, hmac_sha512, pbkdf2 +from .openssl import OpenSSL __version__ = '1.3' diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index f769f0e3..4933ac44 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -6,9 +6,9 @@ This module loads openssl libs with ctypes and incapsulates needed openssl functionality in class _OpenSSL. """ -# pylint: disable=protected-access -import sys import ctypes +import sys +# pylint: disable=protected-access OpenSSL = None diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index 571a16c1..b19d9272 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -1,14 +1,14 @@ """ Module for using filesystem (directory with files) for inventory storage """ +import string +import time from binascii import hexlify, unhexlify from os import listdir, makedirs, path, remove, rmdir -import string from threading import RLock -import time from paths import lookupAppdataFolder -from storage import InventoryStorage, InventoryItem +from storage import InventoryItem, InventoryStorage class FilesystemInventory(InventoryStorage): diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 7f41abc5..0992c00e 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -5,8 +5,8 @@ import sqlite3 import time from threading import RLock -from helper_sql import sqlQuery, SqlBulkExecute, sqlExecute -from storage import InventoryStorage, InventoryItem +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery +from storage import InventoryItem, InventoryStorage class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors From 6f35da4096770a668c4944c3024cd7ddb34be092 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 24 Jan 2020 19:33:13 +0530 Subject: [PATCH 298/306] Imported packages sequencing and formatting --- src/addresses.py | 1 - src/api.py | 3 +-- src/bitmessagecli.py | 10 +++++----- src/bitmessagemain.py | 2 +- src/bmconfigparser.py | 2 +- src/build_osx.py | 2 +- src/class_addressGenerator.py | 16 ++++++++-------- src/class_objectProcessor.py | 30 ++++++++++++++---------------- src/class_singleCleaner.py | 2 +- src/class_sqlThread.py | 15 +++++++-------- src/helper_ackPayload.py | 2 +- src/helper_msgcoding.py | 10 +++++----- src/helper_random.py | 2 ++ src/helper_sql.py | 2 +- src/inventory.py | 2 +- src/l10n.py | 1 - src/main.py | 2 +- src/namecoin.py | 4 ++-- src/openclpow.py | 6 +++--- src/paths.py | 1 - src/protocol.py | 2 +- src/qidenticon.py | 4 ++-- src/shared.py | 7 ++++--- src/threads.py | 12 ++++++------ 24 files changed, 68 insertions(+), 72 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index 2895e256..0d3d4400 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -8,7 +8,6 @@ from struct import pack, unpack from debug import logger - ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" diff --git a/src/api.py b/src/api.py index 6652657f..70da0cda 100644 --- a/src/api.py +++ b/src/api.py @@ -18,8 +18,6 @@ from binascii import hexlify, unhexlify from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from struct import pack -from version import softwareVersion - import defaults import helper_inbox import helper_sent @@ -42,6 +40,7 @@ from helper_ackPayload import genAckPayload from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure from inventory import Inventory from network.threads import StoppableThread +from version import softwareVersion str_chan = '[chan]' diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 02fed7e9..01dbc9bb 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -13,15 +13,15 @@ TODO: fix the following (currently ignored) violations: """ -import xmlrpclib import datetime import imghdr -import ntpath import json -import socket -import time -import sys +import ntpath import os +import socket +import sys +import time +import xmlrpclib from bmconfigparser import BMConfigParser diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 770173b9..d6cb289b 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -33,8 +33,8 @@ from struct import pack import defaults import shared -import state import shutdown +import state from bmconfigparser import BMConfigParser from debug import logger # this should go before any threads from helper_startup import ( diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index abef971a..328cf0c7 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -3,8 +3,8 @@ BMConfigParser class definition and default configuration settings """ import ConfigParser -import shutil import os +import shutil from datetime import datetime import state diff --git a/src/build_osx.py b/src/build_osx.py index c929f48a..83d2f280 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,6 +1,6 @@ """Building osx.""" -from glob import glob import os +from glob import glob from PyQt4 import QtCore from setuptools import setup diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 5fbf7633..3df6501f 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -1,22 +1,22 @@ """ A thread for creating addresses """ -import time import hashlib +import time from binascii import hexlify -from pyelliptic import arithmetic -from pyelliptic.openssl import OpenSSL -import tr -import queues -import state -import shared import defaults import highlevelcrypto -from bmconfigparser import BMConfigParser +import queues +import shared +import state +import tr from addresses import decodeAddress, encodeAddress, encodeVarint +from bmconfigparser import BMConfigParser from fallback import RIPEMD160Hash from network import StoppableThread +from pyelliptic import arithmetic +from pyelliptic.openssl import OpenSSL class addressGenerator(StoppableThread): diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index a2151482..824580c2 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -12,31 +12,29 @@ import time from binascii import hexlify from subprocess import call # nosec -import highlevelcrypto -import knownnodes -import shared -from addresses import ( - calculateInventoryHash, decodeAddress, decodeVarint, encodeAddress, - encodeVarint, varintDecodeError -) -from bmconfigparser import BMConfigParser - import helper_bitcoin import helper_inbox import helper_msgcoding import helper_sent -from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery -from helper_ackPayload import genAckPayload -from network import bmproto -from network.node import Peer - +import highlevelcrypto +import knownnodes +import l10n import protocol import queues +import shared import state import tr +from addresses import ( + calculateInventoryHash, decodeAddress, decodeVarint, + encodeAddress, encodeVarint, varintDecodeError +) +from bmconfigparser import BMConfigParser from fallback import RIPEMD160Hash - -import l10n +from helper_ackPayload import genAckPayload +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery +from network import bmproto +from network.node import Peer +# pylint: disable=too-many-locals, too-many-return-statements, too-many-branches, too-many-statements logger = logging.getLogger('default') diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 68a5e727..b9fe3d1c 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -29,7 +29,7 @@ import shared import state import tr from bmconfigparser import BMConfigParser -from helper_sql import sqlQuery, sqlExecute +from helper_sql import sqlExecute, sqlQuery from inventory import Inventory from network import BMConnectionPool, StoppableThread diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 78d70f79..7e9eb6c5 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -2,15 +2,12 @@ sqlThread is defined here """ -import threading -from bmconfigparser import BMConfigParser - -import sqlite3 -import time -import shutil # used for moving the messages.dat file -import sys import os -from debug import logger +import shutil # used for moving the messages.dat file +import sqlite3 +import sys +import threading +import time import helper_sql import helper_startup @@ -18,6 +15,8 @@ import paths import queues import state import tr +from bmconfigparser import BMConfigParser +from debug import logger # pylint: disable=attribute-defined-outside-init,protected-access diff --git a/src/helper_ackPayload.py b/src/helper_ackPayload.py index dcce3153..d30f4c0d 100644 --- a/src/helper_ackPayload.py +++ b/src/helper_ackPayload.py @@ -5,8 +5,8 @@ This module is for generating ack payload from binascii import hexlify from struct import pack -import highlevelcrypto import helper_random +import highlevelcrypto from addresses import encodeVarint diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index ae2bf80b..76dad423 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -5,6 +5,11 @@ Message encoding end decoding functions import string import zlib +import messagetypes +from bmconfigparser import BMConfigParser +from debug import logger +from tr import _translate + try: import msgpack except ImportError: @@ -13,11 +18,6 @@ except ImportError: except ImportError: import fallback.umsgpack.umsgpack as msgpack -import messagetypes -from bmconfigparser import BMConfigParser -from debug import logger -from tr import _translate - BITMESSAGE_ENCODING_IGNORE = 0 BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 diff --git a/src/helper_random.py b/src/helper_random.py index 0785c737..9a29d5e2 100644 --- a/src/helper_random.py +++ b/src/helper_random.py @@ -2,7 +2,9 @@ import os import random + from pyelliptic.openssl import OpenSSL + NoneType = type(None) diff --git a/src/helper_sql.py b/src/helper_sql.py index e7f2a60e..9b5dc29d 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -16,8 +16,8 @@ SQLite objects can only be used from one thread. or isn't thread-safe. """ -import threading import Queue +import threading sqlSubmitQueue = Queue.Queue() """the queue for SQL""" diff --git a/src/inventory.py b/src/inventory.py index 4b9ad226..fc06e455 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,8 +1,8 @@ """The Inventory singleton""" # TODO make this dynamic, and watch out for frozen, like with messagetypes -import storage.sqlite import storage.filesystem +import storage.sqlite from bmconfigparser import BMConfigParser from singleton import Singleton diff --git a/src/l10n.py b/src/l10n.py index bdfb03b3..7a78525b 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -7,7 +7,6 @@ import time from bmconfigparser import BMConfigParser - logger = logging.getLogger('default') diff --git a/src/main.py b/src/main.py index 969dbe56..71a4cb50 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,6 @@ """This module is for thread start.""" -from bitmessagemain import main import state +from bitmessagemain import main if __name__ == '__main__': state.kivy = True diff --git a/src/namecoin.py b/src/namecoin.py index 63ca5653..ae2bde79 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -10,11 +10,11 @@ import os import socket import sys -from addresses import decodeAddress -from debug import logger import defaults import tr # translate +from addresses import decodeAddress from bmconfigparser import BMConfigParser +from debug import logger configSection = "bitmessagesettings" diff --git a/src/openclpow.py b/src/openclpow.py index fad25fa3..35bf46d2 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -2,14 +2,14 @@ """ Module for Proof of Work using OpenCL """ -from struct import pack, unpack import hashlib import os +from struct import pack, unpack -from bmconfigparser import BMConfigParser import paths -from state import shutdown +from bmconfigparser import BMConfigParser from debug import logger +from state import shutdown libAvailable = True ctx = False diff --git a/src/paths.py b/src/paths.py index 59bc5e42..e2f8c97e 100644 --- a/src/paths.py +++ b/src/paths.py @@ -8,7 +8,6 @@ import sys from datetime import datetime from shutil import move - logger = logging.getLogger('default') # When using py2exe or py2app, the variable frozen is added to the sys diff --git a/src/protocol.py b/src/protocol.py index cdd50dce..4f2d0856 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -11,7 +11,7 @@ import socket import sys import time from binascii import hexlify -from struct import pack, unpack, Struct +from struct import Struct, pack, unpack import defaults import highlevelcrypto diff --git a/src/qidenticon.py b/src/qidenticon.py index deafc570..6eab09cd 100644 --- a/src/qidenticon.py +++ b/src/qidenticon.py @@ -11,8 +11,8 @@ Return a PIL Image class instance which have generated identicon image. """ from PyQt4 import QtGui -from PyQt4.QtCore import QSize, QPointF, Qt -from PyQt4.QtGui import QPixmap, QPainter, QPolygonF +from PyQt4.QtCore import QPointF, QSize, Qt +from PyQt4.QtGui import QPainter, QPixmap, QPolygonF class IdenticonRendererBase(object): diff --git a/src/shared.py b/src/shared.py index dfc86ab6..beed52ed 100644 --- a/src/shared.py +++ b/src/shared.py @@ -10,12 +10,11 @@ from __future__ import division # Libraries. import hashlib import os -import sys import stat -import threading import subprocess +import sys +import threading from binascii import hexlify -from pyelliptic import arithmetic # Project imports. import highlevelcrypto @@ -25,6 +24,8 @@ from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlQuery +from pyelliptic import arithmetic + verbose = 1 # This is obsolete with the change to protocol v3 diff --git a/src/threads.py b/src/threads.py index 08d61196..b7471508 100644 --- a/src/threads.py +++ b/src/threads.py @@ -15,6 +15,12 @@ There are also other threads in the `.network` package. import threading +from class_addressGenerator import addressGenerator +from class_objectProcessor import objectProcessor +from class_singleCleaner import singleCleaner +from class_singleWorker import singleWorker +from class_sqlThread import sqlThread + try: import prctl except ImportError: @@ -33,12 +39,6 @@ else: threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap threading.Thread._Thread__bootstrap = _thread_name_hack -from class_addressGenerator import addressGenerator -from class_objectProcessor import objectProcessor -from class_singleCleaner import singleCleaner -from class_singleWorker import singleWorker -from class_sqlThread import sqlThread - __all__ = [ "addressGenerator", "objectProcessor", "singleCleaner", "singleWorker", From 11bec55be56e73502fbd569bf0327a8876b54315 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Feb 2020 20:34:45 +0800 Subject: [PATCH 299/306] Don't put addresses into queue - attempt to fix #1598 - seems to work - addresses won't be uploaded/announced anymore other than after connecting, Later I need to find out how to announce them without causing problems, but for the time disabling this seems an acceptable drawback --- src/network/bmproto.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 2dcd1208..64bde74c 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -31,7 +31,7 @@ from network.dandelion import Dandelion from network.proxy import ProxyError from node import Node, Peer from objectracker import ObjectTracker, missingObjects -from queues import addrQueue, invQueue, objectProcessorQueue, portCheckerQueue +from queues import invQueue, objectProcessorQueue, portCheckerQueue from randomtrackingdict import RandomTrackingDict logger = logging.getLogger('default') @@ -466,8 +466,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker): } # since we don't track peers outside of knownnodes, # only spread if in knownnodes to prevent flood - addrQueue.put((stream, peer, seenTime, - self.destination)) + # DISABLED TO WORKAROUND FLOOD/LEAK + # addrQueue.put((stream, peer, seenTime, + # self.destination)) return True def bm_command_portcheck(self): From 3fb34370a761659f0d0cdbb70e31f91d1420a0ee Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 11 Feb 2020 23:48:10 +0800 Subject: [PATCH 300/306] Wine build script update - update and clean up and make sure it works - it builds the binary but I haven't tried to run the binary - it probably still missing some fine tuning, OpenCL probably doesn't work --- buildscripts/builder.sh | 173 ----------------------- buildscripts/winbuild.sh | 164 +++++++++++++++++++++ packages/pyinstaller/bitmessagemain.spec | 4 +- 3 files changed, 166 insertions(+), 175 deletions(-) delete mode 100755 buildscripts/builder.sh create mode 100755 buildscripts/winbuild.sh diff --git a/buildscripts/builder.sh b/buildscripts/builder.sh deleted file mode 100755 index 07949fa4..00000000 --- a/buildscripts/builder.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash - -# INIT -MACHINE_TYPE=`uname -m` -BASE_DIR=$(pwd) -PYTHON_VERSION=2.7.15 -PYQT_VERSION=4-4.11.4-gpl-Py2.7-Qt4.8.7 -OPENSSL_VERSION=1_0_2t -DIRECTORY32BIT=SoftwareDownloads32bit -DIRECTORY64BIT=SoftwareDownloads64bit - -if [ ${MACHINE_TYPE} == 'x86_64' ]; then - if [ ! -d "$DIRECTORY64BIT" ]; then - mkdir SoftwareDownloads64bit - cd SoftwareDownloads64bit - else - echo "Directory already exists" - cd SoftwareDownloads64bit - fi -else - if [ ! -d "$DIRECTORY32BIT" ]; then - mkdir SoftwareDownloads32bit - cd SoftwareDownloads32bit - else - echo "Directory 32 bit alrready exists" - cd SoftwareDownloads32bit - fi -fi -#Functions -function install_wine { - - - wget -nc https://dl.winehq.org/wine-builds/Release.key --no-check-certificate - sudo apt-key add Release.key - sudo apt-add-repository 'https://dl.winehq.org/wine-builds/ubuntu/' - sudo apt-get -y update - sudo apt-get -y install wine1.8 winetricks - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - sudo apt-get -y install wine64-development - env WINEPREFIX=$HOME/.wine64 WINEARCH=win64 winecfg - WINE="env WINEPREFIX=$HOME/.wine64 wine" - export WINEPREFIX - - else - sudo apt-get -y install wine32-development - env WINEPREFIX=$HOME/.wine32 WINEARCH=win32 winecfg - WINE="env WINEPREFIX=$HOME/.wine32 wine" - export WINEPREFIX - - fi -} - -function install_python(){ - echo "Download Python2.7" - - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - # For 64 bit machine - wget -nc wget http://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.amd64.msi --no-check-certificate - echo "Install Python2.7 for 64 bit" - $WINE msiexec -i python-${PYTHON_VERSION}.amd64.msi /q /norestart - - wget -nc https://download.microsoft.com/download/d/2/4/d242c3fb-da5a-4542-ad66-f9661d0a8d19/vcredist_x64.exe --no-check-certificate - $WINE vcredist_x64.exe /q /norestart - echo "Installed vcredist for 64 bit" - $WINE pip install --upgrade pip - - else - # For 32 bit machine - wget -nc https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.msi --no-check-certificate - echo "Install Python2.7 for 32 bit" - $WINE msiexec -i python-${PYTHON_VERSION}.msi /q /norestart - - echo "Installing vc_redist for 32 bit " - wget -nc https://download.microsoft.com/download/1/1/1/1116b75a-9ec3-481a-a3c8-1777b5381140/vcredist_x86.exe --no-check-certificate - $WINE vcredist_x86.exe /q /norestart - #insatlled msvcr120.dll for 32 bit system - wget -nc http://www.dll-found.com/zip/m/msvcr120.dll.zip --no-check-certificate - unzip msvcr120.dll.zip - sudo cp msvcr120.dll $HOME/.wine32/drive_c/windows/system32/ - $WINE pip install --upgrade pip - - fi -} - -function install_pyqt(){ - - echo "Download PyQT" - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - # For 64 bit machine - wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe?raw=true --no-check-certificate - $WINE PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes - else - # For 32 bit machine - wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe?raw=true --no-check-certificate - $WINE PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes - fi -} - -function install_openssl(){ - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win64OpenSSL-${OPENSSL_VERSION}.exe?raw=true --no-check-certificate - $WINE Win64OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes - - else - wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win32OpenSSL-${OPENSSL_VERSION}.exe?raw=true --no-check-certificate - $WINE Win32OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes - echo "Install PyInstaller 32 bit" - fi -} - -function install_pyinstaller() -{ - $WINE pip install pyinstaller - echo "Install PyInstaller" - echo "Install Pyopencl" - - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - wget -nc https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win_amd64.whl --no-check-certificate - $WINE pip install pyopencl-2015.1-cp27-none-win_amd64.whl - $WINE pip install msgpack-python - - else - wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win_amd64one-win32.whl?raw=true --no-check-certificate - $WINE pip install msgpack-python - $WINE pip install pyopencl-2015.1-cp27-none-win32.whl - fi - echo "Install Message Pack" - -} - - -function build_dll(){ - cd $BASE_DIR - rm -rf master.zip - rm -rf PyBitmessage - git clone https://github.com/Bitmessage/PyBitmessage.git - cd PyBitmessage/src/bitmsghash - if [ ${MACHINE_TYPE} == 'x86_64' ]; then - # Do stuff for 64 bit machine - echo "Install MinGW" - sudo apt-get -y install mingw-w64 - echo "Create dll" - x86_64-w64-mingw32-g++ -D_WIN32 -Wall -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -I/usr/x86_64-w64-mingw32/include -L$HOME/.wine64/drive_c/OpenSSL-Win64/lib -c bitmsghash.cpp - x86_64-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -L$HOME/.wine64/drive_c/OpenSSL-Win64 -L/usr/lib/x86_64-linux-gnu/wine -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash64.dll -Wl,--out-implib,bitmsghash.a - echo "DLL generated successfully " - cd .. - cp -R bitmsghash ../../../src/ - cd ../../../ - cd packages/pyinstaller/ - env WINEPREFIX=$HOME/.wine64 wine pyinstaller bitmessagemain.spec - else - echo "Install MinGW for 32 bit" - sudo apt-get install mingw-w64 - echo "Create dll" - - - i686-w64-mingw32-g++ -D_WIN32 -Wall -m32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -I/usr/i686-w64-mingw32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib -c bitmsghash.cpp - i686-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib/MinGW -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash32.dll -Wl,--out-implib,bitmsghash.a - cd .. - cp -R bitmsghash ../../../src/ - cd ../../../ - cd packages/pyinstaller/ - env WINEPREFIX=$HOME/.wine32 wine pyinstaller bitmessagemain.spec - fi -} - - -install_wine -install_python -install_pyqt -install_openssl -install_pyinstaller -build_dll diff --git a/buildscripts/winbuild.sh b/buildscripts/winbuild.sh new file mode 100755 index 00000000..4d9dbf9c --- /dev/null +++ b/buildscripts/winbuild.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +# INIT +MACHINE_TYPE=`uname -m` +BASE_DIR=$(pwd) +PYTHON_VERSION=2.7.17 +PYQT_VERSION=4-4.11.4-gpl-Py2.7-Qt4.8.7 +OPENSSL_VERSION=1_0_2t +SRCPATH=~/Downloads + +#Functions +function download_sources_32 { + if [ ! -d ${SRCPATH} ]; then + mkdir -p ${SRCPATH} + fi + wget -P ${SRCPATH} -c -nc --content-disposition \ + https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.msi \ + https://download.microsoft.com/download/1/1/1/1116b75a-9ec3-481a-a3c8-1777b5381140/vcredist_x86.exe \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt${PYQT_VERSION}-x32.exe?raw=true \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win32OpenSSL-${OPENSSL_VERSION}.exe?raw=true \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win32.whl?raw=true + #wget -P ${SRCPATH} -nc http://www.dll-found.com/zip/m/msvcr120.dll.zip + #wget -P ${SRCPATH} -nc http://www.dll-found.com/zip/m/msvcr100.dll.zip +} + +function download_sources_64 { + if [ ! -d ${SRCPATH} ]; then + mkdir -p ${SRCPATH} + fi + wget -P ${SRCPATH} -c -nc --content-disposition \ + http://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.amd64.msi \ + https://download.microsoft.com/download/d/2/4/d242c3fb-da5a-4542-ad66-f9661d0a8d19/vcredist_x64.exe \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt${PYQT_VERSION}-x64.exe?raw=true \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win64OpenSSL-${OPENSSL_VERSION}.exe?raw=true \ + https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win_amd64.whl?raw=true +} + +function download_sources { + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + download_sources_64 + else + download_sources_32 + fi +} + +function install_wine { + echo "Setting up wine" + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + export WINEPREFIX=${HOME}/.wine64 WINEARCH=win64 + else + export WINEPREFIX=${HOME}/.wine32 WINEARCH=win32 + fi + rm -rf ${WINEPREFIX} + rm -rf packages/pyinstaller/{build,dist} +} + +function install_python(){ + cd ${SRCPATH} + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + echo "Installing Python ${PYTHON_VERSION} 64b" + wine msiexec -i python-${PYTHON_VERSION}.amd64.msi /q /norestart + echo "Installing vcredist for 64 bit" + wine vcredist_x64.exe /q /norestart + echo "Upgrading pip" + wine python -m pip install --upgrade pip + else + echo "Installing Python ${PYTHON_VERSION} 32b" + wine msiexec -i python-${PYTHON_VERSION}.msi /q /norestart + echo "Installing vc_redist for 32 bit " + wine vcredist_x86.exe /q /norestart + #echo "Unpacking MSVCR120.DLL" + #unzip msvcr120.dll.zip -o -d $HOME/.wine32/drive_c/windows/system32/ + #unzip msvcr100.dll.zip -o -d $HOME/.wine32/drive_c/windows/system32/ + echo "Upgrading pip" + wine python -m pip install --upgrade pip + + fi +} + +function install_pyqt(){ + + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + echo "Installing PyQt-${PYQT_VERSION} 64b" + wine PyQt${PYQT_VERSION}-x64.exe /S /WX + else + echo "Installing PyQt-${PYQT_VERSION} 32b" + wine PyQt${PYQT_VERSION}-x32.exe /S /WX + fi +} + +function install_openssl(){ + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + echo "Installing OpenSSL ${OPENSSL_VERSION} 64b" + wine Win64OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysilent /sp- /suppressmsgboxes + else + echo "Installing OpenSSL ${OPENSSL_VERSION} 32b" + wine Win32OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysilent /sp- /suppressmsgboxes + fi +} + +function install_pyinstaller() +{ + echo "Installing PyInstaller" + wine python -m pip install pyinstaller +} + +function install_msgpack() +{ + echo "Installing msgpack" + wine python -m pip install msgpack-python +} + +function install_pyopencl() +{ + cd $SRCPATH + echo "Installing PyOpenCL" + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + wine python -m pip install pyopencl-2015.1-cp27-none-win_amd64.whl + else + wine python -m pip install pyopencl-2015.1-cp27-none-win32.whl + fi +} + + +function build_dll(){ + cd $BASE_DIR + cd src/bitmsghash + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + echo "Create dll" + x86_64-w64-mingw32-g++ -D_WIN32 -Wall -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -I/usr/x86_64-w64-mingw32/include -L$HOME/.wine64/drive_c/OpenSSL-Win64/lib -c bitmsghash.cpp + x86_64-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -L$HOME/.wine64/drive_c/OpenSSL-Win64 -L/usr/lib/x86_64-linux-gnu/wine -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash64.dll -Wl,--out-implib,bitmsghash.a + else + echo "Create dll" + i686-w64-mingw32-g++ -D_WIN32 -Wall -m32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -I/usr/i686-w64-mingw32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib -c bitmsghash.cpp + i686-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib/MinGW -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash32.dll -Wl,--out-implib,bitmsghash.a + fi +} + +function build_exe(){ + cd $BASE_DIR + cd packages/pyinstaller + wine pyinstaller bitmessagemain.spec +} + +# prepare on ubuntu +# dpkg --add-architecture i386 +# apt update +# apt -y install wget wine-stable wine-development winetricks mingw-w64 wine32 wine64 xvfb + + +download_sources +if [ "$1" == "--download-only" ]; then + exit +fi + +install_wine +install_python +install_pyqt +install_openssl +install_pyopencl +install_msgpack +install_pyinstaller +build_dll +build_exe diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index 7f30cedf..fe86d7bd 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -33,7 +33,7 @@ os.rename(os.path.join(srcPath, '__init__.py'), os.path.join(srcPath, '__init__. a = Analysis( [srcPath + 'bitmessagemain.py'], pathex=[outPath], - hiddenimports=['pyopencl','numpy', 'win32com' , 'setuptools.msvc' ,'_cffi_backend'], + hiddenimports=['bitmessageqt.languagebox', 'pyopencl','numpy', 'win32com' , 'setuptools.msvc' ,'_cffi_backend'], hookspath=None, runtime_hooks=None ) @@ -94,7 +94,7 @@ exe = EXE(pyz, debug=False, strip=None, upx=True, - console=True, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) + console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) coll = COLLECT(exe, a.binaries, From 73ecf07dec70f66e9afa074ec0c18bed0cf050f0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 16 Feb 2020 00:20:40 +0800 Subject: [PATCH 301/306] Wine build cleanup and XP fix - spec file was cleaned up - 32bit build runs on XP (downgrade of PyInstaller needed) --- buildscripts/winbuild.sh | 35 ++++++++-------- packages/pyinstaller/bitmessagemain.spec | 53 ++++++++++++++---------- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/buildscripts/winbuild.sh b/buildscripts/winbuild.sh index 4d9dbf9c..5b4fc37f 100755 --- a/buildscripts/winbuild.sh +++ b/buildscripts/winbuild.sh @@ -19,8 +19,6 @@ function download_sources_32 { https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt${PYQT_VERSION}-x32.exe?raw=true \ https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win32OpenSSL-${OPENSSL_VERSION}.exe?raw=true \ https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win32.whl?raw=true - #wget -P ${SRCPATH} -nc http://www.dll-found.com/zip/m/msvcr120.dll.zip - #wget -P ${SRCPATH} -nc http://www.dll-found.com/zip/m/msvcr100.dll.zip } function download_sources_64 { @@ -61,24 +59,19 @@ function install_python(){ wine msiexec -i python-${PYTHON_VERSION}.amd64.msi /q /norestart echo "Installing vcredist for 64 bit" wine vcredist_x64.exe /q /norestart - echo "Upgrading pip" - wine python -m pip install --upgrade pip else echo "Installing Python ${PYTHON_VERSION} 32b" wine msiexec -i python-${PYTHON_VERSION}.msi /q /norestart - echo "Installing vc_redist for 32 bit " - wine vcredist_x86.exe /q /norestart - #echo "Unpacking MSVCR120.DLL" - #unzip msvcr120.dll.zip -o -d $HOME/.wine32/drive_c/windows/system32/ - #unzip msvcr100.dll.zip -o -d $HOME/.wine32/drive_c/windows/system32/ - echo "Upgrading pip" - wine python -m pip install --upgrade pip - + # MSVCR 2008 required for Windows XP + cd ${SRCPATH} + echo "Installing vc_redist (2008) for 32 bit " + wine vcredist_x86.exe /Q fi + echo "Upgrading pip" + wine python -m pip install --upgrade pip } function install_pyqt(){ - if [ ${MACHINE_TYPE} == 'x86_64' ]; then echo "Installing PyQt-${PYQT_VERSION} 64b" wine PyQt${PYQT_VERSION}-x64.exe /S /WX @@ -100,19 +93,27 @@ function install_openssl(){ function install_pyinstaller() { + cd ${BASE_DIR} echo "Installing PyInstaller" - wine python -m pip install pyinstaller + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + wine python -m pip install pyinstaller + else + # 3.2.1 is the last version to work on XP + # see https://github.com/pyinstaller/pyinstaller/issues/2931 + wine python -m pip install -I pyinstaller==3.2.1 + fi } function install_msgpack() { + cd ${BASE_DIR} echo "Installing msgpack" wine python -m pip install msgpack-python } function install_pyopencl() { - cd $SRCPATH + cd ${SRCPATH} echo "Installing PyOpenCL" if [ ${MACHINE_TYPE} == 'x86_64' ]; then wine python -m pip install pyopencl-2015.1-cp27-none-win_amd64.whl @@ -123,7 +124,7 @@ function install_pyopencl() function build_dll(){ - cd $BASE_DIR + cd ${BASE_DIR} cd src/bitmsghash if [ ${MACHINE_TYPE} == 'x86_64' ]; then echo "Create dll" @@ -137,7 +138,7 @@ function build_dll(){ } function build_exe(){ - cd $BASE_DIR + cd ${BASE_DIR} cd packages/pyinstaller wine pyinstaller bitmessagemain.spec } diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index fe86d7bd..92e52f6a 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -11,13 +11,13 @@ else: sslName = 'OpenSSL-Win%s' % ("32" if arch == 32 else "64") site_root = os.path.abspath(HOMEPATH) spec_root = os.path.abspath(SPECPATH) -cdrivePath= site_root[0:3] -srcPath = spec_root[:-20]+"src\\" -qtPath = site_root+"\\PyQt4\\" -openSSLPath = cdrivePath+sslName+"\\" -msvcrDllPath = cdrivePath+"windows\\system32\\" -pythonDllPath = cdrivePath+"Python27\\" -outPath = spec_root+"\\bitmessagemain" +cdrivePath = site_root[0:3] +srcPath = os.path.join(spec_root[:-20], "src") +qtBase = "PyQt4" +openSSLPath = os.path.join(cdrivePath, sslName) +msvcrDllPath = os.path.join(cdrivePath, "windows", "system32") +pythonDllPath = os.path.join(cdrivePath, "Python27") +outPath = os.path.join(spec_root, "bitmessagemain") importPath = srcPath sys.path.insert(0,importPath) @@ -31,7 +31,7 @@ os.rename(os.path.join(srcPath, '__init__.py'), os.path.join(srcPath, '__init__. # -*- mode: python -*- a = Analysis( - [srcPath + 'bitmessagemain.py'], + [os.path.join(srcPath, 'bitmessagemain.py')], pathex=[outPath], hiddenimports=['bitmessageqt.languagebox', 'pyopencl','numpy', 'win32com' , 'setuptools.msvc' ,'_cffi_backend'], hookspath=None, @@ -43,23 +43,32 @@ os.rename(os.path.join(srcPath, '__init__.py.backup'), os.path.join(srcPath, '__ def addTranslations(): import os extraDatas = [] - for file in os.listdir(srcPath + 'translations'): - if file[-3:] != ".qm": + for file_ in os.listdir(os.path.join(srcPath, 'translations')): + if file_[-3:] != ".qm": continue - extraDatas.append((os.path.join('translations', file), os.path.join(srcPath, 'translations', file), 'DATA')) - for file in os.listdir(qtPath + 'translations'): - if file[0:3] != "qt_" or file[5:8] != ".qm": + extraDatas.append((os.path.join('translations', file_), + os.path.join(srcPath, 'translations', file_), 'DATA')) + for libdir in sys.path: + qtdir = os.path.join(libdir, qtBase, 'translations') + if os.path.isdir(qtdir): + break + if not os.path.isdir(qtdir): + return extraDatas + for file_ in os.listdir(qtdir): + if file_[0:3] != "qt_" or file_[5:8] != ".qm": continue - extraDatas.append((os.path.join('translations', file), os.path.join(qtPath, 'translations', file), 'DATA')) + extraDatas.append((os.path.join('translations', file_), + os.path.join(qtdir, file_), 'DATA')) return extraDatas def addUIs(): import os extraDatas = [] - for file in os.listdir(srcPath + 'bitmessageqt'): - if file[-3:] != ".ui": + for file_ in os.listdir(os.path.join(srcPath, 'bitmessageqt')): + if file_[-3:] != ".ui": continue - extraDatas.append((os.path.join('ui', file), os.path.join(srcPath, 'bitmessageqt', file), 'DATA')) + extraDatas.append((os.path.join('ui', file_), os.path.join(srcPath, + 'bitmessageqt', file_), 'DATA')) return extraDatas # append the translations directory @@ -67,10 +76,8 @@ a.datas += addTranslations() a.datas += addUIs() - -a.binaries += [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), - ('python27.dll', pythonDllPath + 'python27.dll', 'BINARY'), - ('msvcr120.dll', msvcrDllPath + 'msvcr120.dll','BINARY'), +a.binaries += [('libeay32.dll', os.path.join(openSSLPath, 'libeay32.dll'), 'BINARY'), + ('python27.dll', os.path.join(pythonDllPath, 'python27.dll'), 'BINARY'), (os.path.join('bitmsghash', 'bitmsghash%i.dll' % (arch)), os.path.join(srcPath, 'bitmsghash', 'bitmsghash%i.dll' % (arch)), 'BINARY'), (os.path.join('bitmsghash', 'bitmsghash.cl'), os.path.join(srcPath, 'bitmsghash', 'bitmsghash.cl'), 'BINARY'), (os.path.join('sslkeys', 'cert.pem'), os.path.join(srcPath, 'sslkeys', 'cert.pem'), 'BINARY'), @@ -93,7 +100,7 @@ exe = EXE(pyz, name=fname, debug=False, strip=None, - upx=True, + upx=False, console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) coll = COLLECT(exe, @@ -101,6 +108,6 @@ coll = COLLECT(exe, a.zipfiles, a.datas, strip=False, - upx=True, + upx=False, name='main') From cdf6cbad8f767f22471df3bee5ccf54ce8ece3f1 Mon Sep 17 00:00:00 2001 From: navjot Date: Thu, 16 Apr 2020 21:31:02 +0530 Subject: [PATCH 302/306] fixed android app crashing issue --- src/buildozer.spec | 2 +- src/main.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/buildozer.spec b/src/buildozer.spec index 0dfeb191..fc0bf18b 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -160,7 +160,7 @@ android.ndk = 17c #android.add_activites = com.example.ExampleActivity # (str) python-for-android branch to use, defaults to stable -p4a.branch = master +p4a.branch = release-2019.07.08 # (str) OUYA Console category. Should be one of GAME or APP # If you leave this blank, OUYA support will not be enabled diff --git a/src/main.py b/src/main.py index a3257062..22ea7c3e 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,5 @@ """This module is for thread start.""" import state -from bitmessagemain import main if __name__ == '__main__': state.kivy = True From 1c1eab2382b916d6a393320ba41e0c2a6bccce15 Mon Sep 17 00:00:00 2001 From: navjot Date: Fri, 17 Apr 2020 22:27:23 +0530 Subject: [PATCH 303/306] customize TwoLineAvatarIconListItem text_color behaviour --- src/bitmessagekivy/mpybit.py | 47 +++++++++++++++--------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 2b2f9d56..09328378 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -72,6 +72,13 @@ def toast(text): return +class CustomAvatarIconListItem(TwoLineAvatarIconListItem): + + def __init__(self, **kwargs): + super(CustomAvatarIconListItem, self).__init__(**kwargs) + self.text_color=[0.12, 0.58, 0.95, 1] + + class Navigatorss(MDNavigationDrawer): """Navigator class (image, title and logo)""" image_source = StringProperty('images/qidenticon_two.png') @@ -150,10 +157,10 @@ class Inbox(Screen): """This method is used to create the mdList""" total_message = len(self.ids.ml.children) for item in data: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + ) meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) @@ -339,10 +346,9 @@ class MyAddress(Screen): 'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + theme_text_color='Custom') meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['text'].strip())))) @@ -448,9 +454,8 @@ class AddressBook(Screen): def set_mdList(self, start_index, end_index): """Creating the mdList""" for item in self.queryreturn[start_index:end_index]: - meny = TwoLineAvatarIconListItem( - text=item[0], secondary_text=item[1], theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + meny = CustomAvatarIconListItem( + text=item[0], secondary_text=item[1], theme_text_color='Custom') meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item[0].strip())))) @@ -899,10 +904,9 @@ class Sent(Screen): """This method is used to create the mdList""" total_sent_msg = len(self.ids.ml.children) for item in data: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text=item['text'], secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + theme_text_color='Custom') meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( avatarImageFirstLetter(item['secondary_text'].strip())))) @@ -1098,13 +1102,12 @@ class Trash(Screen): """This method is used to create the mdlist""" total_trash_msg = len(self.ids.ml.children) for item in self.trash_messages: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( item[2]) >= 50 else (item[2] + ',' + item[3].replace( '\n', ''))[0:50] + '........', - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + theme_text_color='Custom') img_latter = './images/text_images/{}.png'.format( item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ 2][0].upper() <= 'Z') else '!') @@ -1228,15 +1231,6 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods title = "PyBitmessage" imgstatus = False count = 0 - menu_items = [ - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - {'viewclass': 'MDMenuItem', 'text': 'Example item'}, - ] def build(self): """Method builds the widget""" @@ -2149,10 +2143,9 @@ class Draft(Screen): third_text) > 25 else third_text, 'ackdata': mail[5]}) for item in data: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text='Draft', secondary_text=item['text'], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) + theme_text_color='Custom') meny.add_widget(AvatarSampleWidget( source='./images/avatar.png')) meny.bind(on_press=partial( @@ -2319,7 +2312,7 @@ class Allmails(Screen): """This method is used to create mdList for allmaills""" data_exist = len(self.ids.ml.children) for item in self.all_mails: - meny = TwoLineAvatarIconListItem( + meny = CustomAvatarIconListItem( text=item[1], secondary_text=item[2][:50] + '........' if len( item[2]) >= 50 else ( From f8782d0b72733e83dcf1175e2edb8a01178c8b2d Mon Sep 17 00:00:00 2001 From: navjot Date: Mon, 27 Apr 2020 22:16:46 +0530 Subject: [PATCH 304/306] worked on resolving navigation issue or spinner UI designing issue --- src/bitmessagekivy/main.kv | 2 +- src/bitmessagekivy/mpybit.py | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 85ba2979..37c20f52 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -39,7 +39,7 @@ NavigationDrawerIconButton: CustomSpinner: id: btn - pos_hint:{"x":0,"y":.25} + pos_hint:{"x":0,"y":.0} option_cls: Factory.get("MySpinnerOption") font_size: '11.9sp' text: app.getDefaultAccData() diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 09328378..fab8ab96 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -812,15 +812,23 @@ class Random(Screen): self.manager.current = 'myaddress' Clock.schedule_once(self.address_created_callback, 6) - @staticmethod - def address_created_callback(dt=0): + def address_created_callback(self, dt=0): """New address created""" state.kivyapp.root.ids.sc10.children[1].active = 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 = BMConfigParser().addresses() + self.manager.parent.parent.parent.parent.ids.nav_drawer.ids.btn.values = [] + self.manager.parent.parent.parent.parent.ids.sc3.children[1].ids.btn.values = [] + self.manager.parent.parent.parent.parent.ids.nav_drawer.ids.btn.values = addresses + self.manager.parent.parent.parent.parent.ids.sc3.children[1].ids.btn.values = addresses + def add_validation(self, instance): """Checking validation at address creation time""" entered_label = str(instance.text.strip()) @@ -1353,14 +1361,20 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods def on_key(self, window, key, *args): """Method is used for going on previous screen""" if key == 27: - if state.in_search_mode and self.root.ids.scr_mngr.current != ( - "mailDetail"): + 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() @@ -1376,7 +1390,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods 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: + 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) @@ -1619,6 +1633,11 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods 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()]] @@ -1924,6 +1943,7 @@ class MailDetail(Screen): def inbox_reply(self): """Reply inbox messages""" + state.in_composer = True data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where" " msgid = ?;", str(state.mail_id)) @@ -2438,16 +2458,16 @@ class Allmails(Screen): def avatarImageFirstLetter(letter_string): """This function is used to the first letter for the avatar image""" - if letter_string: + 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 = '!' - else: + except ValueError as e: img_latter = '!' - return img_latter + return img_latter if img_latter else '!' class Starred(Screen): From 6c47e30fccd48fc476e4d67d560ae28bbb33b81c Mon Sep 17 00:00:00 2001 From: navjot Date: Sat, 2 May 2020 15:09:23 +0530 Subject: [PATCH 305/306] fixed sender address validation issue on composer --- src/bitmessagekivy/mpybit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index fab8ab96..6c0fa813 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -579,7 +579,8 @@ class DropDownWidget(BoxLayout): if toAddress != '' and subject and message: status, addressVersionNumber, streamNumber, ripe = ( decodeAddress(toAddress)) - if status == 'success': + valid_from_add = True if fromAddress in state.kivyapp.variable_1 else False + if status == 'success' and valid_from_add: navApp.root.ids.sc3.children[0].active = True if state.detailPageType == 'draft' \ and state.send_draft_mail: @@ -632,6 +633,8 @@ class DropDownWidget(BoxLayout): print "sqlExecute successfully #######################" state.in_composer = True return + elif valid_from_add is False: + msg = 'Please enter valid sender address' else: msg = 'Enter a valid recipients address' elif not toAddress: From 8850a68347aac3b24087739574a4ec4a0616db86 Mon Sep 17 00:00:00 2001 From: navjot Date: Tue, 15 Sep 2020 22:13:22 +0530 Subject: [PATCH 306/306] removed the inset sent query and using the comman helper_sent.inset method for data insertion --- src/bitmessagekivy/mpybit.py | 52 +++++++++++++++++++++++++----------- src/helper_sent.py | 5 ++++ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 6c0fa813..78921918 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -62,6 +62,7 @@ from uikivysignaler import UIkivySignaler import identiconGeneration from addresses import addBMIfNotPresent, decodeAddress +import helper_sent def toast(text): @@ -606,15 +607,24 @@ class DropDownWidget(BoxLayout): 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - # t = () - sqlExecute( - '''INSERT INTO sent VALUES - (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', toAddress, ripe, fromAddress, subject, message, - ackdata, int(time.time()), int(time.time()), 0, - 'msgqueued', 0, 'sent', encoding, - BMConfigParser().getint( - 'bitmessagesettings', 'ttl')) + t = ( + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'sent', + encoding, + BMConfigParser().getint('bitmessagesettings', 'ttl') + ) + helper_sent.insert(t) state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[2].children[0].ids @@ -2253,12 +2263,24 @@ class Draft(Screen): 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload ackdata = genAckPayload(streamNumber, stealthLevel) - sqlExecute( - '''INSERT INTO sent VALUES - (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', toAddress, ripe, - fromAddress, subject, message, ackdata, int(time.time()), - int(time.time()), 0, 'msgqueued', 0, 'draft', encoding, - BMConfigParser().getint('bitmessagesettings', 'ttl')) + t = ( + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'draft', + encoding, + BMConfigParser().getint('bitmessagesettings', 'ttl') + ) + helper_sent.insert(t) state.msg_counter_objs = src_object.children[2].children[0].ids state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() diff --git a/src/helper_sent.py b/src/helper_sent.py index bc3362e8..60c4772d 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -2,9 +2,14 @@ Insert values into sent table """ +import uuid from helper_sql import sqlExecute def insert(t): """Perform an insert into the `sent` table""" + msgid = uuid.uuid4().bytes + temp = list(t) + temp[0] = msgid + t = tuple(temp) sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)

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 P0T}2#zE`8;^zQ!vHTMmM literal 0 HcmV?d00001 diff --git a/src/images/text_images/N.png b/src/images/text_images/N.png new file mode 100644 index 0000000000000000000000000000000000000000..2d235d0618e32ec6c2d4d0f2f488a4c1e5289011 GIT binary patch literal 6509 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 O(3lvR-$WX?MgJd&$OdNs literal 0 HcmV?d00001 diff --git a/src/images/text_images/O.png b/src/images/text_images/O.png new file mode 100644 index 0000000000000000000000000000000000000000..c0cc972ad641d61181a66c2858e783b6f6ead93a GIT binary patch literal 7912 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 S?#+Gx0000Y`X9O literal 0 HcmV?d00001 diff --git a/src/images/text_images/P.png b/src/images/text_images/P.png new file mode 100644 index 0000000000000000000000000000000000000000..57ec50124111d42dffe70bec13bb3d7487843791 GIT binary patch literal 5914 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 N002ovPDHLkV1kMUAfNyM literal 0 HcmV?d00001 diff --git a/src/images/text_images/R.png b/src/images/text_images/R.png new file mode 100644 index 0000000000000000000000000000000000000000..090646f5d6690043e424755a6f039ad23379595c GIT binary patch literal 6404 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/S.png b/src/images/text_images/S.png new file mode 100644 index 0000000000000000000000000000000000000000..444419cf0d38b0b6f03a567558a54831fab69811 GIT binary patch literal 7826 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/T.png b/src/images/text_images/T.png new file mode 100644 index 0000000000000000000000000000000000000000..ace7b36b257305def81f8856ac85fdbe798dfa6a GIT binary patch literal 4793 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 ShpVT13SCXZM^)E&HB3ksGXp`uS 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 K6jAaPq5lIkL3H8( literal 0 HcmV?d00001 diff --git a/src/images/text_images/X.png b/src/images/text_images/X.png new file mode 100644 index 0000000000000000000000000000000000000000..be919fc4b9003ea5d3e15c7bacd1aad66a292c8c GIT binary patch literal 7367 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/Y.png b/src/images/text_images/Y.png new file mode 100644 index 0000000000000000000000000000000000000000..4819bbd197ec6177f5a2cc3d575e77a108a1f405 GIT binary patch literal 6459 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 literal 0 HcmV?d00001 diff --git a/src/images/text_images/Z.png b/src/images/text_images/Z.png new file mode 100644 index 0000000000000000000000000000000000000000..7d1c8e016888f107ae07afa9f570de3945b86ba5 GIT binary patch literal 6166 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 Date: Wed, 17 Jul 2019 14:20:27 +0530 Subject: [PATCH 012/306] kivy toolbar title updated with new ehancements --- src/bitmessagekivy/main.kv | 198 ++++++++++++++++++++++------- src/bitmessagekivy/mpybit.py | 233 ++++++++++++++++++++++++++++++++--- src/images/down-arrow.png | Bin 0 -> 2384 bytes src/images/right-arrow.png | Bin 0 -> 3145 bytes src/state.py | 6 +- 5 files changed, 371 insertions(+), 66 deletions(-) create mode 100644 src/images/down-arrow.png create mode 100644 src/images/right-arrow.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 562e9f98..7d1d380f 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -1,3 +1,4 @@ + #:import Toolbar kivymd.toolbar.Toolbar #:import ThemeManager kivymd.theming.ThemeManager #:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer @@ -34,6 +35,7 @@ #:import MDBottomNavigationItem kivymd.tabs.MDBottomNavigationItem #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory +#:import MDTextButton kivymd.button.MDTextButton #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -67,6 +69,7 @@ values: app.variable_1 on_text:app.getCurrentAccountData(self.text) on_press: app.limit_spinner() + ArrowImg: NavigationDrawerIconButton: id: inbox_cnt icon: 'email-open' @@ -80,10 +83,11 @@ on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: app.mail_count(self.text) NavigationDrawerIconButton: + id: draft_cnt icon: 'message-draw' text: "Draft" - on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "99+" + on_release: app.root.ids.scr_mngr.current = 'draft' + badge_text: app.mail_count(self.text) NavigationDrawerIconButton: text: "Starred" icon:'star' @@ -147,6 +151,7 @@ NavigationLayout: orientation: 'vertical' Toolbar: id: toolbar + title: app.current_address_label() opacity: 1 if app.addressexist() else 0 disabled: False if app.addressexist() else True md_bg_color: app.theme_cls.primary_color @@ -197,6 +202,9 @@ NavigationLayout: id:sc14 ShowQRCode: id:sc15 + Draft: + id:sc16 + : name: 'inbox' @@ -225,9 +233,12 @@ NavigationLayout: : name: 'draft' - Label: - text:"I have a good dialox box" - color: 0,0,0,1 + ScrollView: + do_scroll_x: False + MDList: + id: ml + ComposerButton: + : name: 'test' Label: @@ -258,8 +269,10 @@ NavigationLayout: hint_text: 'type or select sender address' size_hint_y: None height: 100 + font_size: '13sp' multiline: False required: True + allow_copy: True helper_text_mode: "on_error" BoxLayout: @@ -269,9 +282,13 @@ NavigationLayout: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 - on_text: ti.text = self.text + on_text: ti.text = self.text if self.text != 'Select' else '' option_cls: Factory.get("MySpinnerOption") + background_color: color_button if self.state == 'normal' else color_button_pressed + background_down: 'atlas://data/images/defaulttheme/spinner' + color: color_font font_size: '12.5sp' + ArrowImg: BoxLayout: orientation: 'vertical' @@ -282,6 +299,7 @@ NavigationLayout: MyTextInput: id: txt_input size_hint_y: None + font_size: '13sp' height: 100 hint_text: 'type or search recipients address starting with BM-' RV: @@ -291,6 +309,7 @@ NavigationLayout: hint_text: 'subject' required: True height: 100 + font_size: '13sp' size_hint_y: None multiline: False helper_text_mode: "on_error" @@ -300,6 +319,7 @@ NavigationLayout: multiline: True hint_text: 'body' size_hint_y: None + font_size: '13sp' required: True helper_text_mode: "on_error" BoxLayout: @@ -308,14 +328,24 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'send' on_press: root.send() + MDLabel: + font_style: 'Title' + text: 'send' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' AnchorLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'reset' - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: app.root.ids.scr_mngr.current = 'random' + MDLabel: + font_style: 'Title' + text: 'reset' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : readonly: False @@ -357,7 +387,8 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(700) + height: dp(750) + padding: dp(10) BoxLayout: MDLabel: font_style: 'Body1' @@ -404,9 +435,15 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .5 - text: 'proceed' + size_hint: .5, .35 + height: dp(40) on_press: app.root.ids.scr_mngr.current = 'random' + MDLabel: + font_style: 'Title' + text: 'proceed' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'random' @@ -415,8 +452,8 @@ NavigationLayout: orientation: 'vertical' size_hint_y: None height: self.minimum_height - padding: dp(48) - spacing: 200 + padding: dp(20) + spacing: 100 MDLabel: font_style: 'Body1' theme_text_color: 'Primary' @@ -439,13 +476,19 @@ NavigationLayout: hint_text: "Label" required: True helper_text_mode: "on_error" - MDRaisedButton: - text: 'next' - size_hint_y: 0.13 - size_hint_x: 0.8 - pos_hint: {'x': .1, 'y': 0.3} - opposite_colors: True - on_release: root.generateaddress() + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .5, None + height: dp(40) + on_release: root.generateaddress() + opposite_colors: True + MDLabel: + font_style: 'Title' + text: 'next' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'add_sucess' @@ -466,25 +509,40 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Server ' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Server' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "DATA SETTINGS" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Import or export data' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Import or export data' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "OTHER SETTINGS" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: 'Restart background service' - on_press: app.root.ids.scr_mngr.current = 'random' + size_hint: .6, .55 + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Restart background service' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' BoxLayout: AnchorLayout: MDLabel: @@ -549,7 +607,7 @@ NavigationLayout: orientation: 'vertical' MDTextField: id: label - multiline: True + multiline: False hint_text: "Label" required: True helper_text_mode: "on_error" @@ -612,8 +670,14 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .5 - text: root.text_variable_1 + size_hint: .6, .35 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_1 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' MDTab: name: 'processes' text: 'Processes' @@ -628,30 +692,53 @@ NavigationLayout: BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_2 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_2 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "Brodcast" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_3 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_3 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "publickeys" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_4 - + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_4 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' OneLineListItem: text: "objects" BoxLayout: AnchorLayout: MDRaisedButton: - size_hint: .8, .6 - text: root.text_variable_5 + size_hint: .7, .6 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.text_variable_5 + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'mailDetail' @@ -689,17 +776,27 @@ NavigationLayout: halign: 'left' bold: True BoxLayout: - spacing:50 + spacing:20 MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Reply' if root.page_type == 'inbox' else 'Copy' on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() + MDLabel: + font_style: 'Title' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'Delete' on_press: root.delete_mail() + MDLabel: + font_style: 'Title' + text: 'Delete' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : size_hint_y: None @@ -715,7 +812,7 @@ NavigationLayout: elevation_normal: 8 md_bg_color: [0.941, 0, 0,1] on_press: app.root.ids.scr_mngr.current = 'create' - on_release: app.clear_composer() + on_press: app.clear_composer() : id: myadd_popup @@ -871,4 +968,11 @@ NavigationLayout: name: 'showqrcode' BoxLayout: orientation: 'vertical' - id: qr \ No newline at end of file + id: qr + + +: + source: './images/down-arrow.png' if self.parent.is_open == True else './images/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 \ No newline at end of file diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 851375a1..b122791f 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -47,7 +47,6 @@ import kivy_helper_search from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel -from kivy.garden.qrcode import QRCodeWidget from kivy.utils import platform @@ -101,7 +100,8 @@ class Inbox(Screen): carousel.data_index = 0 carousel.min_move = 0.2 del_btn = Button(text='Delete') - del_btn.background_color = (1, 0, 0, .5) + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) @@ -135,8 +135,13 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing""" - state.navigation_drawer_obj = self.parent.parent.parent.parent.children[2].children[0].children[0].children[0].children sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + if int(state.inbox_count) > 0: + msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.inbox_count = str(int(state.inbox_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -208,7 +213,22 @@ class AddressBook(Screen): meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) - self.ids.ml.add_widget(meny) + # self.ids.ml.add_widget(meny) + carousel = Carousel(direction='right') + if platform == 'android': + carousel.height = 140 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete_address, item[1])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index=1 + self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -228,6 +248,12 @@ class AddressBook(Screen): p.open() p.set_addbook_data(address, label) + def delete_address(self, address, instance, *args): + """Delete inbox mail from inbox listing""" + self.ids.ml.remove_widget(instance.parent.parent) + sqlExecute("DELETE FROM addressbook WHERE address = '{}';".format(address)) + + class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): ''' Adds selection and focus behaviour to the view. ''' @@ -491,7 +517,6 @@ class Sent(Screen): xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - state.totalSentMail = len(queryreturn) if state.msg_counter_objs and state.association == state.check_sent_acc: state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(int(state.sent_count) + 1) @@ -513,7 +538,8 @@ class Sent(Screen): carousel.data_index = 0 carousel.min_move = 0.2 del_btn = Button(text='Delete') - del_btn.background_color = (1, 0, 0, .5) + del_btn.background_normal = '' + del_btn.background_color = (1.0, 0.0, 0.0, 1.0) del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) @@ -628,9 +654,9 @@ class NavigateApp(App): obj_1 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - total_sentmail = str(state.totalSentMail) state.screen_density = Window.size title = "PyBitmessage" + imgstatus = False count = 0 menu_items = [ {'viewclass': 'MDMenuItem', @@ -692,24 +718,30 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" + address_label = self.current_address_label(BMConfigParser().get(text, 'label')) + self.root_window.children[1].ids.toolbar.title = address_label state.association = text self.root.ids.sc1.clear_widgets() self.root.ids.sc4.clear_widgets() self.root.ids.sc5.clear_widgets() + self.root.ids.sc16.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) + self.root.ids.sc16.add_widget(Draft()) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = self.root_window.children[1].children[2].children[0].ids state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format(state.association))[0][0]) state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format(state.association))[0][0]) state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'draft' ;".format(state.association))[0][0]) if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count msg_counter_objs.inbox_cnt.badge_text = state.inbox_count msg_counter_objs.trash_cnt.badge_text = state.trash_count + msg_counter_objs.draft_cnt.badge_text = state.draft_count def getInboxMessageDetail(self, instance): @@ -748,17 +780,33 @@ class NavigateApp(App): spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 def on_key(self, window, key, *args): + """This method is used for going on previous screen""" if key == 27: # the esc key - if self.root.ids.scr_mngr.current_screen.name == "mailDetail": - self.root.ids.scr_mngr.current = 'sent' + if self.root.ids.scr_mngr.current == "mailDetail": + self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' # this is for direction of the screen comesup - # self.root.ids.scr_mngr.transition.direction = 'right' - return True - elif self.root.ids.scr_mngr.current_screen.name == "create": + elif self.root.ids.scr_mngr.current == "create": + composer_objs = self.root + from_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.ti.text) + to_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) + if from_addr and to_addr: + Draft().draft_msg(composer_objs) + # self.root.ids.scr_mngr.current self.root.ids.scr_mngr.current = 'inbox' - return True + elif self.root.ids.scr_mngr.current == "showqrcode": + self.root.ids.scr_mngr.current = 'myaddress' + elif self.root.ids.scr_mngr.current == "random": + self.root.ids.scr_mngr.current = 'login' else: - return True + 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.restart) + return True + + def restart(self, *args): + """this method is used to set transition direction""" + self.root.ids.scr_mngr.transition.direction = 'left' + self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) def status_dispatching(self, data): ackData, message = data @@ -769,7 +817,7 @@ class NavigateApp(App): """if slow down the nwe will make new composer edit screen""" composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' - composer_obj.btn.text = '' + composer_obj.btn.text = 'Select' composer_obj.txt_input.text = '' composer_obj.subject.text = '' @@ -792,6 +840,19 @@ class NavigateApp(App): elif text == 'Trash': state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) return state.trash_count + elif text == 'Draft': + state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + return state.draft_count + + def current_address_label(self, current_address = None): + if BMConfigParser().addresses() or current_address: + if current_address: + first_name = current_address + else: + first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') + f_name = first_name.split() + return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] + return '' class GrashofPopup(Popup): @@ -805,6 +866,15 @@ class GrashofPopup(Popup): self.size_hint_x = 0.7 def savecontact(self): + my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + entered_text = str(self.ids.label.text) + if entered_text in my_addresses: + self.ids.label.focus = True + self.ids.label.helper_text = 'Please Enter corrent address' + elif entered_text == '': + self.ids.label.focus = True + self.ids.label.helper_text = 'This field is required' + label = self.ids.label.text address = self.ids.address.text if label and address: @@ -904,16 +974,23 @@ class MailDetail(Screen): self.status = data[0][4] def delete_mail(self): + msg_count_objs =self.parent.parent.parent.parent.parent.children[2].children[0].ids if state.detailPageType == 'sent': sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) + msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' elif state.detailPageType == 'inbox': sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(state.sentMailTime)) + msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) self.parent.parent.screens[0].clear_widgets() self.parent.parent.screens[0].add_widget(Inbox()) self.parent.parent.current = 'inbox' + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) @@ -1006,4 +1083,128 @@ class ShowQRCode(Screen): def qrdisplay(self): self.ids.qr.clear_widgets() - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) \ No newline at end of file + if platform == 'android': + from kivy.garden.qrcode import QRCodeWidget + self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) + + +class Draft(Screen): + """Draft screen is used to show the list of draft messages.""" + data = ListProperty() + + def __init__(self, *args, **kwargs): + super(Draft, self).__init__(*args, **kwargs) + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[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.""" + account = state.association + self.loadSent(account, 'All', '') + + def loadSent(self, account, where="", what=""): + """Load draft list for Draft messages.""" + xAddress = 'fromaddress' + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "draft", where, what, False) + if state.msg_counter_objs: + state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) + + if queryreturn: + for mail in queryreturn: + third_text = mail[3].replace('\n', ' ') + self.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, 'lastactiontime': mail[6]}) + for item in self.data: + meny = TwoLineAvatarIconListItem(text='Draft', secondary_text=item['text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + # wimg = Image(source='/home/cis/transparent1.png', size= (10, 10)) + # meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) + carousel = Carousel(direction='right') + # carousel = MDCardPost(text_post='Card with text',swipe=True, callback=callback) + if platform == 'android': + carousel.height = 150 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.bind(on_press=partial(self.delete_draft, item['lastactiontime'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index=1 + self.ids.ml.add_widget(carousel) + else: + content = MDLabel(font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def delete_draft(self, data_index, instance, *args): + """This method is used to delete draft message permanently""" + sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) + try: + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + except Exception as e: + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + if int(state.draft_count) > 0: + msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) + state.draft_count = str(int(state.draft_count) - 1) + self.ids.ml.remove_widget(instance.parent.parent) + + def draft_msg(self, src_object): + """This method is used for saving draft mails""" + composer_object = src_object.children[1].children[0].children[0].children[0].children[0].ids + fromAddress = str(composer_object.ti.text) + toAddress = str(composer_object.txt_input.text) + subject = str(composer_object.subject.text) + message = str(composer_object.body.text) + encoding = 3 + sendMessageToPeople = True + if sendMessageToPeople: + from addresses import decodeAddress + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress) + from addresses import * + toAddress = addBMIfNotPresent(toAddress) + statusIconColor = 'red' + stealthLevel = BMConfigParser().safeGetInt( + 'bitmessagesettings', 'ackstealthlevel') + from helper_ackPayload import genAckPayload + ackdata = genAckPayload(streamNumber, stealthLevel) + t = () + sqlExecute( + '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'draft', + encoding, + BMConfigParser().getint('bitmessagesettings', 'ttl')) + + state.msg_counter_objs = src_object.children[2].children[0].ids + state.draft_count = str(int(state.draft_count) + 1) + src_object.ids.sc16.clear_widgets() + src_object.ids.sc16.add_widget(Draft()) + return \ No newline at end of file diff --git a/src/images/down-arrow.png b/src/images/down-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3e864c8093738d0ab553d60af018d11f9a2ebb GIT binary patch literal 2384 zcmcImX;_l!8h()xN+DWYQtIH)Ch3T$CarTC#Thega!n1VQgTa2##|~)ktNG_lwLKnj9wHj(X*Q9KkO6;uM?Y zxf)s?kX)88LBQD*m*ptLsRtCECkkQp06Hx}6hPQ&6oh@WkWs|dD6L%J_%}y2SNL3( zC%yC9#7LkwwvA)8wL-o6AICy;_;?Jtei{a>fh!=vfDH%(EGu9Kc;J71B8&c7x(27$ zw}a^MOag1Gq4spqb%In^lQ$!>8rK;)-;@`*UszO$muJp$Vb#8~ME}I$g}dtbwog*< zHu8tjB;9HJmhVksbwt|?2BwHMAtgznoADLDwJq#_U&OS{;J6`~?4oI|L?d)%+2n3w6OC5V+6P+*{gGESC8e7e$U8rncC$ z{f?CRmKRYu>UUhUBFL7a9$6&&4+YCUe1o-rO4>GzF1lSM(HpL6oSQC+VdXkau0-JYa^!t4ak7*bQ>E@vtC z)_Vr?>;_v35wcay3DOzT+z)}rKOasaD;wx5Z6)WOtiy);O#EHWz2oH{J(BH7qv<3i zckew#+&UpBAqss@mMeFjdqndTgOWy}1Xj+cy^lt)jBVSA*5>LC|w+Qyp?WPcXHQjkm9WJsCqgNZzCDhAA{GxHb46?cM7PyWZyS7yoa5tO#y}76(3S87Pn@3yX@nOKQmQSsA-e?yn>~>P1)DM ziLfCUo9%m{K@9;^gnEpZO zTW>=Nm_jHUP(llLy*D(!HP4|Yc-VKG8b)_rL*20eiO>LAEXltf@zbqxO?Aq$*gBiT zS#asmoOCX*42rj63h}zK4*Gxjm=|T)qv;eh0bAGEIGesXpY?>ZGN)Eg?dc;_@nRX) z8F(5zA$gmnLn$u>8Qz`|J%1e0Gf(T+^dnOS$C|e6{I=)G_)HhG_6o;`^nMsUT@&>= z3*5U?PHH4n)ykxy1O3Pkk0u4&gR&iZ{9^xYT>HQ)!`g8TqTd*m&%3v*>gwL6bMA-VeHm(aJ}VBISwUa8gb;=UE?S-C~{^N(?7R&YG&Vzh8QDOVJ3f zDAOq>vmn@zc>f4AlzGgJn*}^bQ6y0aC>Uw3}7DY1sDu6dGJ-z*hQzr_N($yc5Fx_y4LEvzsS! zuCk>otY6$n`?tF1;|+w5uN_IBYe~qSh7AtZ+|v`c>9MnIVW6}1fYxE-*kL$#l?{db zl>$AeR_~n$)G=|eqRV=p*J`QPM;Q+k?q~G+$W-kI*GnHVn3wvIl(ZYeW-fUisFZZ& zTQn#5aVeU<%$4Ogk#0f9R|kz;J%JFEVR6ILes$JBCSaR!jw6Jdp<}$zVU<@ z>snP9O-Ekz0i~Rdfd;AeqXt9F2M*zR-V_OQ17z>-j`2dM6X7Y3Y3AdnmD^L3TBs{y z(Qs<#f#g=8|scm7i6~YUrf|f_8=Y-~5(x>c0{SPHX@G literal 0 HcmV?d00001 diff --git a/src/images/right-arrow.png b/src/images/right-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..8f136a774a2f1d83fc4c367a4c49d32da82eec49 GIT binary patch literal 3145 zcmYjU2~?BE7XA~AY?5H5Y&H<#v8hN{3TQ>ZB7#IvP!?HCgh!!LMdS$@AOUQsHE4rc zgIh|4*cKNMEK-F8qY;XVB^7KyLMoQ#P)JzHCXn8V`rbPyoSA>-&b{CL?lQx%ZQ+|u zjI50?3^NH035vup987VT!D1K^vc5~juqCFUL4iAR<--@3{wjQB&MDT@(=X}|FkPfy zM6om|qM+a6B08O75WK5J4C^iM7pVK`wG`4N;zEkA>7v(j5!a%(KAzLQE>OJgohne| zC+Pc!6Xzu&EOB_R1m)9Au33 zw-aeq(BI<8qj58jeW4mP6SteyDq9357~LCK?0 z6D`@6F6>b0SWeo%X(hW|HTeuZa8ml^=08(uB?@QFMP`+DxF{7Q8i34D5Q( zi*V*BRu^7>c?fc$5;N85GlFGZB8GD8t@f2}GBW2{Tq22pUIzpq>gVQHIC;3F|` zGIIq;aQbgEta!ANurxTksKlh*N~W~vWLaE8kjm;fA5zIe%$fZM_ZdaT0E1}|mj)Tj zei()PhrOIrhkfRAI#E4T+)4I@qygwpFGN5M5o&5H?$UkFyFuv@YAROv?S77bv;Dza zsSp^&<(%m>Mm*p;GOPY`8@OmP({`_mtI~w2L{$=mYGTT08GRiMw+(x2<&fz)?{kZZ zfWM4ntOO)6cTlb7?lW_gWb^UgVCTl;JOJ`_YC^Z+d(AXt!htjF75IQp^gpu@-%|?2 zOLERqjsmIxoY!C=l3v*3>-OHjJ6Bbjc9p2h2Ei!zIc00bIlU4i*`8~2~(MRek zEinwGKySCcgRZ5SVO|_iianlLSx$_?o}P0j?`yKw$?q*LtG`6-0fkdlfpOALYhGnP z2h_K3EZO3@rT@W%!i7L>%iL{w`pS#98^(tMt5r3SoSD1L|KfPpF@RxZ^GfHA>1u81 zgkmLu+LF23;&kfVIP1LVZ!K!)%4Vu_d+yxuf=K|}KB9#o(O@S_U?xtH|c7>~uF2yA&EzLDRaDgHiU0VxF4{n^5+h7L>t$rm&)U*Yibhm)wW* z9p@Vk#v(A2hm^GDFxU`tI1_ow5BOljEFel+fA&ANNbSJofzc@J)RGruiD7T3wzM9# zlGbpmu6y-oA;GLYgiZS^wcc_B)62)i7+}Z9{#P*$)M3|e0qC{_?*v0x-$s;1Ee9m8 zU|9&ue3l~9P~j-+%R=R>aw495Ig}!gj|3mwXIhoNfY?`y zr1uGeE@0}}l}}^p?w;qU{;$+>RKq{!th3Hmf6^OOcg6($#C`tcPb>?a{|z$j zc?v}83#*~#^D3=h4I4Gn;)iuP{7E~AKLp!lUZiK<2}du?ADwKEol1<*?q@$hwK&-P z?Zq)lITE~yA^ETTjOjp%yq_u2Lk;xFk?_~Qx2MRDn+3Gv=`e`xxt=!9l62E#u1xW4 zjc)27ZHuV(PJS_Us8DT@^Bn}lceHRPC*2KFwp7*^8wUyHe|wn=`*Ue%$5lrN&c;Hu zS+*OsCS1sI zn7~n%REg~}$I#&I(beSlk=lIviKZX1xU-`}AFVrDuCl2(E;xlyxEe#9L}JTIA4F{L z0JXdOKf0&83af5xe?)4lw{T&9O%TI?@oN9t`m?1hsVhGO_XT%TN2Fx1?d8LF?-{WZ z$R0;gG++PZH|p?%NMx~EF}S18MMH*n*&b>A)HS@omWMZ$)LVoh5+jXeNvl!0hLCB@ z0~YAOuT+#XZ{`;|ra)&-B?z=Og2orf+bkP_!%15mldWrep+Ij(LAnI*Bgv9_Z$X6Z z8(u{hb{vIQiC5NgFd1CfQ49o9$MU2-0 z6rD)}(~t2p@Hjmdyl}C0gn2E%I|yEMJQ6tHgPb2D>3YeJ=%q5SpPR0(BaBhx=t2dj mYd^zrwXQz0r2GCeEUlaTaqEuqpW$BwEOb+N(DjY Date: Fri, 2 Aug 2019 14:41:33 +0530 Subject: [PATCH 013/306] kivy searchbar adding with few more implementation --- src/bitmessagekivy/kivy_helper_search.py | 16 +- src/bitmessagekivy/main.kv | 90 ++++++++-- src/bitmessagekivy/mpybit.py | 211 +++++++++++++++++++---- src/state.py | 6 +- 4 files changed, 266 insertions(+), 57 deletions(-) diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 73a8a1ff..eae6be01 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -7,7 +7,7 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w else: what = None - if folder == "sent": + if folder == "sent" or folder == "draft": sqlStatementBase = ''' SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' @@ -34,12 +34,20 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementParts.append("folder != ?") sqlArguments.append("trash") if what is not None: - sqlStatementParts.append("%s LIKE ?" % (where)) - sqlArguments.append(what) + for colmns in where: + if len(where) > 1: + if where[0] == colmns: + filter_col = "(%s LIKE ?" % (colmns) + else: + filter_col += " or %s LIKE ? )" % (colmns) + else: + filter_col = "%s LIKE ?" % (colmns) + sqlArguments.append(what) + sqlStatementParts.append(filter_col) if unreadOnly: sqlStatementParts.append("read = 0") if len(sqlStatementParts) > 0: sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) if folder == "sent": sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) + return sqlQuery(sqlStatementBase, sqlArguments) \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 7d1d380f..861bbbac 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -36,6 +36,8 @@ #:import MDFloatingActionButton kivymd.button.MDFloatingActionButton #:import Factory kivy.factory.Factory #:import MDTextButton kivymd.button.MDTextButton +#:import FadeTransition kivy.uix.screenmanager.FadeTransition +#:import MDScrollViewRefreshLayout kivymd.refreshlayout.MDScrollViewRefreshLayout #:set color_button (0.784, 0.443, 0.216, 1) # brown #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -57,7 +59,7 @@ NavigationDrawerTwoLineListItem: text: "Accounts" NavigationDrawerIconButton: - Spinner: + CustomSpinner: pos_hint:{"x":0,"y":.25} id: btn option_cls: Factory.get("MySpinnerOption") @@ -68,7 +70,6 @@ color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - on_press: app.limit_spinner() ArrowImg: NavigationDrawerIconButton: id: inbox_cnt @@ -76,43 +77,51 @@ text: "Inbox" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: send_cnt icon: 'send' text: "Sent" on_release: app.root.ids.scr_mngr.current = 'sent' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: draft_cnt icon: 'message-draw' text: "Draft" on_release: app.root.ids.scr_mngr.current = 'draft' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Starred" icon:'star' on_release: app.root.ids.scr_mngr.current = 'inbox' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'archive' text: "Archieve" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: "9+" + on_press: app.check_search_screen(self) NavigationDrawerIconButton: icon: 'email-open-outline' text: "Spam" on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "8+" + on_press: app.check_search_screen(self) NavigationDrawerIconButton: id: trash_cnt icon: 'delete' text: "Trash" on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: app.mail_count(self.text) + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "All Mails" icon:'contact-mail' on_release: app.root.ids.scr_mngr.current = 'inbox' badge_text: "999+" + on_press: app.check_search_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -120,26 +129,32 @@ text: "Address Book" icon:'book-multiple' on_release: app.root.ids.scr_mngr.current = 'addressbook' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Settings" icon:'settings' - on_release: app.root.ids.scr_mngr.current = 'set' + on_release: app.root.ids.scr_mngr.current = 'set' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Subscriptions/Payment" icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'payment' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "new address" icon:'account-plus' on_release: app.root.ids.scr_mngr.current = 'login' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "Network Status" icon:'server-network' on_release: app.root.ids.scr_mngr.current = 'networkstat' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "My Addresses" icon:'account-multiple' on_release: app.root.ids.scr_mngr.current = 'myaddress' + on_press: app.check_search_screen(self) NavigationLayout: id: nav_layout @@ -148,6 +163,7 @@ NavigationLayout: id: nav_drawer BoxLayout: + id: box_layout orientation: 'vertical' Toolbar: id: toolbar @@ -158,6 +174,45 @@ NavigationLayout: background_palette: 'Primary' background_hue: '500' left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] + Button: + id: reset_navbar + size_hint_y: 0.35 + size_hint_x: 0.2 + opacity: 0 + disabled: True + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.reset_navdrawer(self) + Image: + source: './images/left_arrow.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 40, 40 + TextInput: + id: search_input + hint_text: 'search' + opacity: 0 + size_hint: 1,None + height: dp(32) + disabled: True + pos_hint: {'center_x':.565,'center_y': .5} + multiline: False + padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0] + padding_x: 20,20 + Button: + id: serch_btn + size_hint_y: 0.35 + size_hint_x: 0.2 + pos_hint: {'x': .1, 'y': 0.3} + color: 0,0,0,1 + background_color: (0,0,0,0) + on_press:app.searchQuery(self, search_input.text) + Image: + source: './images/search_mail.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 55, 55 Button: id: myButton size_hint_y: 0.35 @@ -170,6 +225,7 @@ NavigationLayout: source: './images/addressbookadd.png' center_x: self.parent.center_x center_y: self.parent.center_y + size: 55, 55 ScreenManager: id: scr_mngr Inbox: @@ -208,12 +264,14 @@ NavigationLayout: : name: 'inbox' - ScrollView: - do_scroll_x: False - MDList: - id: ml - - ComposerButton: + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml + ComposerButton : name: 'sent' @@ -272,13 +330,12 @@ NavigationLayout: font_size: '13sp' multiline: False required: True - allow_copy: True helper_text_mode: "on_error" BoxLayout: size_hint_y: None height: dp(40) - Spinner: + CustomSpinner: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 @@ -569,10 +626,13 @@ NavigationLayout: : name: 'myaddress' - ScrollView: - do_scroll_x: False - MDList: - id: ml + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml ComposerButton: : diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b122791f..067eb4e5 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -4,7 +4,7 @@ from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ObjectProperty from kivy.uix.image import Image -from kivy.uix.screenmanager import Screen +from kivy.uix.screenmanager import Screen, NoTransition from kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet from kivymd.button import MDIconButton from kivymd.date_picker import MDDatePicker @@ -48,7 +48,7 @@ from kivy.core.window import Window from functools import partial from kivy.uix.carousel import Carousel from kivy.utils import platform - +from kivy.uix.spinner import Spinner class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') @@ -79,6 +79,9 @@ class Inbox(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox list for Inbox messages.""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text xAddress = 'toaddress' data = [] queryreturn = kivy_helper_search.search_sql( @@ -86,15 +89,16 @@ class Inbox(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - # ('inbox', 'j\xe5(M\xcfPbe\rl\x0f\xa3\r\xef>\xf0\x0b&\t\'}"RYg\x03\x80\x14\x82\xeb&,', 'BM-2cXpNNd7dhTjsv7LHNfmphfUabZk958sA3', 'hello', 'BM-2cWyUfBdY2FbgyuCb7abFZ49JYxSzUhNFe', 'test from peter', '1559121770', 0) data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) for item in data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -109,7 +113,7 @@ class Inbox(Screen): ach_btn.background_color = (0,1,0,1) ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) carousel.add_widget(ach_btn) - carousel.index=1 + carousel.index = 1 self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', @@ -129,6 +133,8 @@ class Inbox(Screen): src_mng_obj = self.manager else: src_mng_obj = self.parent.parent + + hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -160,6 +166,23 @@ class Inbox(Screen): self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + def refresh_callback(self, *args): + """A method that updates the state of your application + while the spinner remains on the screen.""" + + def refresh_callback(interval): + """This methods is used for loading the inbox screen data""" + self.ids.ml.clear_widgets() + self.remove_widget(self.children[1]) + try: + screens_obj = self.parent.screens[0] + except Exception as e: + screens_obj = self.parent.parent.screens[0] + screens_obj.add_widget(Inbox()) + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) class MyAddress(Screen): @@ -176,7 +199,7 @@ class MyAddress(Screen): data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper() if (item['text'][0].upper() >= 'A' and item['text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: @@ -198,6 +221,24 @@ class MyAddress(Screen): p.open() p.set_address(fromaddress, label) + def refresh_callback(self, *args): + """A method that updates the state of your application + while the spinner remains on the screen.""" + + def refresh_callback(interval): + """This methods is used for loading the myaddress screen data""" + self.ids.ml.clear_widgets() + self.remove_widget(self.children[1]) + try: + screens_obj = self.parent.screens[9] + except Exception as e: + screens_obj = self.parent.parent.screens[9] + screens_obj.add_widget(MyAddress()) + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -211,12 +252,13 @@ class AddressBook(Screen): if data: for item in data: meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper() if (item[0][0].upper() >= 'A' and item[0][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) - # self.ids.ml.add_widget(meny) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 140 + carousel.height = 140 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -358,6 +400,8 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' + self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 + self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False return None else: @@ -487,10 +531,6 @@ class AddressSuccessful(Screen): pass -class NavigationLayout(): - pass - - class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" data = ListProperty() @@ -514,6 +554,9 @@ class Sent(Screen): def loadSent(self, account, where="", what=""): """Load Sent list for Sent messages.""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) @@ -528,11 +571,13 @@ class Sent(Screen): self.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, 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -549,7 +594,6 @@ class Sent(Screen): carousel.add_widget(ach_btn) carousel.index=1 self.ids.ml.add_widget(carousel) - # self.ids.ml.add_widget(meny) else: content = MDLabel(font_style='Body1', theme_text_color='Primary', @@ -568,6 +612,7 @@ class Sent(Screen): src_mng_obj = self.manager else: src_mng_obj = self.parent.parent + hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -575,7 +620,7 @@ class Sent(Screen): def delete(self, data_index, instance, *args): """delete sent mail from sent mail listing""" try: - msg_count_objs = self.parent.parent.parent.parent.children[2].ids + msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids except Exception as e: msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.sent_count) > 0: @@ -586,7 +631,6 @@ class Sent(Screen): sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) - # self.update_mail_count() self.update_trash() def archive(self, data_index, instance, *args): @@ -623,7 +667,7 @@ class Trash(Screen): for item in trash_data: meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper()))) + meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper() if (item[2][0].upper() >= 'A' and item[2][0].upper() <= 'Z') else '!'))) self.ids.ml.add_widget(meny) class Page(Screen): @@ -676,7 +720,7 @@ class NavigateApp(App): ] def build(self): - import os + import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -705,7 +749,6 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": - # return BMConfigParser().get(BMConfigParser().addresses()[0], 'label')[:12] + '..' if bmconfigparserigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: @@ -774,16 +817,12 @@ class NavigateApp(App): return True return False - def limit_spinner(self): - max = 2.8 - spinner_obj = ContentNavigationDrawer().ids.btn - spinner_obj.dropdown_cls.max_height = spinner_obj.height* max + max * 4 - def on_key(self, window, key, *args): """This method is used for going on previous screen""" if key == 27: # the esc key if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' + show_search_btn(self) # this is for direction of the screen comesup elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root @@ -791,19 +830,21 @@ class NavigateApp(App): to_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) if from_addr and to_addr: Draft().draft_msg(composer_objs) - # self.root.ids.scr_mngr.current + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False self.root.ids.scr_mngr.current = 'inbox' elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' elif self.root.ids.scr_mngr.current == "random": - self.root.ids.scr_mngr.current = 'login' + self.root.ids.scr_mngr.current = 'login' else: self.root.ids.scr_mngr.current = 'inbox' + show_search_btn(self) self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.restart) return True - def restart(self, *args): + def restart(self, *args): """this method is used to set transition direction""" self.root.ids.scr_mngr.transition.direction = 'left' self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) @@ -815,6 +856,8 @@ class NavigateApp(App): def clear_composer(self): """if slow down the nwe will make new composer edit screen""" + self.root.ids.serch_btn.opacity = 0 + self.root.ids.serch_btn.disabled = True composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -844,16 +887,77 @@ class NavigateApp(App): state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) return state.draft_count - def current_address_label(self, current_address = None): + def current_address_label(self, current_address=None): if BMConfigParser().addresses() or current_address: if current_address: first_name = current_address - else: + else: first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') f_name = first_name.split() return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] return '' + def searchQuery(self, instance, text): + '''This method is used for showing searched mails''' + if self.root.ids.search_input.opacity == 0: + self.root.ids.search_input.opacity = 1 + self.root.ids.search_input.size_hint = 4,None + # self.root.ids.serch_btn.opacity = 0 + # self.root.ids.serch_btn.disabled = True + self.root.ids.search_input.disabled = False + self.root.ids.search_input.focus = True + self.root.ids.toolbar.left_action_items = [] + self.root.ids.toolbar.title = '' + self.root.ids.myButton.opacity = 0 + self.root.ids.myButton.disabled = True + self.root.ids.reset_navbar.opacity = 1 + self.root.ids.reset_navbar.disabled = False + elif str(text): + state.search_screen = self.root.ids.scr_mngr.current + state.searcing_text = str(text).strip() + if state.search_screen == 'inbox': + self.root.ids.sc1.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + else: + self.root.ids.sc4.clear_widgets() + self.root.ids.sc4.add_widget(Sent()) + self.root.ids.scr_mngr.current = state.search_screen + + def reset_navdrawer(self, instance): + '''This methos is used for reseting navigation drawer''' + self.root.ids.search_input.text = '' + self.root.ids.search_input.opacity = 0 + self.root.ids.search_input.size_hint = 1,None + self.root.ids.search_input.disabled = True + self.root.ids.toolbar.left_action_items = [['menu', lambda x: self.root.toggle_nav_drawer()]] + self.root.ids.toolbar.title = self.current_address_label() + self.root.ids.myButton.opacity = 1 + self.root.ids.myButton.disabled = False + self.root.ids.reset_navbar.opacity = 0 + self.root.ids.reset_navbar.disabled = True + state.searcing_text = '' + if state.search_screen == 'inbox': + self.root.ids.sc1.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + else: + self.root.ids.sc4.clear_widgets() + self.root.ids.sc4.add_widget(Sent()) + + def check_search_screen(self, instance): + '''This method is used for showing search button only on inbox or sent screen''' + if instance.text == 'Inbox' or instance.text == 'Sent': + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False + state.searcing_text = '' + self.root.ids.sc1.clear_widgets() + self.root.ids.sc4.clear_widgets() + self.root.ids.sc1.add_widget(Inbox()) + self.root.ids.sc4.add_widget(Sent()) + else: + self.root.ids.serch_btn.opacity = 0 + self.root.ids.serch_btn.disabled = True + return + class GrashofPopup(Popup): def __init__(self, **kwargs): @@ -882,6 +986,8 @@ class GrashofPopup(Popup): queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + self.parent.children[1].ids.serch_btn.opacity = 0 + self.parent.children[1].ids.serch_btn.disabled = True self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): @@ -993,6 +1099,8 @@ class MailDetail(Screen): state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 + self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False def inbox_reply(self): """This method is used for replying inbox messages""" @@ -1124,12 +1232,11 @@ class Draft(Screen): for item in self.data: meny = TwoLineAvatarIconListItem(text='Draft', secondary_text=item['text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) - # wimg = Image(source='/home/cis/transparent1.png', size= (10, 10)) - # meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') - # carousel = MDCardPost(text_post='Card with text',swipe=True, callback=callback) if platform == 'android': - carousel.height = 150 + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -1207,4 +1314,34 @@ class Draft(Screen): state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() src_object.ids.sc16.add_widget(Draft()) - return \ No newline at end of file + return + + +def show_search_btn(self): + '''This method is used to show search button''' + self.root.ids.serch_btn.opacity = 1 + self.root.ids.serch_btn.disabled = False + + +def hide_search_btn(mgr_objs): + '''This method is used to hide search button and search box''' + mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 + mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True + mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1,None + mgr_objs.parent.parent.parent.ids.search_input.disabled = True + mgr_objs.parent.parent.parent.ids.search_input.opacity = 0 + mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] + mgr_objs.parent.parent.parent.ids.toolbar.title = NavigateApp().current_address_label() + mgr_objs.parent.parent.parent.ids.myButton.opacity = 1 + mgr_objs.parent.parent.parent.ids.myButton.disabled = False + mgr_objs.parent.parent.parent.ids.reset_navbar.opacity = 0 + mgr_objs.parent.parent.parent.ids.reset_navbar.disabled = True + + +class CustomSpinner(Spinner): + '''This class is used for setting spinner size''' + def __init__(self, *args, **kwargs): + '''This methods is used for setting size of spinner''' + super(CustomSpinner, self).__init__(*args, **kwargs) + max = 2.8 + self.dropdown_cls.max_height = self.height * max + max * 4 \ No newline at end of file diff --git a/src/state.py b/src/state.py index 34bef37b..745f2f4c 100644 --- a/src/state.py +++ b/src/state.py @@ -96,4 +96,8 @@ inbox_count = 0 trash_count = 0 -draft_count = 0 \ No newline at end of file +draft_count = 0 + +searcing_text = '' + +search_screen = '' \ No newline at end of file From a7a634be1bee0d67831d36d60b2240e3ee1f32ac Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 2 Aug 2019 17:56:40 +0300 Subject: [PATCH 014/306] Add self peers with rating 1 --- src/knownnodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knownnodes.py b/src/knownnodes.py index 5d1c003d..f4e00b90 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -98,7 +98,7 @@ def saveKnownNodes(dirName=None): def addKnownNode(stream, peer, lastseen=None, is_self=False): knownNodes[stream][peer] = { "lastseen": lastseen or time.time(), - "rating": 0, + "rating": 1 if is_self else 0, "self": is_self, } From e94046370934cec855802e06aa40a85215a7ca34 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 3 Aug 2019 17:19:28 +0530 Subject: [PATCH 015/306] flake8 fixes part1 --- src/bitmessagekivy/mpybit.py | 133 ++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 50 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 067eb4e5..b7d15bd9 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,22 +1,17 @@ -# -*- coding: utf-8 -*- +"""Coding: utf-8.""" from kivy.app import App from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ObjectProperty from kivy.uix.image import Image -from kivy.uix.screenmanager import Screen, NoTransition -from kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet +from kivy.uix.screenmanager import Screen from kivymd.button import MDIconButton -from kivymd.date_picker import MDDatePicker from kivymd.dialog import MDDialog from kivymd.label import MDLabel -from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch, BaseListItem -from kivymd.material_resources import DEVICE_TYPE +from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase from kivymd.selectioncontrols import MDCheckbox -from kivymd.snackbar import Snackbar from kivymd.theming import ThemeManager -from kivymd.time_picker import MDTimePicker from kivymd.list import ThreeLineAvatarIconListItem, TwoLineAvatarIconListItem, TwoLineListItem from kivy.properties import ListProperty, StringProperty, BooleanProperty from kivy.clock import Clock @@ -24,16 +19,12 @@ from bmconfigparser import BMConfigParser import state import queues from kivy.uix.popup import Popup -from helper_sql import * -from kivy.uix.gridlayout import GridLayout -from kivy.app import App +from helper_sql import sqlQuery, sqlExecute from kivy.uix.textinput import TextInput -from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout from kivy.uix.floatlayout import FloatLayout -from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty +from kivy.properties import NumericProperty from kivy.uix.recycleview import RecycleView -from kivy.uix.recyclegridlayout import RecycleGridLayout from kivy.uix.recycleview.views import RecycleDataViewBehavior from kivy.uix.label import Label from kivy.uix.recycleboxlayout import RecycleBoxLayout @@ -50,7 +41,10 @@ from kivy.uix.carousel import Carousel from kivy.utils import platform from kivy.uix.spinner import Spinner + class Navigatorss(MDNavigationDrawer): + """Navigators class contains image, title and logo.""" + image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() @@ -58,9 +52,11 @@ class Navigatorss(MDNavigationDrawer): class Inbox(Screen): """Inbox Screen uses screen to show widgets of screens.""" + data = ListProperty() def __init__(self, *args, **kwargs): + """Method Parsing the address.""" super(Inbox, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -89,16 +85,31 @@ class Inbox(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - data.append({'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len(mail[3]) > 10 else mail[3] + '\n' + " " + (third_text[:25] + '...!') if len(third_text) > 25 else third_text, 'receivedTime': mail[6] }) + data.append({ + 'text': mail[4].strip(), + 'secondary_text': mail[5][:10] + '...........' if len( + mail[3]) > 10 else mail[3] + '\n' + " " + ( + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, + 'receivedTime': mail[6]}) for item in data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) - meny.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) + meny = ThreeLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget( + AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item[ + 'secondary_text'][0].upper() <= 'Z') else '!'))) + meny.bind(on_press=partial(self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -110,7 +121,7 @@ class Inbox(Screen): carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') - ach_btn.background_color = (0,1,0,1) + ach_btn.background_color = (0, 1, 0, 1) ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) carousel.add_widget(ach_btn) carousel.index = 1 @@ -126,7 +137,7 @@ class Inbox(Screen): self.ids.ml.add_widget(content) def inbox_detail(self, receivedTime, *args): - """Load inbox page details""" + """Load inbox page details.""" state.detailPageType = 'inbox' state.sentMailTime = receivedTime if self.manager: @@ -140,7 +151,7 @@ class Inbox(Screen): src_mng_obj.current = 'mailDetail' def delete(self, data_index, instance, *args): - """Delete inbox mail from inbox listing""" + """Delete inbox mail from inbox listing.""" sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids if int(state.inbox_count) > 0: @@ -152,13 +163,13 @@ class Inbox(Screen): self.update_trash() def archive(self, data_index, instance, *args): - """Archive inbox mail from inbox listing""" + """Archive inbox mail from inbox listing.""" sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() def update_trash(self): - """Update trash screen mails which is deleted from inbox""" + """Update trash screen mails which is deleted from inbox.""" try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) @@ -167,11 +178,9 @@ class Inbox(Screen): self.parent.parent.screens[4].add_widget(Trash()) def refresh_callback(self, *args): - """A method that updates the state of your application - while the spinner remains on the screen.""" - + """A method that updates the state of your application while the spinner remains on the screen.""" def refresh_callback(interval): - """This methods is used for loading the inbox screen data""" + """Method used for loading the inbox screen data.""" self.ids.ml.clear_widgets() self.remove_widget(self.children[1]) try: @@ -187,7 +196,9 @@ class Inbox(Screen): class MyAddress(Screen): """MyAddress Screen uses screen to show widgets of screens.""" + def __init__(self, *args, **kwargs): + """Clock Schdule for method inbox accounts.""" super(MyAddress, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) @@ -198,8 +209,15 @@ class MyAddress(Screen): for address in state.kivyapp.variable_1: data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) for item in data: - meny = TwoLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['text'][0].upper() if (item['text'][0].upper() >= 'A' and item['text'][0].upper() <= 'Z') else '!'))) + meny = TwoLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item['text'][0].upper() if (item['text'][0].upper() >= 'A' and item[ + 'text'][0].upper() <= 'Z') else '!'))) meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: @@ -217,16 +235,15 @@ class MyAddress(Screen): pass def myadd_detail(self, fromaddress, label, *args): + """Myaddress Details.""" p = MyaddDetailPopup() p.open() p.set_address(fromaddress, label) def refresh_callback(self, *args): - """A method that updates the state of your application - while the spinner remains on the screen.""" - + """A method that updates the state of your application while the spinner remains on the screen.""" def refresh_callback(interval): - """This methods is used for loading the myaddress screen data""" + """Method used for loading the myaddress screen data.""" self.ids.ml.clear_widgets() self.remove_widget(self.children[1]) try: @@ -242,7 +259,9 @@ class MyAddress(Screen): class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" + def __init__(self, *args, **kwargs): + """Getting AddressBook Details.""" super(AddressBook, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) @@ -251,9 +270,15 @@ class AddressBook(Screen): data = sqlQuery("SELECT label, address from addressbook") if data: for item in data: - meny = TwoLineAvatarIconListItem(text=item[0], secondary_text=item[1], theme_text_color='Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[0][0].upper() if (item[0][0].upper() >= 'A' and item[0][0].upper() <= 'Z') else '!'))) - meny.bind(on_press = partial(self.addBook_detail, item[1], item[0])) + meny = TwoLineAvatarIconListItem( + text=item[0], + secondary_text=item[1], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item[0][0].upper() if (item[0][0].upper() >= 'A' and item[0][0].upper() <= 'Z') else '!'))) + meny.bind(on_press=partial(self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 140 @@ -269,7 +294,7 @@ class AddressBook(Screen): del_btn.bind(on_press=partial(self.delete_address, item[1])) carousel.add_widget(del_btn) carousel.add_widget(meny) - carousel.index=1 + carousel.index = 1 self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', @@ -282,59 +307,69 @@ class AddressBook(Screen): self.ids.ml.add_widget(content) def refreshs(self, *args): + """Refresh the Widget.""" state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) def addBook_detail(self, address, label, *args): + """Addressbook Details.""" p = AddbookDetailPopup() p.open() p.set_addbook_data(address, label) def delete_address(self, address, instance, *args): - """Delete inbox mail from inbox listing""" + """Delete inbox mail from inbox listing.""" self.ids.ml.remove_widget(instance.parent.parent) sqlExecute("DELETE FROM addressbook WHERE address = '{}';".format(address)) class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): - ''' Adds selection and focus behaviour to the view. ''' + """Adds selection and focus behaviour to the view.""" + pass class SelectableLabel(RecycleDataViewBehavior, Label): - ''' Add selection support to the 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 ''' + """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): - ''' Add selection on touch down ''' + """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. ''' + """Respond to the selection of items in the view.""" self.selected = is_selected if is_selected: print("selection changed to {0}".format(rv.data[index])) - rv.parent.txt_input.text = rv.parent.txt_input.text.replace(rv.parent.txt_input.text, rv.data[index]['text']) + rv.parent.txt_input.text = rv.parent.txt_input.text.replace( + rv.parent.txt_input.text, rv.data[index]['text']) class RV(RecycleView): + """Recycling View.""" + def __init__(self, **kwargs): + """Recycling Method.""" super(RV, self).__init__(**kwargs) class DropDownWidget(BoxLayout): + """Adding Dropdown Widget.""" + txt_input = ObjectProperty() rv = ObjectProperty() @@ -353,7 +388,7 @@ class DropDownWidget(BoxLayout): status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if status == 'success': - from addresses import * + from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' if addressVersionNumber > 4 or addressVersionNumber <= 1: @@ -385,9 +420,8 @@ class DropDownWidget(BoxLayout): encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress - state.msg_counter_objs = self.parent.parent.parent.parent.parent.parent.children[0].children[2].children[0].ids - # state.msg_counter_objs.send_cnt.badge_text = str(int(state.sent_count) + 1) - # state.sent_count = str(int(state.sent_count) + 1) + state.msg_counter_objs = \ + self.parent.parent.parent.parent.parent.parent.children[0].children[2].children[0].ids self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' @@ -423,7 +457,6 @@ class DropDownWidget(BoxLayout): self.main_pop = Popup(title="Error", content=self.box, size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) self.but.bind(on_press=self.main_pop.dismiss) - # self.main_pop.background = './images/popup.jpeg' self.main_pop.open() From a4d192f1c8922632c553b58c0a664548f8196909 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 5 Aug 2019 12:54:32 +0530 Subject: [PATCH 016/306] flake8 fixes part2 --- src/bitmessagekivy/mpybit.py | 285 +++++++++++++++++++++++++---------- 1 file changed, 205 insertions(+), 80 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b7d15bd9..9147a7eb 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -447,6 +447,7 @@ class DropDownWidget(BoxLayout): self.address_error_message(msg) def address_error_message(self, msg): + """Show Error Message.""" self.box = FloatLayout() self.lab = (Label(text=msg, font_size=25, size_hint=(None, None), pos_hint={'x': .25, 'y': .6})) @@ -461,20 +462,23 @@ class DropDownWidget(BoxLayout): class MyTextInput(TextInput): + """Takes the text input in the field.""" + txt_input = ObjectProperty() flt_list = ObjectProperty() word_list = ListProperty() - # this is the variable storing the number to which the look-up will start starting_no = NumericProperty(3) suggestion_text = '' def __init__(self, **kwargs): + """Getting Text Input.""" super(MyTextInput, self).__init__(**kwargs) def on_text(self, instance, value): - # find all the occurrence of the word + """Find all the occurrence of the word.""" self.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]] + 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 the data in the recycleview display_data = [] for i in matches: @@ -487,6 +491,7 @@ class MyTextInput(TextInput): self.parent.height = 400 def keyboard_on_key_down(self, window, keycode, text, modifiers): + """Key Down.""" if self.suggestion_text and keycode[1] == 'tab': self.insert_text(self.suggestion_text + ' ') return True @@ -494,14 +499,20 @@ class MyTextInput(TextInput): class Payment(Screen): + """Payment Method.""" + pass class Login(Screen): + """Login Screeen.""" + pass class NetworkStat(Screen): + """Method used to show network stat.""" + 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')) @@ -509,6 +520,7 @@ class NetworkStat(Screen): 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) @@ -525,17 +537,20 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): + """Navigate Content Drawer.""" + pass class Random(Screen): + """Generates Random Address.""" + is_active = BooleanProperty(False) checked = StringProperty("") - # self.manager.parent.ids.create.children[0].source = 'images/plus-4-xxl.png' def generateaddress(self): + """Method for Address Generator.""" import queues - # queues.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 label = self.ids.label.text eighteenByteRipe = False @@ -549,7 +564,6 @@ class Random(Screen): nonceTrialsPerByte, payloadLengthExtraBytes) ) - # self.manager.current = 'add_sucess' self.manager.current = 'myaddress' self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 @@ -561,14 +575,18 @@ class Random(Screen): class AddressSuccessful(Screen): + """Getting Address Detail.""" + pass class Sent(Screen): """Sent Screen uses screen to show widgets of screens.""" + data = ListProperty() def __init__(self, *args, **kwargs): + """Association with the screen.""" super(Sent, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -601,16 +619,30 @@ class Sent(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - self.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, 'lastactiontime': mail[6]}) + self.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, + 'lastactiontime': mail[6]}) for item in self.data: - meny = ThreeLineAvatarIconListItem(text=item['text'], secondary_text=item['secondary_text'], theme_text_color= 'Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item['secondary_text'][0].upper() if (item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][0].upper() <= 'Z') else '!'))) - meny.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) + meny = ThreeLineAvatarIconListItem( + text=item['text'], + secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget( + AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][ + 0].upper() <= 'Z') else '!'))) + meny.bind(on_press=partial(self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 elif platform == 'linux': - carousel.height = meny.height - 10 + carousel.height = meny.height - 10 carousel.size_hint_y = None carousel.ignore_perpendicular_swipes = True carousel.data_index = 0 @@ -622,10 +654,10 @@ class Sent(Screen): carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') - ach_btn.background_color = (0,1,0,1) + ach_btn.background_color = (0, 1, 0, 1) ach_btn.bind(on_press=partial(self.archive, item['lastactiontime'])) carousel.add_widget(ach_btn) - carousel.index=1 + carousel.index = 1 self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', @@ -638,7 +670,7 @@ class Sent(Screen): self.ids.ml.add_widget(content) def sent_detail(self, lastsenttime, *args): - """Load sent mail details""" + """Load sent mail details.""" state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: @@ -651,7 +683,7 @@ class Sent(Screen): src_mng_obj.current = 'mailDetail' def delete(self, data_index, instance, *args): - """delete sent mail from sent mail listing""" + """Delete sent mail from sent mail listing.""" try: msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids except Exception as e: @@ -667,13 +699,13 @@ class Sent(Screen): self.update_trash() def archive(self, data_index, instance, *args): - """archive sent mail from sent mail listing""" + """Archive sent mail from sent mail listing.""" sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() def update_trash(self): - """Update trash screen mails which is deleted from inbox""" + """Update trash screen mails which is deleted from inbox.""" try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) @@ -684,7 +716,9 @@ class Sent(Screen): class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" + 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) @@ -694,38 +728,53 @@ class Trash(Screen): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] - inbox = sqlQuery("SELECT toaddress, fromaddress, subject, message from inbox WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) - sent = sqlQuery("SELECT toaddress, fromaddress, subject, message from sent WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + inbox = sqlQuery( + "SELECT toaddress, fromaddress, subject, message from inbox \ + WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + sent = sqlQuery( + "SELECT toaddress, fromaddress, subject, message from sent \ + WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) trash_data = inbox + sent for item in trash_data: - meny = ThreeLineAvatarIconListItem(text=item[1], secondary_text=item[2], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/text_images/{}.png'.format(item[2][0].upper() if (item[2][0].upper() >= 'A' and item[2][0].upper() <= 'Z') else '!'))) + meny = ThreeLineAvatarIconListItem( + text=item[1], + secondary_text=item[2], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format(item[2][0].upper() if ( + item[2][0].upper() >= 'A' and item[2][0].upper() <= 'Z') else '!'))) self.ids.ml.add_widget(meny) + class Page(Screen): + """Page Screen show widgets of page.""" + pass class Create(Screen): + """Creates the screen widgets.""" + def __init__(self, **kwargs): + """Getting Labels and address from addressbook.""" super(Create, self).__init__(**kwargs) widget_1 = DropDownWidget() - from helper_sql import * widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] widget_1.ids.txt_input.starting_no = 2 self.add_widget(widget_1) -class AddressSuccessful(Screen): - pass - - class Setting(Screen): + """Setting the Screen components.""" + pass class NavigateApp(App): + """Navigation Layout of class.""" + theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() @@ -753,7 +802,8 @@ class NavigateApp(App): ] def build(self): - import os + """Method builds the widget.""" + import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -765,10 +815,12 @@ class NavigateApp(App): return main_widget def run(self): + """Running the widgets.""" kivyuisignaler.release() super(NavigateApp, self).run() def show_address_success(self): + """Showing the succesfull address.""" content = MDLabel(font_style='Body1', theme_text_color='Secondary', text="Successfully Saved your contact address. " @@ -782,7 +834,7 @@ class NavigateApp(App): def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" if name == "text": - if bmconfigparserigParser().addresses(): + if BMConfigParser().addresses(): return BMConfigParser().addresses()[0][:16] + '..' else: return "textdemo" @@ -808,10 +860,23 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = self.root_window.children[1].children[2].children[0].ids - state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format(state.association))[0][0]) - state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format(state.association))[0][0]) - state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) - state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'draft' ;".format(state.association))[0][0]) + state.sent_count = str( + sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format( + state.association))[0][0]) + state.inbox_count = str( + sqlQuery( + "SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format( + state.association))[0][0]) + state.trash_count = str( + sqlQuery( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )\ + +(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format( + state.association))[0][0]) + state.draft_count = str( + sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'draft' ;".format( + state.association))[0][0]) if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count @@ -819,7 +884,6 @@ class NavigateApp(App): msg_counter_objs.trash_cnt.badge_text = state.trash_count msg_counter_objs.draft_cnt.badge_text = state.draft_count - def getInboxMessageDetail(self, instance): """It will get message detail after make selected message description.""" try: @@ -837,21 +901,24 @@ class NavigateApp(App): return "Bitmessage Login" def addingtoaddressbook(self): + """Adding to address Book.""" p = GrashofPopup() p.open() def getDefaultAccData(self): + """Getting Default Account Data.""" if BMConfigParser().addresses(): return BMConfigParser().addresses()[0] return 'Select Address' def addressexist(self): + """Checking address existence.""" if BMConfigParser().addresses(): return True return False def on_key(self, window, key, *args): - """This method is used for going on previous screen""" + """Method is used for going on previous screen.""" if key == 27: # the esc key if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' @@ -878,17 +945,18 @@ class NavigateApp(App): return True def restart(self, *args): - """this method is used to set transition direction""" + """Method used to set transition direction.""" self.root.ids.scr_mngr.transition.direction = 'left' self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) def status_dispatching(self, data): + """Method used for status dispatching acknowledgment.""" ackData, message = data if state.ackdata == ackData: state.status.status = message def clear_composer(self): - """if slow down the nwe will make new composer edit screen""" + """If slow down the nwe will make new composer edit screen.""" self.root.ids.serch_btn.opacity = 0 self.root.ids.serch_btn.disabled = True composer_obj = self.root.ids.sc3.children[0].ids @@ -898,7 +966,7 @@ class NavigateApp(App): composer_obj.subject.text = '' def on_stop(self): - """On stop methos is used for stoping the runing script""" + """On stop methos is used for stoping the runing script.""" print("**************************EXITING FROM APPLICATION*****************************") import shutdown shutdown.doCleanShutdown() @@ -908,33 +976,46 @@ class NavigateApp(App): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] if text == 'Sent': - state.sent_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + state.sent_count = str( + sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format( + text.lower(), state.association))[0][0]) return state.sent_count elif text == 'Inbox': - state.inbox_count = str(sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + state.inbox_count = str( + sqlQuery( + "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format( + text.lower(), state.association))[0][0]) return state.inbox_count elif text == 'Trash': - state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )+(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format(state.association))[0][0]) + state.trash_count = str( + sqlQuery( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )\ + +(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format( + state.association))[0][0]) return state.trash_count elif text == 'Draft': - state.draft_count = str(sqlQuery("SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format(text.lower(), state.association))[0][0]) + state.draft_count = str( + sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format( + text.lower(), state.association))[0][0]) return state.draft_count def current_address_label(self, current_address=None): + """Getting current address labels.""" if BMConfigParser().addresses() or current_address: if current_address: first_name = current_address else: first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') f_name = first_name.split() - return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] + return f_name[0][:14] + '...' if len(f_name[0]) > 15 else f_name[0] return '' def searchQuery(self, instance, text): - '''This method is used for showing searched mails''' + """Method used for showing searched mails.""" if self.root.ids.search_input.opacity == 0: self.root.ids.search_input.opacity = 1 - self.root.ids.search_input.size_hint = 4,None + self.root.ids.search_input.size_hint = 4, None # self.root.ids.serch_btn.opacity = 0 # self.root.ids.serch_btn.disabled = True self.root.ids.search_input.disabled = False @@ -957,10 +1038,10 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = state.search_screen def reset_navdrawer(self, instance): - '''This methos is used for reseting navigation drawer''' + """Method used for reseting navigation drawer.""" self.root.ids.search_input.text = '' self.root.ids.search_input.opacity = 0 - self.root.ids.search_input.size_hint = 1,None + self.root.ids.search_input.size_hint = 1, None self.root.ids.search_input.disabled = True self.root.ids.toolbar.left_action_items = [['menu', lambda x: self.root.toggle_nav_drawer()]] self.root.ids.toolbar.title = self.current_address_label() @@ -969,7 +1050,7 @@ class NavigateApp(App): self.root.ids.reset_navbar.opacity = 0 self.root.ids.reset_navbar.disabled = True state.searcing_text = '' - if state.search_screen == 'inbox': + if state.search_screen == 'inbox': self.root.ids.sc1.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) else: @@ -977,7 +1058,7 @@ class NavigateApp(App): self.root.ids.sc4.add_widget(Sent()) def check_search_screen(self, instance): - '''This method is used for showing search button only on inbox or sent screen''' + """Method used for showing search button only on inbox or sent screen.""" if instance.text == 'Inbox' or instance.text == 'Sent': self.root.ids.serch_btn.opacity = 1 self.root.ids.serch_btn.disabled = False @@ -993,7 +1074,10 @@ class NavigateApp(App): class GrashofPopup(Popup): + """Methods for saving contacts, error messages.""" + def __init__(self, **kwargs): + """Grash of pop screen settings.""" super(GrashofPopup, self).__init__(**kwargs) if state.screen_density[0] <= 720: self.size_hint_y = 0.4 @@ -1003,6 +1087,7 @@ class GrashofPopup(Popup): self.size_hint_x = 0.7 def savecontact(self): + """Method is used for Saving Contacts.""" my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values entered_text = str(self.ids.label.text) if entered_text in my_addresses: @@ -1024,6 +1109,7 @@ class GrashofPopup(Popup): self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): + """Showing error message.""" content = MDLabel(font_style='Body1', theme_text_color='Secondary', text="Hey you are not allowed to save blank address contact. " @@ -1042,34 +1128,40 @@ class GrashofPopup(Popup): class AvatarSampleWidget(ILeftBody, Image): + """Avatar Sample Widget.""" + pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): + """Left icon sample widget.""" + pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): + """Right icon sample widget.""" pass class NavigationDrawerTwoLineListItem( TwoLineListItem, NavigationDrawerHeaderBase): + """Navigation Drawer in Listitems.""" address_property = StringProperty() def __init__(self, **kwargs): + """Method for Navigation Drawer.""" super(NavigationDrawerTwoLineListItem, self).__init__(**kwargs) Clock.schedule_once(lambda dt: self.setup()) def setup(self): - """ - Binds Controller.current_account property. - """ + """Bind Controller.current_account property.""" pass def on_current_account(self, account): + """Account detail.""" pass def _update_specific_text_color(self, instance, value): @@ -1081,14 +1173,16 @@ class NavigationDrawerTwoLineListItem( class MailDetail(Screen): """MailDetail Screen uses to show the detail of mails.""" + to_addr = StringProperty() from_addr = StringProperty() subject = StringProperty() message = StringProperty() status = StringProperty() - page_type = StringProperty() + page_type = StringProperty() def __init__(self, *args, **kwargs): + """Mail Details method.""" super(MailDetail, self).__init__(*args, **kwargs) Clock.schedule_once(self.init_ui, 0) @@ -1096,15 +1190,20 @@ class MailDetail(Screen): """Clock Schdule for method MailDetail mails.""" self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent': - data = sqlQuery("select toaddress, fromaddress, subject, message , status, ackdata from sent where lastactiontime = {};".format(state.sentMailTime)) + data = sqlQuery( + "select toaddress, fromaddress, subject, message , status, ackdata from sent \ + where lastactiontime = {};".format(state.sentMailTime)) state.status = self state.ackdata = data[0][5] self.assign_mail_details(data) elif state.detailPageType == 'inbox': - data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + data = sqlQuery( + "select toaddress, fromaddress, subject, message from inbox where received = {};".format( + state.sentMailTime)) self.assign_mail_details(data) - def assign_mail_details(self, data): + def assign_mail_details(self, data): + """Assigning mail details.""" self.to_addr = data[0][0] self.from_addr = data[0][1] self.subject = data[0][2].upper() @@ -1113,7 +1212,8 @@ class MailDetail(Screen): self.status = data[0][4] def delete_mail(self): - msg_count_objs =self.parent.parent.parent.parent.parent.children[2].children[0].ids + """Method for mail delete.""" + msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if state.detailPageType == 'sent': sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) @@ -1136,8 +1236,10 @@ class MailDetail(Screen): self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False def inbox_reply(self): - """This method is used for replying inbox messages""" - data = sqlQuery("select toaddress, fromaddress, subject, message from inbox where received = {};".format(state.sentMailTime)) + """Method used for replying inbox messages.""" + data = sqlQuery( + "select toaddress, fromaddress, subject, message from inbox where received = {};".format( + state.sentMailTime)) composer_obj = self.parent.parent.screens[2].children[0].ids composer_obj.ti.text = data[0][1] composer_obj.btn.text = data[0][1] @@ -1146,16 +1248,18 @@ class MailDetail(Screen): self.parent.parent.current = 'create' def copy_sent_mail(self): - """This method is used for copying sent mail to the composer""" + """Method used for copying sent mail to the composer.""" pass class MyaddDetailPopup(Popup): - """MyaddDetailPopup pop is used for showing my address detail""" + """MyaddDetailPopup pop is used for showing my address detail.""" + address_label = StringProperty() address = StringProperty() def __init__(self, **kwargs): + """My Address Details screen setting.""" super(MyaddDetailPopup, self).__init__(**kwargs) if state.screen_density[0] <= 720: self.size_hint_y = 0.32 @@ -1165,12 +1269,12 @@ class MyaddDetailPopup(Popup): self.size_hint_x = 0.7 def set_address(self, address, label): - """Getting address for displaying details on popup""" + """Getting address for displaying details on popup.""" self.address_label = label self.address = address def send_message_from(self): - """This method used to fill from address of composer autofield""" + """Method used to fill from address of composer autofield.""" window_obj = self.parent.children[1].ids window_obj.sc3.children[0].ids.ti.text = self.address window_obj.sc3.children[0].ids.btn.text = self.address @@ -1180,12 +1284,15 @@ class MyaddDetailPopup(Popup): window_obj.scr_mngr.current = 'create' self.dismiss() + class AddbookDetailPopup(Popup): - """AddbookDetailPopup pop is used for showing my address detail""" + """AddbookDetailPopup pop is used for showing my address detail.""" + address_label = StringProperty() address = StringProperty() def __init__(self, **kwargs): + """Method used set screen of address detail page.""" super(AddbookDetailPopup, self).__init__(**kwargs) if state.screen_density[0] <= 720: self.size_hint_y = 0.35 @@ -1195,20 +1302,23 @@ class AddbookDetailPopup(Popup): self.size_hint_x = 0.7 def set_addbook_data(self, address, label): - """Getting address book data for detial dipaly""" + """Getting address book data for detial dipaly.""" self.address_label = label self.address = address def update_addbook_label(self, address): - """Updating the label of address book address""" + """Updating the label of address book address.""" if str(self.ids.add_label.text): - sqlExecute("UPDATE addressbook SET label = '{}' WHERE address = '{}';".format(str(self.ids.add_label.text), address)) + sqlExecute( + "UPDATE addressbook SET label = '{}' WHERE address = '{}';".format( + str( + self.ids.add_label.text), address)) self.parent.children[1].ids.sc11.clear_widgets() self.parent.children[1].ids.sc11.add_widget(AddressBook()) self.dismiss() def send_message_to(self): - """This method used to fill to_address of composer autofield""" + """Method used to fill to_address of composer autofield.""" window_obj = self.parent.children[1].ids window_obj.sc3.children[0].ids.txt_input.text = self.address window_obj.sc3.children[0].ids.ti.text = '' @@ -1223,6 +1333,7 @@ class ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" def qrdisplay(self): + """Method used for showing QR Code.""" self.ids.qr.clear_widgets() if platform == 'android': from kivy.garden.qrcode import QRCodeWidget @@ -1231,9 +1342,11 @@ class ShowQRCode(Screen): class Draft(Screen): """Draft screen is used to show the list of draft messages.""" + data = ListProperty() def __init__(self, *args, **kwargs): + """Method used for storing draft messages.""" super(Draft, self).__init__(*args, **kwargs) if state.association == '': if BMConfigParser().addresses(): @@ -1261,9 +1374,19 @@ class Draft(Screen): if queryreturn: for mail in queryreturn: third_text = mail[3].replace('\n', ' ') - self.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, 'lastactiontime': mail[6]}) + self.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, + 'lastactiontime': mail[6]}) for item in self.data: - meny = TwoLineAvatarIconListItem(text='Draft', secondary_text=item['text'], theme_text_color= 'Custom',text_color=NavigateApp().theme_cls.primary_color) + meny = TwoLineAvatarIconListItem( + text='Draft', + secondary_text=item['text'], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) carousel = Carousel(direction='right') if platform == 'android': @@ -1280,7 +1403,7 @@ class Draft(Screen): del_btn.bind(on_press=partial(self.delete_draft, item['lastactiontime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) - carousel.index=1 + carousel.index = 1 self.ids.ml.add_widget(carousel) else: content = MDLabel(font_style='Body1', @@ -1293,7 +1416,7 @@ class Draft(Screen): self.ids.ml.add_widget(content) def delete_draft(self, data_index, instance, *args): - """This method is used to delete draft message permanently""" + """Method used to delete draft message permanently.""" sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) try: msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids @@ -1305,7 +1428,7 @@ class Draft(Screen): self.ids.ml.remove_widget(instance.parent.parent) def draft_msg(self, src_object): - """This method is used for saving draft mails""" + """Method used for saving draft mails.""" composer_object = src_object.children[1].children[0].children[0].children[0].children[0].ids fromAddress = str(composer_object.ti.text) toAddress = str(composer_object.txt_input.text) @@ -1317,7 +1440,7 @@ class Draft(Screen): from addresses import decodeAddress status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) - from addresses import * + from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' stealthLevel = BMConfigParser().safeGetInt( @@ -1351,19 +1474,20 @@ class Draft(Screen): def show_search_btn(self): - '''This method is used to show search button''' + """Method used to show search button.""" self.root.ids.serch_btn.opacity = 1 self.root.ids.serch_btn.disabled = False def hide_search_btn(mgr_objs): - '''This method is used to hide search button and search box''' + """Method used to hide search button and search box.""" mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True - mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1,None + mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1, None mgr_objs.parent.parent.parent.ids.search_input.disabled = True mgr_objs.parent.parent.parent.ids.search_input.opacity = 0 - mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] + mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = \ + [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] mgr_objs.parent.parent.parent.ids.toolbar.title = NavigateApp().current_address_label() mgr_objs.parent.parent.parent.ids.myButton.opacity = 1 mgr_objs.parent.parent.parent.ids.myButton.disabled = False @@ -1372,9 +1496,10 @@ def hide_search_btn(mgr_objs): class CustomSpinner(Spinner): - '''This class is used for setting spinner size''' + """This class is used for setting spinner size.""" + def __init__(self, *args, **kwargs): - '''This methods is used for setting size of spinner''' + """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) max = 2.8 - self.dropdown_cls.max_height = self.height * max + max * 4 \ No newline at end of file + self.dropdown_cls.max_height = self.height * max + max * 4 From e56f452e7d0105bd15da5974315959112b23ec79 Mon Sep 17 00:00:00 2001 From: cis Date: Mon, 5 Aug 2019 13:11:56 +0530 Subject: [PATCH 017/306] Changes made on search Ui with filter --- src/bitmessagekivy/main.kv | 13 ++++++++- src/bitmessagekivy/mpybit.py | 53 +++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 861bbbac..ee44841e 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -207,7 +207,6 @@ NavigationLayout: pos_hint: {'x': .1, 'y': 0.3} color: 0,0,0,1 background_color: (0,0,0,0) - on_press:app.searchQuery(self, search_input.text) Image: source: './images/search_mail.png' center_x: self.parent.center_x @@ -226,6 +225,18 @@ NavigationLayout: center_x: self.parent.center_x center_y: self.parent.center_y size: 55, 55 + BoxLayout: + id: search_bar + size_hint_y: None + height: self.minimum_height + + MDIconButton: + icon: 'magnify' + + MDTextField: + id: search_field + hint_text: 'Search icon' + on_text: app.searchQuery(self) ScreenManager: id: scr_mngr Inbox: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 067eb4e5..ed371ff9 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -49,6 +49,7 @@ from functools import partial from kivy.uix.carousel import Carousel from kivy.utils import platform from kivy.uix.spinner import Spinner +from kivymd.textfields import MDTextField class Navigatorss(MDNavigationDrawer): image_source = StringProperty('images/qidenticon_two.png') @@ -897,24 +898,12 @@ class NavigateApp(App): return f_name[0][:14]+ '...' if len(f_name[0])>15 else f_name[0] return '' - def searchQuery(self, instance, text): + def searchQuery(self, instance): '''This method is used for showing searched mails''' - if self.root.ids.search_input.opacity == 0: - self.root.ids.search_input.opacity = 1 - self.root.ids.search_input.size_hint = 4,None - # self.root.ids.serch_btn.opacity = 0 - # self.root.ids.serch_btn.disabled = True - self.root.ids.search_input.disabled = False - self.root.ids.search_input.focus = True - self.root.ids.toolbar.left_action_items = [] - self.root.ids.toolbar.title = '' - self.root.ids.myButton.opacity = 0 - self.root.ids.myButton.disabled = True - self.root.ids.reset_navbar.opacity = 1 - self.root.ids.reset_navbar.disabled = False - elif str(text): + # import pdb;pdb.set_trace() + if str(instance.text): state.search_screen = self.root.ids.scr_mngr.current - state.searcing_text = str(text).strip() + state.searcing_text = str(instance.text).strip() if state.search_screen == 'inbox': self.root.ids.sc1.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) @@ -922,6 +911,29 @@ class NavigateApp(App): self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) self.root.ids.scr_mngr.current = state.search_screen + # if self.root.ids.search_input.opacity == 0: + # self.root.ids.search_input.opacity = 1 + # self.root.ids.search_input.size_hint = 4,None + # # self.root.ids.serch_btn.opacity = 0 + # # self.root.ids.serch_btn.disabled = True + # self.root.ids.search_input.disabled = False + # self.root.ids.search_input.focus = True + # self.root.ids.toolbar.left_action_items = [] + # self.root.ids.toolbar.title = '' + # self.root.ids.myButton.opacity = 0 + # self.root.ids.myButton.disabled = True + # self.root.ids.reset_navbar.opacity = 1 + # self.root.ids.reset_navbar.disabled = False + # elif str(text): + # state.search_screen = self.root.ids.scr_mngr.current + # state.searcing_text = str(text).strip() + # if state.search_screen == 'inbox': + # self.root.ids.sc1.clear_widgets() + # self.root.ids.sc1.add_widget(Inbox()) + # else: + # self.root.ids.sc4.clear_widgets() + # self.root.ids.sc4.add_widget(Sent()) + # self.root.ids.scr_mngr.current = state.search_screen def reset_navdrawer(self, instance): '''This methos is used for reseting navigation drawer''' @@ -946,6 +958,9 @@ class NavigateApp(App): def check_search_screen(self, instance): '''This method is used for showing search button only on inbox or sent screen''' if instance.text == 'Inbox' or instance.text == 'Sent': + if not self.root.ids.search_bar.children: + self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) + # self.root.ids.search_bar.add_widget(MDTextField(id='search_field', hint_text='Search icon', on_text=app.searchQuery(self))) self.root.ids.serch_btn.opacity = 1 self.root.ids.serch_btn.disabled = False state.searcing_text = '' @@ -954,6 +969,7 @@ class NavigateApp(App): self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) else: + self.root.ids.search_bar.clear_widgets() self.root.ids.serch_btn.opacity = 0 self.root.ids.serch_btn.disabled = True return @@ -1191,9 +1207,8 @@ class ShowQRCode(Screen): def qrdisplay(self): self.ids.qr.clear_widgets() - if platform == 'android': - from kivy.garden.qrcode import QRCodeWidget - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) + from kivy.garden.qrcode import QRCodeWidget + self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) class Draft(Screen): From e494a5589ac099bd826b1f34cc2ab178a67abc67 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 5 Aug 2019 15:49:19 +0530 Subject: [PATCH 018/306] Autopep8 fixes part1 --- src/bitmessagekivy/mpybit.py | 309 ++++++++++++++++++++++------------- 1 file changed, 194 insertions(+), 115 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 9147a7eb..e4e172bc 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -9,10 +9,15 @@ from kivymd.button import MDIconButton from kivymd.dialog import MDDialog from kivymd.label import MDLabel from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch -from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase +from kivymd.navigationdrawer import ( + MDNavigationDrawer, + NavigationDrawerHeaderBase) from kivymd.selectioncontrols import MDCheckbox from kivymd.theming import ThemeManager -from kivymd.list import ThreeLineAvatarIconListItem, TwoLineAvatarIconListItem, TwoLineListItem +from kivymd.list import ( + ThreeLineAvatarIconListItem, + TwoLineAvatarIconListItem, + TwoLineListItem) from kivy.properties import ListProperty, StringProperty, BooleanProperty from kivy.clock import Clock from bmconfigparser import BMConfigParser @@ -98,13 +103,14 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget( - AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') else '!'))) - meny.bind(on_press=partial(self.inbox_detail, item['receivedTime'])) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item[ + 'secondary_text'][0].upper() <= 'Z') + else '!'))) + meny.bind(on_press=partial( + self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 @@ -117,23 +123,26 @@ class Inbox(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) + del_btn.bind(on_press=partial( + self.delete, item['receivedTime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial(self.archive, item['receivedTime'])) + ach_btn.bind(on_press=partial( + self.archive, item['receivedTime'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) else: - content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) def inbox_detail(self, receivedTime, *args): @@ -152,11 +161,16 @@ class Inbox(Screen): def delete(self, data_index, instance, *args): """Delete inbox mail from inbox listing.""" - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) - msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + data_index)) + msg_count_objs = \ + self.parent.parent.parent.parent.children[2].children[0].ids if int(state.inbox_count) > 0: - msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) - msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + msg_count_objs.inbox_cnt.badge_text = str( + int(state.inbox_count) - 1) + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) + 1) state.inbox_count = str(int(state.inbox_count) - 1) state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) @@ -164,7 +178,8 @@ class Inbox(Screen): def archive(self, data_index, instance, *args): """Archive inbox mail from inbox listing.""" - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(data_index)) + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE \ + received = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -178,7 +193,8 @@ class Inbox(Screen): self.parent.parent.screens[4].add_widget(Trash()) def refresh_callback(self, *args): - """A method that updates the state of your application while the spinner remains on the screen.""" + """A method that updates the state of your application.""" + """While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" self.ids.ml.clear_widgets() @@ -207,7 +223,9 @@ class MyAddress(Screen): if BMConfigParser().addresses() or state.kivyapp.variable_1: data = [] for address in state.kivyapp.variable_1: - data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) + data.append({ + 'text': BMConfigParser().get(address, 'label'), + 'secondary_text': address}) for item in data: meny = TwoLineAvatarIconListItem( text=item['text'], @@ -216,18 +234,22 @@ class MyAddress(Screen): text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( - item['text'][0].upper() if (item['text'][0].upper() >= 'A' and item[ - 'text'][0].upper() <= 'Z') else '!'))) - meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) + item['text'][0].upper() if ( + item['text'][0].upper() >= 'A' and item['text'][ + 0].upper() <= 'Z') + else '!'))) + meny.bind(on_press=partial( + self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) else: - content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no address is created by user!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no address is created by user!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) try: self.manager.current = 'login' @@ -241,7 +263,8 @@ class MyAddress(Screen): p.set_address(fromaddress, label) def refresh_callback(self, *args): - """A method that updates the state of your application while the spinner remains on the screen.""" + """A method that updates the state of your application.""" + """While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the myaddress screen data.""" self.ids.ml.clear_widgets() @@ -277,8 +300,11 @@ class AddressBook(Screen): text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( source='./images/text_images/{}.png'.format( - item[0][0].upper() if (item[0][0].upper() >= 'A' and item[0][0].upper() <= 'Z') else '!'))) - meny.bind(on_press=partial(self.addBook_detail, item[1], item[0])) + item[0][0].upper() if ( + item[0][0].upper() >= 'A' and item[0][ + 0].upper() <= 'Z') else '!'))) + meny.bind(on_press=partial( + self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 140 @@ -320,7 +346,8 @@ class AddressBook(Screen): def delete_address(self, address, instance, *args): """Delete inbox mail from inbox listing.""" self.ids.ml.remove_widget(instance.parent.parent) - sqlExecute("DELETE FROM addressbook WHERE address = '{}';".format(address)) + sqlExecute( + "DELETE FROM addressbook WHERE address = '{}';".format(address)) class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, @@ -385,14 +412,15 @@ class DropDownWidget(BoxLayout): if sendMessageToPeople: if toAddress != '' and subject and message: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) + status, addressVersionNumber, streamNumber, ripe = \ + decodeAddress(toAddress) if status == 'success': from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' if addressVersionNumber > 4 or addressVersionNumber <= 1: - print("addressVersionNumber > 4 or addressVersionNumber <= 1") + print("addressVersionNumber > 4 \ + or addressVersionNumber <= 1") if streamNumber > 1 or streamNumber == 0: print("streamNumber > 1 or streamNumber == 0") if statusIconColor == 'red': @@ -403,7 +431,8 @@ class DropDownWidget(BoxLayout): ackdata = genAckPayload(streamNumber, stealthLevel) t = () sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '''INSERT INTO sent VALUES + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', toAddress, ripe, @@ -420,8 +449,8 @@ class DropDownWidget(BoxLayout): encoding, BMConfigParser().getint('bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress - state.msg_counter_objs = \ - self.parent.parent.parent.parent.parent.parent.children[0].children[2].children[0].ids + state.msg_counter_objs = self.parent.parent.parent.parent\ + .parent.parent.children[0].children[2].children[0].ids self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' @@ -434,8 +463,10 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' - self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 - self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False + self.parent.parent.parent.parent.parent\ + .ids.serch_btn.opacity = 1 + self.parent.parent.parent.parent.parent\ + .ids.serch_btn.disabled = False return None else: @@ -449,14 +480,26 @@ class DropDownWidget(BoxLayout): def address_error_message(self, msg): """Show Error Message.""" self.box = FloatLayout() - self.lab = (Label(text=msg, font_size=25, - size_hint=(None, None), pos_hint={'x': .25, 'y': .6})) + self.lab = (Label( + text=msg, + font_size=25, + size_hint=(None, None), + pos_hint={'x': .25, 'y': .6})) self.box.add_widget(self.lab) - self.but = (Button(text="dismiss", size_hint=(None, None), - width=200, height=50, pos_hint={'x': .3, 'y': 0})) + self.but = (Button( + text="dismiss", + size_hint=(None, None), + width=200, + height=50, + pos_hint={'x': .3, 'y': 0})) self.box.add_widget(self.but) - self.main_pop = Popup(title="Error", content=self.box, - size_hint=(None, None), size=(550, 400), auto_dismiss=False, title_size=30) + self.main_pop = Popup( + title="Error", + content=self.box, + size_hint=(None, None), + size=(550, 400), + auto_dismiss=False, + title_size=30) self.but.bind(on_press=self.main_pop.dismiss) self.main_pop.open() @@ -476,15 +519,15 @@ class MyTextInput(TextInput): def on_text(self, instance, value): """Find all the occurrence of the word.""" + import pdb;pdb.set_trace() self.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 the data in the recycleview + 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.ids.rv.data = display_data - # ensure the size is okay if len(matches) <= 10: self.parent.height = (250 + (len(matches) * 20)) else: @@ -495,7 +538,8 @@ class MyTextInput(TextInput): 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) + return super(MyTextInput, self).keyboard_on_key_down( + window, keycode, text, modifiers) class Payment(Screen): @@ -513,11 +557,15 @@ class Login(Screen): class NetworkStat(Screen): """Method used to show network stat.""" - 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_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')) + text_variable_5 = StringProperty( + 'Processed {0} object to be synced'.format('0')) def __init__(self, *args, **kwargs): """Init method for network stat.""" @@ -529,11 +577,16 @@ class NetworkStat(Screen): import network.stats import shared from network import objectracker - self.text_variable_1 = '{0} :: {1}'.format('Total Connections', str(len(network.stats.connectedHostsList()))) - self.text_variable_2 = 'Processed {0} per-to-per messages'.format(str(shared.numberOfMessagesProcessed)) - self.text_variable_3 = 'Processed {0} brodcast messages'.format(str(shared.numberOfBroadcastsProcessed)) - self.text_variable_4 = 'Processed {0} public keys'.format(str(shared.numberOfPubkeysProcessed)) - self.text_variable_5 = '{0} object to be synced'.format(len(objectracker.missingObjects)) + self.text_variable_1 = '{0} :: {1}'.format( + 'Total Connections', str(len(network.stats.connectedHostsList()))) + self.text_variable_2 = 'Processed {0} per-to-per messages'.format( + str(shared.numberOfMessagesProcessed)) + self.text_variable_3 = 'Processed {0} brodcast messages'.format( + str(shared.numberOfBroadcastsProcessed)) + self.text_variable_4 = 'Processed {0} public keys'.format( + str(shared.numberOfPubkeysProcessed)) + self.text_variable_5 = '{0} object to be synced'.format( + len(objectracker.missingObjects)) class ContentNavigationDrawer(Navigatorss): @@ -568,8 +621,6 @@ class Random(Screen): self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 self.parent.parent.parent.parent.ids.toolbar.disabled = False - - # state.myAddressObj = self.parent.parent.parent.parent.ids.sc10 self.parent.parent.parent.parent.ids.sc10.clear_widgets() self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) @@ -611,7 +662,8 @@ class Sent(Screen): xAddress = 'fromaddress' queryreturn = kivy_helper_search.search_sql( xAddress, account, "sent", where, what, False) - if state.msg_counter_objs and state.association == state.check_sent_acc: + if state.msg_counter_objs and state.association == \ + state.check_sent_acc: state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(int(state.sent_count) + 1) state.check_sent_acc = None @@ -622,7 +674,8 @@ class Sent(Screen): self.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( + mail[2]) > 10 else mail[2] + '\n' + " " + ( + third_text[:25] + '...!') if len( third_text) > 25 else third_text, 'lastactiontime': mail[6]}) for item in self.data: @@ -631,13 +684,14 @@ class Sent(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget( - AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item['secondary_text'][ - 0].upper() <= 'Z') else '!'))) - meny.bind(on_press=partial(self.sent_detail, item['lastactiontime'])) + meny.add_widget(AvatarSampleWidget( + source='./images/text_images/{}.png'.format( + item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item[ + 'secondary_text'][0].upper() <= 'Z') + else '!'))) + meny.bind(on_press=partial( + self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 @@ -650,23 +704,26 @@ class Sent(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1.0, 0.0, 0.0, 1.0) - del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) + del_btn.bind(on_press=partial( + self.delete, item['lastactiontime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) ach_btn = Button(text='Achieve') ach_btn.background_color = (0, 1, 0, 1) - ach_btn.bind(on_press=partial(self.archive, item['lastactiontime'])) + ach_btn.bind(on_press=partial( + self.archive, item['lastactiontime'])) carousel.add_widget(ach_btn) carousel.index = 1 self.ids.ml.add_widget(carousel) else: - content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) def sent_detail(self, lastsenttime, *args): @@ -685,22 +742,29 @@ class Sent(Screen): def delete(self, data_index, instance, *args): """Delete sent mail from sent mail listing.""" try: - msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = self.parent.parent.parent.parent.children[ + 2].children[0].ids except Exception as e: - msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = self.parent.parent.parent.parent.parent.children[ + 2].children[0].ids if int(state.sent_count) > 0: - msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) - msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + msg_count_objs.send_cnt.badge_text = str( + int(state.sent_count) - 1) + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) + 1) state.sent_count = str(int(state.sent_count) - 1) state.trash_count = str(int(state.trash_count) + 1) - - sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + sqlExecute( + "UPDATE sent SET folder = 'trash' \ + WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() def archive(self, data_index, instance, *args): """Archive sent mail from sent mail listing.""" - sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + sqlExecute( + "UPDATE sent SET folder = 'trash' \ + WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -730,10 +794,12 @@ class Trash(Screen): inbox = sqlQuery( "SELECT toaddress, fromaddress, subject, message from inbox \ - WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + WHERE folder = 'trash' and fromaddress = '{}';".format( + state.association)) sent = sqlQuery( "SELECT toaddress, fromaddress, subject, message from sent \ - WHERE folder = 'trash' and fromaddress = '{}';".format(state.association)) + WHERE folder = 'trash' and fromaddress = '{}';".format( + state.association)) trash_data = inbox + sent for item in trash_data: @@ -743,8 +809,9 @@ class Trash(Screen): theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(item[2][0].upper() if ( - item[2][0].upper() >= 'A' and item[2][0].upper() <= 'Z') else '!'))) + source='./images/text_images/{}.png'.format( + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!'))) self.ids.ml.add_widget(meny) @@ -761,7 +828,9 @@ class Create(Screen): """Getting Labels and address from addressbook.""" super(Create, self).__init__(**kwargs) widget_1 = DropDownWidget() - widget_1.ids.txt_input.word_list = [addr[1] for addr in sqlQuery("SELECT label, address from addressbook")] + widget_1.ids.txt_input.word_list = [ + addr[1] for addr in sqlQuery( + "SELECT label, address from addressbook")] widget_1.ids.txt_input.starting_no = 2 self.add_widget(widget_1) @@ -846,7 +915,8 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" - address_label = self.current_address_label(BMConfigParser().get(text, 'label')) + address_label = self.current_address_label( + BMConfigParser().get(text, 'label')) self.root_window.children[1].ids.toolbar.title = address_label state.association = text self.root.ids.sc1.clear_widgets() @@ -919,15 +989,16 @@ class NavigateApp(App): def on_key(self, window, key, *args): """Method is used for going on previous screen.""" - if key == 27: # the esc key + if key == 27: if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' show_search_btn(self) - # this is for direction of the screen comesup elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root - from_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.ti.text) - to_addr = str(self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) + from_addr = str( + self.root.children[1].children[0].children[0].children[0].children[0].ids.ti.text) + to_addr = str( + self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) if from_addr and to_addr: Draft().draft_msg(composer_objs) self.root.ids.serch_btn.opacity = 1 @@ -1006,7 +1077,8 @@ class NavigateApp(App): if current_address: first_name = current_address else: - first_name = BMConfigParser().get(BMConfigParser().addresses()[0], 'label') + first_name = BMConfigParser().get( + BMConfigParser().addresses()[0], 'label') f_name = first_name.split() return f_name[0][:14] + '...' if len(f_name[0]) > 15 else f_name[0] return '' @@ -1016,8 +1088,6 @@ class NavigateApp(App): if self.root.ids.search_input.opacity == 0: self.root.ids.search_input.opacity = 1 self.root.ids.search_input.size_hint = 4, None - # self.root.ids.serch_btn.opacity = 0 - # self.root.ids.serch_btn.disabled = True self.root.ids.search_input.disabled = False self.root.ids.search_input.focus = True self.root.ids.toolbar.left_action_items = [] @@ -1043,7 +1113,8 @@ class NavigateApp(App): self.root.ids.search_input.opacity = 0 self.root.ids.search_input.size_hint = 1, None self.root.ids.search_input.disabled = True - 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.toggle_nav_drawer()]] self.root.ids.toolbar.title = self.current_address_label() self.root.ids.myButton.opacity = 1 self.root.ids.myButton.disabled = False @@ -1215,15 +1286,18 @@ class MailDetail(Screen): """Method for mail delete.""" msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if state.detailPageType == 'sent': - sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(state.sentMailTime)) + sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( + state.sentMailTime)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' elif state.detailPageType == 'inbox': - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format(state.sentMailTime)) - msg_count_objs.inbox_cnt.badge_text = str(int(state.inbox_count) - 1) + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + state.sentMailTime)) + msg_count_objs.inbox_cnt.badge_text = str( + int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) self.parent.parent.screens[0].clear_widgets() self.parent.parent.screens[0].add_widget(Inbox()) @@ -1337,7 +1411,8 @@ class ShowQRCode(Screen): self.ids.qr.clear_widgets() if platform == 'android': from kivy.garden.qrcode import QRCodeWidget - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) + self.ids.qr.add_widget(QRCodeWidget( + data=self.manager.get_parent_window().children[0].address)) class Draft(Screen): @@ -1387,7 +1462,8 @@ class Draft(Screen): secondary_text=item['text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget(source='./images/avatar.png')) + meny.add_widget(AvatarSampleWidget( + source='./images/avatar.png')) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 @@ -1400,7 +1476,8 @@ class Draft(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1.0, 0.0, 0.0, 1.0) - del_btn.bind(on_press=partial(self.delete_draft, item['lastactiontime'])) + del_btn.bind(on_press=partial( + self.delete_draft, item['lastactiontime'])) carousel.add_widget(del_btn) carousel.add_widget(meny) carousel.index = 1 @@ -1417,13 +1494,15 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) + sqlExecute( + "DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) try: msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids except Exception as e: msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.draft_count) > 0: - msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) + msg_count_objs.draft_cnt.badge_text = str( + int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) self.ids.ml.remove_widget(instance.parent.parent) From dbe69348f439e51790169dc807ffe47807377ec0 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 6 Aug 2019 15:35:03 +0530 Subject: [PATCH 019/306] Autopep8 part 2 --- src/bitmessagekivy/mpybit.py | 164 +++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 75 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index e4e172bc..483c230d 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -519,7 +519,6 @@ class MyTextInput(TextInput): def on_text(self, instance, value): """Find all the occurrence of the word.""" - import pdb;pdb.set_trace() self.parent.parent.parent.parent.ids.rv.data = [] matches = [self.word_list[i] for i in range( len(self.word_list)) if self.word_list[ @@ -909,7 +908,8 @@ class NavigateApp(App): return "textdemo" elif name == "values": if BMConfigParser().addresses(): - return [address[:16] + '..' for address in BMConfigParser().addresses()] + return [address[:16] + '..' + for address in BMConfigParser().addresses()] else: return "valuesdemo" @@ -929,24 +929,24 @@ class NavigateApp(App): self.root.ids.sc16.add_widget(Draft()) self.root.ids.scr_mngr.current = 'inbox' - msg_counter_objs = self.root_window.children[1].children[2].children[0].ids + msg_counter_objs = \ + self.root_window.children[1].children[2].children[0].ids state.sent_count = str( sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'sent' ;".format( - state.association))[0][0]) + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and \ + folder = 'sent' ;".format(state.association))[0][0]) state.inbox_count = str( sqlQuery( - "SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and folder = 'inbox' ;".format( - state.association))[0][0]) - state.trash_count = str( - sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )\ - +(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format( - state.association))[0][0]) + "SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and \ + folder = 'inbox' ;".format(state.association))[0][0]) + state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent \ + where fromaddress = '{0}' and folder = 'trash' ) \ + +(SELECT count(*) FROM inbox where fromaddress = '{0}' and \ + folder = 'trash') AS SumCount".format(state.association))[0][0]) state.draft_count = str( sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and folder = 'draft' ;".format( - state.association))[0][0]) + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and \ + folder = 'draft' ;".format(state.association))[0][0]) if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count @@ -955,7 +955,7 @@ class NavigateApp(App): msg_counter_objs.draft_cnt.badge_text = state.draft_count def getInboxMessageDetail(self, instance): - """It will get message detail after make selected message description.""" + """Getting message detail after selected message description.""" try: self.root.ids._mngr.current = 'page' except AttributeError: @@ -991,14 +991,15 @@ class NavigateApp(App): """Method is used for going on previous screen.""" if key == 27: if self.root.ids.scr_mngr.current == "mailDetail": - self.root.ids.scr_mngr.current = 'sent' if state.detailPageType == 'sent' else 'inbox' + self.root.ids.scr_mngr.current = \ + 'sent' if state.detailPageType == 'sent' else 'inbox' show_search_btn(self) elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root - from_addr = str( - self.root.children[1].children[0].children[0].children[0].children[0].ids.ti.text) - to_addr = str( - self.root.children[1].children[0].children[0].children[0].children[0].ids.txt_input.text) + from_addr = str(self.root.children[1].children[0].children[ + 0].children[0].children[0].ids.ti.text) + to_addr = str(self.root.children[1].children[0].children[ + 0].children[0].children[0].ids.txt_input.text) if from_addr and to_addr: Draft().draft_msg(composer_objs) self.root.ids.serch_btn.opacity = 1 @@ -1038,7 +1039,7 @@ class NavigateApp(App): def on_stop(self): """On stop methos is used for stoping the runing script.""" - print("**************************EXITING FROM APPLICATION*****************************") + print("*******************EXITING FROM APPLICATION*******************") import shutdown shutdown.doCleanShutdown() @@ -1047,28 +1048,29 @@ class NavigateApp(App): if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] if text == 'Sent': - state.sent_count = str( - sqlQuery("SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format( + state.sent_count = str(sqlQuery( + "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and \ + folder = '{0}' ;".format( text.lower(), state.association))[0][0]) return state.sent_count elif text == 'Inbox': - state.inbox_count = str( - sqlQuery( - "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and folder = '{0}' ;".format( - text.lower(), state.association))[0][0]) + state.inbox_count = str(sqlQuery( + "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and \ + folder = '{0}' ;".format( + text.lower(), state.association))[0][0]) return state.inbox_count elif text == 'Trash': - state.trash_count = str( - sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and folder = 'trash' )\ - +(SELECT count(*) FROM inbox where fromaddress = '{0}' and folder = 'trash') AS SumCount".format( - state.association))[0][0]) + state.trash_count = str(sqlQuery( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' \ + and folder = 'trash' )+(SELECT count(*) FROM inbox where \ + fromaddress = '{0}' and folder = 'trash') AS SumCount".format( + state.association))[0][0]) return state.trash_count elif text == 'Draft': - state.draft_count = str( - sqlQuery( - "SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and folder = '{0}' ;".format( - text.lower(), state.association))[0][0]) + state.draft_count = str(sqlQuery( + "SELECT COUNT(*) FROM sent WHERE fromaddress = '{1}' and \ + folder = '{0}' ;".format( + text.lower(), state.association))[0][0]) return state.draft_count def current_address_label(self, current_address=None): @@ -1129,7 +1131,7 @@ class NavigateApp(App): self.root.ids.sc4.add_widget(Sent()) def check_search_screen(self, instance): - """Method used for showing search button only on inbox or sent screen.""" + """Method shows search button on inbox and sent screen only.""" if instance.text == 'Inbox' or instance.text == 'Sent': self.root.ids.serch_btn.opacity = 1 self.root.ids.serch_btn.disabled = False @@ -1159,7 +1161,8 @@ class GrashofPopup(Popup): def savecontact(self): """Method is used for Saving Contacts.""" - my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + my_addresses = \ + self.parent.children[1].children[2].children[0].ids.btn.values entered_text = str(self.ids.label.text) if entered_text in my_addresses: self.ids.label.focus = True @@ -1181,12 +1184,13 @@ class GrashofPopup(Popup): def show_error_message(self): """Showing error message.""" - content = MDLabel(font_style='Body1', - theme_text_color='Secondary', - text="Hey you are not allowed to save blank address contact. " - "That's wrong!", - size_hint_y=None, - valign='top') + content = MDLabel( + font_style='Body1', + theme_text_color='Secondary', + text="Hey you are not allowed to save blank address contact. " + "That's wrong!", + size_hint_y=None, + valign='top') content.bind(texture_size=content.setter('size')) self.dialog = MDDialog(content=content, size_hint=(.8, None), @@ -1262,15 +1266,16 @@ class MailDetail(Screen): self.page_type = state.detailPageType if state.detailPageType else '' if state.detailPageType == 'sent': data = sqlQuery( - "select toaddress, fromaddress, subject, message , status, ackdata from sent \ - where lastactiontime = {};".format(state.sentMailTime)) + "select toaddress, fromaddress, subject, message, status, \ + ackdata from sent where lastactiontime = {};".format( + state.sentMailTime)) state.status = self state.ackdata = data[0][5] self.assign_mail_details(data) elif state.detailPageType == 'inbox': data = sqlQuery( - "select toaddress, fromaddress, subject, message from inbox where received = {};".format( - state.sentMailTime)) + "select toaddress, fromaddress, subject, message from inbox \ + where received = {};".format(state.sentMailTime)) self.assign_mail_details(data) def assign_mail_details(self, data): @@ -1284,18 +1289,21 @@ class MailDetail(Screen): def delete_mail(self): """Method for mail delete.""" - msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = \ + self.parent.parent.parent.parent.parent.children[2].children[0].ids if state.detailPageType == 'sent': - sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( - state.sentMailTime)) + sqlExecute( + "UPDATE sent SET folder = 'trash' WHERE \ + lastactiontime = {};".format(state.sentMailTime)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) self.parent.parent.current = 'sent' elif state.detailPageType == 'inbox': - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE received = {};".format( - state.sentMailTime)) + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE \ + received = {};".format(state.sentMailTime)) msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) @@ -1312,8 +1320,8 @@ class MailDetail(Screen): def inbox_reply(self): """Method used for replying inbox messages.""" data = sqlQuery( - "select toaddress, fromaddress, subject, message from inbox where received = {};".format( - state.sentMailTime)) + "select toaddress, fromaddress, subject, message from inbox where \ + received = {};".format(state.sentMailTime)) composer_obj = self.parent.parent.screens[2].children[0].ids composer_obj.ti.text = data[0][1] composer_obj.btn.text = data[0][1] @@ -1383,10 +1391,8 @@ class AddbookDetailPopup(Popup): def update_addbook_label(self, address): """Updating the label of address book address.""" if str(self.ids.add_label.text): - sqlExecute( - "UPDATE addressbook SET label = '{}' WHERE address = '{}';".format( - str( - self.ids.add_label.text), address)) + sqlExecute("UPDATE addressbook SET label = '{}' WHERE \ + address = '{}';".format(str(self.ids.add_label.text), address)) self.parent.children[1].ids.sc11.clear_widgets() self.parent.children[1].ids.sc11.add_widget(AddressBook()) self.dismiss() @@ -1483,23 +1489,26 @@ class Draft(Screen): carousel.index = 1 self.ids.ml.add_widget(carousel) else: - content = MDLabel(font_style='Body1', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - bold=True, - size_hint_y=None, - valign='top') + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') self.ids.ml.add_widget(content) def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute( - "DELETE FROM sent WHERE lastactiontime = '{}';".format(data_index)) + sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( + data_index)) try: - msg_count_objs = self.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = \ + self.parent.parent.parent.parent.children[2].children[0].ids except Exception as e: - msg_count_objs = self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = self.parent.parent.parent.parent.parent.children[ + 2].children[0].ids if int(state.draft_count) > 0: msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) @@ -1508,7 +1517,8 @@ class Draft(Screen): def draft_msg(self, src_object): """Method used for saving draft mails.""" - composer_object = src_object.children[1].children[0].children[0].children[0].children[0].ids + composer_object = src_object.children[1].children[0].children[ + 0].children[0].children[0].ids fromAddress = str(composer_object.ti.text) toAddress = str(composer_object.txt_input.text) subject = str(composer_object.subject.text) @@ -1517,8 +1527,8 @@ class Draft(Screen): sendMessageToPeople = True if sendMessageToPeople: from addresses import decodeAddress - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) + status, addressVersionNumber, streamNumber, ripe = \ + decodeAddress(toAddress) from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' @@ -1528,7 +1538,8 @@ class Draft(Screen): ackdata = genAckPayload(streamNumber, stealthLevel) t = () sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '''INSERT INTO sent VALUES + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', toAddress, ripe, @@ -1560,6 +1571,7 @@ def show_search_btn(self): def hide_search_btn(mgr_objs): """Method used to hide search button and search box.""" + mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1, None @@ -1567,7 +1579,8 @@ def hide_search_btn(mgr_objs): mgr_objs.parent.parent.parent.ids.search_input.opacity = 0 mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = \ [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] - mgr_objs.parent.parent.parent.ids.toolbar.title = NavigateApp().current_address_label() + mgr_objs.parent.parent.parent.ids.toolbar.title = \ + NavigateApp().current_address_label() mgr_objs.parent.parent.parent.ids.myButton.opacity = 1 mgr_objs.parent.parent.parent.ids.myButton.disabled = False mgr_objs.parent.parent.parent.ids.reset_navbar.opacity = 0 @@ -1582,3 +1595,4 @@ class CustomSpinner(Spinner): super(CustomSpinner, self).__init__(*args, **kwargs) max = 2.8 self.dropdown_cls.max_height = self.height * max + max * 4 + print(args) From c97a8ceffc1204aa94af48bfa178fcfb852e4eec Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 6 Aug 2019 16:31:05 +0530 Subject: [PATCH 020/306] Changes made after merging new pull request --- src/bitmessagekivy/mpybit.py | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 9be788dc..d1ee84a9 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -45,7 +45,6 @@ from functools import partial from kivy.uix.carousel import Carousel from kivy.utils import platform from kivy.uix.spinner import Spinner -from kivymd.textfields import MDTextField class Navigatorss(MDNavigationDrawer): @@ -1087,7 +1086,7 @@ class NavigateApp(App): return '' def searchQuery(self, instance): - '''This method is used for showing searched mails''' + """Method used for showing searched mails.""" state.search_screen = self.root.ids.scr_mngr.current state.searcing_text = str(instance.text).strip() if state.search_screen == 'inbox': @@ -1097,29 +1096,6 @@ class NavigateApp(App): self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) self.root.ids.scr_mngr.current = state.search_screen - # if self.root.ids.search_input.opacity == 0: - # self.root.ids.search_input.opacity = 1 - # self.root.ids.search_input.size_hint = 4,None - # # self.root.ids.serch_btn.opacity = 0 - # # self.root.ids.serch_btn.disabled = True - # self.root.ids.search_input.disabled = False - # self.root.ids.search_input.focus = True - # self.root.ids.toolbar.left_action_items = [] - # self.root.ids.toolbar.title = '' - # self.root.ids.myButton.opacity = 0 - # self.root.ids.myButton.disabled = True - # self.root.ids.reset_navbar.opacity = 1 - # self.root.ids.reset_navbar.disabled = False - # elif str(text): - # state.search_screen = self.root.ids.scr_mngr.current - # state.searcing_text = str(text).strip() - # if state.search_screen == 'inbox': - # self.root.ids.sc1.clear_widgets() - # self.root.ids.sc1.add_widget(Inbox()) - # else: - # self.root.ids.sc4.clear_widgets() - # self.root.ids.sc4.add_widget(Sent()) - # self.root.ids.scr_mngr.current = state.search_screen def reset_navdrawer(self, instance): """Method used for reseting navigation drawer.""" @@ -1146,8 +1122,8 @@ class NavigateApp(App): """Method shows search button on inbox and sent screen only.""" if instance.text == 'Inbox' or instance.text == 'Sent': if not self.root.ids.search_bar.children: - self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) - # self.root.ids.search_bar.add_widget(MDTextField(id='search_field', hint_text='Search icon', on_text=app.searchQuery(self))) + self.root.ids.search_bar.add_widget( + MDIconButton(icon='magnify')) self.root.ids.serch_btn.opacity = 1 self.root.ids.serch_btn.disabled = False state.searcing_text = '' @@ -1432,7 +1408,8 @@ class ShowQRCode(Screen): """Method used for showing QR Code.""" self.ids.qr.clear_widgets() from kivy.garden.qrcode import QRCodeWidget - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) + self.ids.qr.add_widget(QRCodeWidget( + data=self.manager.get_parent_window().children[0].address)) class Draft(Screen): @@ -1585,7 +1562,6 @@ def show_search_btn(self): def hide_search_btn(mgr_objs): """Method used to hide search button and search box.""" - mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1, None @@ -1609,4 +1585,3 @@ class CustomSpinner(Spinner): super(CustomSpinner, self).__init__(*args, **kwargs) max = 2.8 self.dropdown_cls.max_height = self.height * max + max * 4 - print(args) From ad2a2b3fb4e579ddc8794a6c2faa107f97e6c09a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 1 Aug 2019 14:37:26 +0300 Subject: [PATCH 021/306] Inherit helper_threading.StoppableThread from threading.Thread and do random.seed() in its __init__ --- src/api.py | 10 ++++------ src/class_addressGenerator.py | 8 ++------ src/class_objectProcessor.py | 3 ++- src/class_singleCleaner.py | 8 ++------ src/class_singleWorker.py | 6 ++---- src/class_smtpDeliver.py | 8 ++------ src/class_smtpServer.py | 6 +++--- src/helper_random.py | 5 +++++ src/helper_threading.py | 16 ++++++++++++++-- src/network/addrthread.py | 13 ++++--------- src/network/announcethread.py | 8 +++----- src/network/downloadthread.py | 7 ++----- src/network/invthread.py | 31 ++++++++++++++----------------- src/network/networkthread.py | 7 ++----- src/network/receivequeuethread.py | 15 +++------------ src/network/uploadthread.py | 7 ++----- src/upnp.py | 6 ++---- 17 files changed, 68 insertions(+), 96 deletions(-) diff --git a/src/api.py b/src/api.py index d3e87dfd..fad5d623 100644 --- a/src/api.py +++ b/src/api.py @@ -21,7 +21,6 @@ import json import random # nosec import socket import subprocess -import threading import time from binascii import hexlify, unhexlify from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer @@ -32,7 +31,6 @@ from version import softwareVersion import defaults import helper_inbox import helper_sent -import helper_threading import network.stats import proofofwork import queues @@ -44,6 +42,7 @@ from bmconfigparser import BMConfigParser from debug import logger from helper_ackPayload import genAckPayload from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure +from helper_threading import StoppableThread from inventory import Inventory str_chan = '[chan]' @@ -73,11 +72,10 @@ class StoppableXMLRPCServer(SimpleXMLRPCServer): # This thread, of which there is only one, runs the API. -class singleAPI(threading.Thread, helper_threading.StoppableThread): +class singleAPI(StoppableThread): """API thread""" - def __init__(self): - threading.Thread.__init__(self, name="singleAPI") - self.initStop() + + name = "singleAPI" def stopThread(self): super(singleAPI, self).stopThread() diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 0893b73a..d930fc99 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -1,6 +1,5 @@ import time -import threading import hashlib from binascii import hexlify from pyelliptic import arithmetic @@ -19,12 +18,9 @@ from fallback import RIPEMD160Hash from helper_threading import StoppableThread -class addressGenerator(threading.Thread, StoppableThread): +class addressGenerator(StoppableThread): - def __init__(self): - # QThread.__init__(self, parent) - threading.Thread.__init__(self, name="addressGenerator") - self.initStop() + name = "addressGenerator" def stopThread(self): try: diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 720cdf02..1a9c0d81 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -35,12 +35,13 @@ class objectProcessor(threading.Thread): objects (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. """ def __init__(self): + threading.Thread.__init__(self, name="objectProcessor") + random.seed() # It may be the case that the last time Bitmessage was running, # the user closed it before it finished processing everything in the # objectProcessorQueue. Assuming that Bitmessage wasn't closed # forcefully, it should have saved the data in the queue into the # objectprocessorqueue table. Let's pull it out. - threading.Thread.__init__(self, name="objectProcessor") queryreturn = sqlQuery( '''SELECT objecttype, data FROM objectprocessorqueue''') for row in queryreturn: diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index e2cdbb89..a5938716 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -21,7 +21,6 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) import gc import os import shared -import threading import time import tr @@ -36,14 +35,11 @@ import queues import state -class singleCleaner(threading.Thread, StoppableThread): +class singleCleaner(StoppableThread): + name = "singleCleaner" cycleLength = 300 expireDiscoveredPeers = 300 - def __init__(self): - threading.Thread.__init__(self, name="singleCleaner") - self.initStop() - def run(self): gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index d979ae19..0798296e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -7,7 +7,6 @@ src/class_singleWorker.py from __future__ import division import hashlib -import threading import time from binascii import hexlify, unhexlify from struct import pack @@ -43,12 +42,11 @@ def sizeof_fmt(num, suffix='h/s'): return "%.1f%s%s" % (num, 'Yi', suffix) -class singleWorker(threading.Thread, StoppableThread): +class singleWorker(StoppableThread): """Thread for performing PoW""" def __init__(self): - threading.Thread.__init__(self, name="singleWorker") - self.initStop() + super(singleWorker, self).__init__(name="singleWorker") proofofwork.init() def stopThread(self): diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index ef7a4363..fa607220 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -6,7 +6,6 @@ src/class_smtpDeliver.py import smtplib import sys -import threading import urlparse from email.header import Header from email.mime.text import MIMEText @@ -20,14 +19,11 @@ from helper_threading import StoppableThread SMTPDOMAIN = "bmaddr.lan" -class smtpDeliver(threading.Thread, StoppableThread): +class smtpDeliver(StoppableThread): """SMTP client thread for delivery""" + name = "smtpDeliver" _instance = None - def __init__(self): - threading.Thread.__init__(self, name="smtpDeliver") - self.initStop() - def stopThread(self): try: queues.UISignallerQueue.put(("stopThread", "data")) # pylint: disable=no-member diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 216d35be..d87ab69b 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -154,10 +154,10 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): continue return -class smtpServer(threading.Thread, StoppableThread): + +class smtpServer(StoppableThread): def __init__(self, parent=None): - threading.Thread.__init__(self, name="smtpServerThread") - self.initStop() + super(smtpServer, self).__init__(name="smtpServerThread") self.server = smtpServerPyBitmessage(('127.0.0.1', LISTENPORT), None) def stopThread(self): diff --git a/src/helper_random.py b/src/helper_random.py index bb173d1b..57f0ccb3 100644 --- a/src/helper_random.py +++ b/src/helper_random.py @@ -6,6 +6,11 @@ from pyelliptic.openssl import OpenSSL NoneType = type(None) +def seed(): + """Initialize random number generator""" + random.seed() + + def randomBytes(n): """Method randomBytes.""" try: diff --git a/src/helper_threading.py b/src/helper_threading.py index 6b6a5e25..4b0a074e 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -1,7 +1,9 @@ """Helper threading perform all the threading operations.""" -from contextlib import contextmanager import threading +from contextlib import contextmanager + +import helper_random try: import prctl @@ -22,7 +24,16 @@ else: threading.Thread._Thread__bootstrap = _thread_name_hack -class StoppableThread(object): +class StoppableThread(threading.Thread): + name = None + + def __init__(self, name=None): + if name: + self.name = name + super(StoppableThread, self).__init__(name=self.name) + self.initStop() + helper_random.seed() + def initStop(self): self.stop = threading.Event() self._stopped = False @@ -35,6 +46,7 @@ class StoppableThread(object): class BusyError(threading.ThreadError): pass + @contextmanager def nonBlocking(lock): locked = lock.acquire(False) diff --git a/src/network/addrthread.py b/src/network/addrthread.py index 5b0ea638..9f516e80 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -1,18 +1,13 @@ import Queue -import threading -import addresses from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool from queues import addrQueue -import protocol import state -class AddrThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="AddrBroadcaster") - self.initStop() - self.name = "AddrBroadcaster" + +class AddrThread(StoppableThread): + name = "AddrBroadcaster" def run(self): while not state.shutdown: @@ -28,7 +23,7 @@ class AddrThread(threading.Thread, StoppableThread): except KeyError: continue - #finish + # finish addrQueue.iterate() for i in range(len(chunk)): diff --git a/src/network/announcethread.py b/src/network/announcethread.py index a94eeb36..e7bec45a 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -1,4 +1,3 @@ -import threading import time from bmconfigparser import BMConfigParser @@ -9,11 +8,10 @@ from network.connectionpool import BMConnectionPool from network.udp import UDPSocket import state -class AnnounceThread(threading.Thread, StoppableThread): + +class AnnounceThread(StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="Announcer") - self.initStop() - self.name = "Announcer" + super(AnnounceThread, self).__init__(name="Announcer") logger.info("init announce thread") def run(self): diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index babce5da..308dffcb 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,4 +1,3 @@ -import threading import time import addresses @@ -12,7 +11,7 @@ from network.connectionpool import BMConnectionPool from objectracker import missingObjects -class DownloadThread(threading.Thread, StoppableThread): +class DownloadThread(StoppableThread): minPending = 200 maxRequestChunk = 1000 requestTimeout = 60 @@ -20,9 +19,7 @@ class DownloadThread(threading.Thread, StoppableThread): requestExpires = 3600 def __init__(self): - threading.Thread.__init__(self, name="Downloader") - self.initStop() - self.name = "Downloader" + super(DownloadThread, self).__init__(name="Downloader") logger.info("init download thread") self.lastCleaned = time.time() diff --git a/src/network/invthread.py b/src/network/invthread.py index 6f6f1364..e79172ba 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,16 +1,14 @@ import Queue -from random import randint, shuffle -import threading +import random from time import time import addresses -from bmconfigparser import BMConfigParser +import protocol +import state from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool from network.dandelion import Dandelion from queues import invQueue -import protocol -import state def handleExpiredDandelion(expired): @@ -33,11 +31,8 @@ def handleExpiredDandelion(expired): i.objectsNewToThem[hashid] = time() -class InvThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="InvBroadcaster") - self.initStop() - self.name = "InvBroadcaster" +class InvThread(StoppableThread): + name = "InvBroadcaster" def handleLocallyGenerated(self, stream, hashId): Dandelion().addHash(hashId, stream=stream) @@ -80,7 +75,7 @@ class InvThread(threading.Thread, StoppableThread): if connection == Dandelion().objectChildStem(inv[1]): # Fluff trigger by RNG # auto-ignore if config set to 0, i.e. dandelion is off - if randint(1, 100) >= state.dandelion: + if random.randint(1, 100) >= state.dandelion: fluffs.append(inv[1]) # send a dinv only if the stem node supports dandelion elif connection.services & protocol.NODE_DANDELION > 0: @@ -91,13 +86,15 @@ class InvThread(threading.Thread, StoppableThread): fluffs.append(inv[1]) if fluffs: - shuffle(fluffs) - connection.append_write_buf(protocol.CreatePacket('inv', \ - addresses.encodeVarint(len(fluffs)) + "".join(fluffs))) + random.shuffle(fluffs) + connection.append_write_buf(protocol.CreatePacket( + 'inv', addresses.encodeVarint(len(fluffs)) + + "".join(fluffs))) if stems: - shuffle(stems) - connection.append_write_buf(protocol.CreatePacket('dinv', \ - addresses.encodeVarint(len(stems)) + "".join(stems))) + random.shuffle(stems) + connection.append_write_buf(protocol.CreatePacket( + 'dinv', addresses.encodeVarint(len(stems)) + + "".join(stems))) invQueue.iterate() for i in range(len(chunk)): diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 9ceb856b..433c771e 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -1,4 +1,3 @@ -import threading import network.asyncore_pollchoose as asyncore import state @@ -8,11 +7,9 @@ from network.connectionpool import BMConnectionPool from queues import excQueue -class BMNetworkThread(threading.Thread, StoppableThread): +class BMNetworkThread(StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="Asyncore") - self.initStop() - self.name = "Asyncore" + super(BMNetworkThread, self).__init__(name="Asyncore") logger.info("init asyncore thread") def run(self): diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 0a7562cb..5d8cbd37 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -1,27 +1,18 @@ import errno import Queue import socket -import sys -import threading -import time -import addresses -from bmconfigparser import BMConfigParser from debug import logger from helper_threading import StoppableThread -from inventory import Inventory from network.connectionpool import BMConnectionPool -from network.bmproto import BMProto from network.advanceddispatcher import UnknownStateError from queues import receiveDataQueue -import protocol import state -class ReceiveQueueThread(threading.Thread, StoppableThread): + +class ReceiveQueueThread(StoppableThread): def __init__(self, num=0): - threading.Thread.__init__(self, name="ReceiveQueue_%i" %(num)) - self.initStop() - self.name = "ReceiveQueue_%i" % (num) + super(ReceiveQueueThread, self).__init__(name="ReceiveQueue_%i" % num) logger.info("init receive queue thread %i", num) def run(self): diff --git a/src/network/uploadthread.py b/src/network/uploadthread.py index 61ee6fab..9b29ef0a 100644 --- a/src/network/uploadthread.py +++ b/src/network/uploadthread.py @@ -2,7 +2,6 @@ src/network/uploadthread.py """ # pylint: disable=unsubscriptable-object -import threading import time import helper_random @@ -15,14 +14,12 @@ from network.dandelion import Dandelion from randomtrackingdict import RandomTrackingDict -class UploadThread(threading.Thread, StoppableThread): +class UploadThread(StoppableThread): """This is a thread that uploads the objects that the peers requested from me """ maxBufSize = 2097152 # 2MB def __init__(self): - threading.Thread.__init__(self, name="Uploader") - self.initStop() - self.name = "Uploader" + super(UploadThread, self).__init__(name="Uploader") logger.info("init upload thread") def run(self): diff --git a/src/upnp.py b/src/upnp.py index d4ffce36..fdc4bc1d 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -9,7 +9,6 @@ Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-por import httplib import socket -import threading import time import urllib2 from random import randint @@ -201,7 +200,7 @@ class Router: # pylint: disable=old-style-class return resp -class uPnPThread(threading.Thread, StoppableThread): +class uPnPThread(StoppableThread): """Start a thread to handle UPnP activity""" SSDP_ADDR = "239.255.255.250" @@ -211,7 +210,7 @@ class uPnPThread(threading.Thread, StoppableThread): SSDP_ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1" def __init__(self): - threading.Thread.__init__(self, name="uPnPThread") + super(uPnPThread, self).__init__(name="uPnPThread") try: self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') except: @@ -223,7 +222,6 @@ class uPnPThread(threading.Thread, StoppableThread): self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) self.sock.settimeout(5) self.sendSleep = 60 - self.initStop() def run(self): """Start the thread to manage UPnP activity""" From d8d76ed42dc78fbbd6c026f1cf5b9e9111bdbfa0 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 1 Aug 2019 14:49:31 +0300 Subject: [PATCH 022/306] No random.seed() in protocol.assembleVersionMessage() --- src/protocol.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/protocol.py b/src/protocol.py index c2bf3021..ab81e5e5 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -290,7 +290,6 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server= else: # no extport and not incoming over Tor payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'port')) - random.seed() if nodeid is not None: payload += nodeid[0:8] else: From 2bd75b87bd76b85579716d0f3a535bc0ab474b5a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 23 Jul 2019 18:55:14 +0300 Subject: [PATCH 023/306] Use config = BMConfigParser() in bitmessagemain.Main --- src/bitmessagemain.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 4efd0154..5639edae 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -187,8 +187,8 @@ class Main: def start(self): _fixSocket() - daemon = BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'daemon') + config = BMConfigParser() + daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') try: opts, args = getopt.getopt( @@ -216,7 +216,6 @@ class Main: # Fallback: in case when no api command was issued state.last_api_response = time.time() # Apply special settings - config = BMConfigParser() config.set( 'bitmessagesettings', 'apienabled', 'true') config.set( @@ -256,14 +255,14 @@ class Main: helper_threading.set_thread_name("PyBitmessage") - state.dandelion = BMConfigParser().safeGetInt('network', 'dandelion') + state.dandelion = config.safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, # stem objects will get stuck forever - if state.dandelion and not BMConfigParser().safeGetBoolean( + if state.dandelion and not config.safeGetBoolean( 'bitmessagesettings', 'sendoutgoingconnections'): state.dandelion = 0 - if state.testmode or BMConfigParser().safeGetBoolean( + if state.testmode or config.safeGetBoolean( 'bitmessagesettings', 'extralowdifficulty'): defaults.networkDefaultProofOfWorkNonceTrialsPerByte = int( defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) @@ -302,15 +301,15 @@ class Main: if state.enableObjProc: # SMTP delivery thread - if daemon and BMConfigParser().safeGet( - "bitmessagesettings", "smtpdeliver", '') != '': + if daemon and config.safeGet( + 'bitmessagesettings', 'smtpdeliver', '') != '': from class_smtpDeliver import smtpDeliver smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread - if daemon and BMConfigParser().safeGetBoolean( - "bitmessagesettings", "smtpd"): + if daemon and config.safeGetBoolean( + 'bitmessagesettings', 'smtpd'): from class_smtpServer import smtpServer smtpServerThread = smtpServer() smtpServerThread.start() @@ -335,7 +334,7 @@ class Main: shared.reloadBroadcastSendersForWhichImWatching() # API is also objproc dependent - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if config.safeGetBoolean('bitmessagesettings', 'apienabled'): import api # pylint: disable=relative-import singleAPIThread = api.singleAPI() # close the main program even if there are threads left @@ -348,7 +347,7 @@ class Main: asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() - for i in range(BMConfigParser().getint("threads", "receive")): + for i in range(config.getint('threads', 'receive')): receiveQueueThread = ReceiveQueueThread(i) receiveQueueThread.daemon = True receiveQueueThread.start() @@ -370,8 +369,7 @@ class Main: connectToStream(1) - if BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'upnp'): + if config.safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() @@ -387,14 +385,14 @@ class Main: import bitmessagecurses bitmessagecurses.runwrapper() elif state.kivy: - BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + config.remove_option('bitmessagesettings', 'dontconnect') from bitmessagekivy.mpybit import NavigateApp NavigateApp().run() else: import bitmessageqt bitmessageqt.run() else: - BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + config.remove_option('bitmessagesettings', 'dontconnect') if daemon: while state.shutdown == 0: From da36062f7c8023caeaab6eb782acfbcc55f6645c Mon Sep 17 00:00:00 2001 From: cis Date: Tue, 6 Aug 2019 21:43:34 +0530 Subject: [PATCH 024/306] worked on fixing search bar issue --- .../recipes/kivymd/__init__.py | 24 +--- src/bitmessagekivy/main.kv | 40 +------ src/bitmessagekivy/mpybit.py | 113 ++++-------------- src/bitmessagemain.py | 5 +- src/buildozer.spec | 53 +++++--- src/paths.py | 3 +- src/pyelliptic/openssl.py | 7 +- 7 files changed, 71 insertions(+), 174 deletions(-) diff --git a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py index b49013a7..d7e91a90 100644 --- a/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py +++ b/src/bitmessagekivy/android/python-for-android/recipes/kivymd/__init__.py @@ -10,36 +10,14 @@ from pythonforandroid.recipe import PythonRecipe class KivyMDRecipe(PythonRecipe): # This recipe installs KivyMD into the android dist from source version = 'master' - # url = 'https://gitlab.com/kivymd/KivyMD/repository/{version}/archive.zip' - url = 'https://github.com/HeaTTheatR/KivyMD/archive/master.zip' + url = 'https://github.com/surbhicis/kivymd/archive/master.zip' depends = ['kivy'] site_packages_name = 'kivymd' call_hostpython_via_targetpython = False - # patches = ['kivymd-fix-dev-compatibility.patch'] - # Made commented as use different repo for updates def should_build(self, arch): return True - # def unpack(self, arch): - # info_main('Unpacking {} for {}'.format(self.name, arch)) - # - # build_dir = self.get_build_container_dir(arch) - # - # user_dir = environ.get('P4A_{}_DIR'.format(self.name.lower())) - # - # if user_dir is not None: - # info("Installing KivyMD development version (from modded source)") - # self.clean_build() - # shprint(sh.rm, '-rf', build_dir) - # shprint(sh.mkdir, '-p', build_dir) - # shprint(sh.rmdir, build_dir) - # ensure_dir(build_dir) - # ensure_dir(build_dir + "/kivymd") - # shprint(sh.cp, user_dir + '/setup.py', self.get_build_dir(arch) + "/setup.py") - # shprint(sh.cp, '-a', user_dir + "/kivymd", self.get_build_dir(arch) + "/kivymd") - # return - def get_recipe_env(self, arch): env = super(KivyMDRecipe, self).get_recipe_env(arch) env['PYTHON_ROOT'] = self.ctx.get_python_install_dir() diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index ee44841e..4b72022b 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -174,44 +174,6 @@ NavigationLayout: background_palette: 'Primary' background_hue: '500' left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] - Button: - id: reset_navbar - size_hint_y: 0.35 - size_hint_x: 0.2 - opacity: 0 - disabled: True - pos_hint: {'x': .1, 'y': 0.3} - color: 0,0,0,1 - background_color: (0,0,0,0) - on_press:app.reset_navdrawer(self) - Image: - source: './images/left_arrow.png' - center_x: self.parent.center_x - center_y: self.parent.center_y - size: 40, 40 - TextInput: - id: search_input - hint_text: 'search' - opacity: 0 - size_hint: 1,None - height: dp(32) - disabled: True - pos_hint: {'center_x':.565,'center_y': .5} - multiline: False - padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0] - padding_x: 20,20 - Button: - id: serch_btn - size_hint_y: 0.35 - size_hint_x: 0.2 - pos_hint: {'x': .1, 'y': 0.3} - color: 0,0,0,1 - background_color: (0,0,0,0) - Image: - source: './images/search_mail.png' - center_x: self.parent.center_x - center_y: self.parent.center_y - size: 55, 55 Button: id: myButton size_hint_y: 0.35 @@ -282,7 +244,7 @@ NavigationLayout: root_layout: root MDList: id: ml - ComposerButton + ComposerButton: : name: 'sent' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 9be788dc..f8e7015a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -148,6 +148,7 @@ class Inbox(Screen): def inbox_detail(self, receivedTime, *args): """Load inbox page details.""" + remove_search_bar(self) state.detailPageType = 'inbox' state.sentMailTime = receivedTime if self.manager: @@ -155,7 +156,6 @@ class Inbox(Screen): else: src_mng_obj = self.parent.parent - hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -464,10 +464,6 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'sent' self.ids.btn.text = 'select' self.ids.ti.text = '' - self.parent.parent.parent.parent.parent\ - .ids.serch_btn.opacity = 1 - self.parent.parent.parent.parent.parent\ - .ids.serch_btn.disabled = False return None else: @@ -728,13 +724,13 @@ class Sent(Screen): def sent_detail(self, lastsenttime, *args): """Load sent mail details.""" + remove_search_bar(self) state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: src_mng_obj = self.manager else: src_mng_obj = self.parent.parent - hide_search_btn(src_mng_obj) src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -994,7 +990,7 @@ class NavigateApp(App): if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = \ 'sent' if state.detailPageType == 'sent' else 'inbox' - show_search_btn(self) + self.add_search_bar() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root from_addr = str(self.root.children[1].children[0].children[ @@ -1003,16 +999,15 @@ class NavigateApp(App): 0].children[0].children[0].ids.txt_input.text) if from_addr and to_addr: Draft().draft_msg(composer_objs) - self.root.ids.serch_btn.opacity = 1 - self.root.ids.serch_btn.disabled = False self.root.ids.scr_mngr.current = 'inbox' + self.add_search_bar() elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' elif self.root.ids.scr_mngr.current == "random": self.root.ids.scr_mngr.current = 'login' else: self.root.ids.scr_mngr.current = 'inbox' - show_search_btn(self) + self.add_search_bar() self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.restart) return True @@ -1030,8 +1025,7 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" - self.root.ids.serch_btn.opacity = 0 - self.root.ids.serch_btn.disabled = True + self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -1086,7 +1080,7 @@ class NavigateApp(App): return f_name[0][:14] + '...' if len(f_name[0]) > 15 else f_name[0] return '' - def searchQuery(self, instance): + def searchQuery(self, instance, *args): '''This method is used for showing searched mails''' state.search_screen = self.root.ids.scr_mngr.current state.searcing_text = str(instance.text).strip() @@ -1097,59 +1091,15 @@ class NavigateApp(App): self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) self.root.ids.scr_mngr.current = state.search_screen - # if self.root.ids.search_input.opacity == 0: - # self.root.ids.search_input.opacity = 1 - # self.root.ids.search_input.size_hint = 4,None - # # self.root.ids.serch_btn.opacity = 0 - # # self.root.ids.serch_btn.disabled = True - # self.root.ids.search_input.disabled = False - # self.root.ids.search_input.focus = True - # self.root.ids.toolbar.left_action_items = [] - # self.root.ids.toolbar.title = '' - # self.root.ids.myButton.opacity = 0 - # self.root.ids.myButton.disabled = True - # self.root.ids.reset_navbar.opacity = 1 - # self.root.ids.reset_navbar.disabled = False - # elif str(text): - # state.search_screen = self.root.ids.scr_mngr.current - # state.searcing_text = str(text).strip() - # if state.search_screen == 'inbox': - # self.root.ids.sc1.clear_widgets() - # self.root.ids.sc1.add_widget(Inbox()) - # else: - # self.root.ids.sc4.clear_widgets() - # self.root.ids.sc4.add_widget(Sent()) - # self.root.ids.scr_mngr.current = state.search_screen - - def reset_navdrawer(self, instance): - """Method used for reseting navigation drawer.""" - self.root.ids.search_input.text = '' - self.root.ids.search_input.opacity = 0 - self.root.ids.search_input.size_hint = 1, None - self.root.ids.search_input.disabled = True - self.root.ids.toolbar.left_action_items = [ - ['menu', lambda x: self.root.toggle_nav_drawer()]] - self.root.ids.toolbar.title = self.current_address_label() - self.root.ids.myButton.opacity = 1 - self.root.ids.myButton.disabled = False - self.root.ids.reset_navbar.opacity = 0 - self.root.ids.reset_navbar.disabled = True - state.searcing_text = '' - if state.search_screen == 'inbox': - self.root.ids.sc1.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) - else: - self.root.ids.sc4.clear_widgets() - self.root.ids.sc4.add_widget(Sent()) def check_search_screen(self, instance): - """Method shows search button on inbox and sent screen only.""" + """Method used for showing search button only on inbox or sent screen.""" if instance.text == 'Inbox' or instance.text == 'Sent': if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) - # self.root.ids.search_bar.add_widget(MDTextField(id='search_field', hint_text='Search icon', on_text=app.searchQuery(self))) - self.root.ids.serch_btn.opacity = 1 - self.root.ids.serch_btn.disabled = False + text_field = MDTextField(id='search_field', hint_text='Search icon') + text_field.bind(text = self.searchQuery) + self.root.ids.search_bar.add_widget(text_field) state.searcing_text = '' self.root.ids.sc1.clear_widgets() self.root.ids.sc4.clear_widgets() @@ -1157,10 +1107,15 @@ class NavigateApp(App): self.root.ids.sc4.add_widget(Sent()) else: self.root.ids.search_bar.clear_widgets() - self.root.ids.serch_btn.opacity = 0 - self.root.ids.serch_btn.disabled = True return + def add_search_bar(self): + """This method is used for adding search function on screen""" + if not self.root.ids.search_bar.children: + self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) + text_field = MDTextField(id='search_field', hint_text='Search icon') + text_field.bind(text = self.searchQuery) + self.root.ids.search_bar.add_widget(text_field) class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1194,8 +1149,6 @@ class GrashofPopup(Popup): queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - self.parent.children[1].ids.serch_btn.opacity = 0 - self.parent.children[1].ids.serch_btn.disabled = True self.parent.children[1].ids.scr_mngr.current = 'addressbook' def show_error_message(self): @@ -1330,8 +1283,6 @@ class MailDetail(Screen): state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) - self.parent.parent.parent.parent.parent.ids.serch_btn.opacity = 1 - self.parent.parent.parent.parent.parent.ids.serch_btn.disabled = False def inbox_reply(self): """Method used for replying inbox messages.""" @@ -1577,30 +1528,6 @@ class Draft(Screen): return -def show_search_btn(self): - """Method used to show search button.""" - self.root.ids.serch_btn.opacity = 1 - self.root.ids.serch_btn.disabled = False - - -def hide_search_btn(mgr_objs): - """Method used to hide search button and search box.""" - - mgr_objs.parent.parent.parent.ids.serch_btn.opacity = 0 - mgr_objs.parent.parent.parent.ids.serch_btn.disabled = True - mgr_objs.parent.parent.parent.ids.search_input.size_hint = 1, None - mgr_objs.parent.parent.parent.ids.search_input.disabled = True - mgr_objs.parent.parent.parent.ids.search_input.opacity = 0 - mgr_objs.parent.parent.parent.ids.toolbar.left_action_items = \ - [['menu', lambda x: mgr_objs.parent.parent.parent.toggle_nav_drawer()]] - mgr_objs.parent.parent.parent.ids.toolbar.title = \ - NavigateApp().current_address_label() - mgr_objs.parent.parent.parent.ids.myButton.opacity = 1 - mgr_objs.parent.parent.parent.ids.myButton.disabled = False - mgr_objs.parent.parent.parent.ids.reset_navbar.opacity = 0 - mgr_objs.parent.parent.parent.ids.reset_navbar.disabled = True - - class CustomSpinner(Spinner): """This class is used for setting spinner size.""" @@ -1610,3 +1537,7 @@ class CustomSpinner(Spinner): max = 2.8 self.dropdown_cls.max_height = self.height * max + max * 4 print(args) + + +def remove_search_bar(self): + self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 808b52da..a5fe29a1 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -247,7 +247,10 @@ class Main: ' \'-c\' as a commandline argument.' ) # is the application already running? If yes then exit. - shared.thisapp = singleinstance("", daemon) + try: + shared.thisapp = singleinstance("", daemon) + except Exception as e: + pass if daemon: with shared.printLock: diff --git a/src/buildozer.spec b/src/buildozer.spec index cc91e880..f6fdacde 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -1,10 +1,10 @@ [app] # (str) Title of your application -title = bluewhale +title = messageapp # (str) Package name -package.name = bluewhale +package.name = messageapp # (str) Package domain (needed for android/ios packaging) package.domain = org.test @@ -35,21 +35,29 @@ version = 0.1 # version.filename = %(source.dir)s/main.py # (list) Application requirements -# comma seperated e.g. requirements = sqlite3,kivy -requirements = python2, sqlite3, kivy, openssl, bitmsghash, libexpat, kivymd +# comma separated e.g. requirements = sqlite3,kivy +requirements = + openssl, + sqlite3, + python2, + kivy, + bitmsghash, + kivymd, + kivy-garden, + qrcode # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes # requirements.source.kivy = ../../kivy # (list) Garden requirements -#garden_requirements = +garden_requirements = qrcode # (str) Presplash of the application -presplash.filename = "images/presplas.gif" +#presplash.filename = %(source.dir)s/data/presplash.png # (str) Icon of the application -icon.filename ='images/if_android_1220385.png' +#icon.filename = %(source.dir)s/data/icon.png # (str) Supported orientation (one of landscape, portrait or all) orientation = portrait @@ -88,28 +96,28 @@ fullscreen = 0 android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE # (int) Android API to use -android.api = 19 +android.api = 27 # (int) Minimum API required -#android.minapi = 9 +android.minapi = 21 # (int) Android SDK version to use android.sdk = 20 # (str) Android NDK version to use -android.ndk = 10e +android.ndk = 17c # (bool) Use --private data storage (True) or --dir public storage (False) -#android.private_storage = True +# android.private_storage = True # (str) Android NDK directory (if empty, it will be automatically downloaded.) -android.ndk_path =/home/cis/Downloads/android-ndk-r10e +#android.ndk_path = # (str) Android SDK directory (if empty, it will be automatically downloaded.) -android.sdk_path =/home/cis/Android/Sdk +#android.sdk_path = # (str) ANT directory (if empty, it will be automatically downloaded.) -android.ant_path =/home/cis/apache-ant-1.10.5 +#android.ant_path = # (bool) If True, then skip trying to update the Android sdk # This can be useful to avoid excess Internet downloads or save time @@ -146,7 +154,10 @@ android.ant_path =/home/cis/apache-ant-1.10.5 # bootstrap) #android.gradle_dependencies = -# (str) python-for-android branch to use, defaults to master +# (list) Java classes to add as activities to the manifest. +#android.add_activites = com.example.ExampleActivity + +# (str) python-for-android branch to use, defaults to stable p4a.branch = master # (str) OUYA Console category. Should be one of GAME or APP @@ -159,7 +170,10 @@ p4a.branch = master # (str) XML file to include as an intent filters in tag #android.manifest.intent_filters = -# (list) Android additionnal libraries to copy into libs/armeabi +# (str) launchMode to set for the main activity +#android.manifest.launch_mode = standard + +# (list) Android additional libraries to copy into libs/armeabi #android.add_libs_armeabi = libs/android/*.so #android.add_libs_armeabi_v7a = libs/android-v7/*.so #android.add_libs_x86 = libs/android-x86/*.so @@ -193,7 +207,7 @@ android.arch = armeabi-v7a #p4a.source_dir = # (str) The directory in which python-for-android should look for your own build recipes (if any) -p4a.local_recipes =/home/cis/Desktop/Mobileandroid/peter_android/PyBitmessage/src/bitmessagekivy/android/python-for-android/recipes/ +p4a.local_recipes = /home/cis/navjotrepo/PyBitmessage/src/bitmessagekivy/android/python-for-android/recipes/ # (str) Filename to the hook for p4a #p4a.hook = @@ -201,6 +215,9 @@ p4a.local_recipes =/home/cis/Desktop/Mobileandroid/peter_android/PyBitmessage/sr # (str) Bootstrap to use for android builds # p4a.bootstrap = sdl2 +# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) +#p4a.port = + # # iOS specific @@ -267,4 +284,4 @@ warn_on_root = 1 # # Then, invoke the command line with the "demo" profile: # -#buildozer --profile demo android debug +#buildozer --profile demo android debug \ No newline at end of file diff --git a/src/paths.py b/src/paths.py index 63e92704..110a32bd 100644 --- a/src/paths.py +++ b/src/paths.py @@ -43,7 +43,8 @@ def lookupAppdataFolder(): sys.exit() elif platform == 'android': # dataFolder = path.join(os.path.dirname(os.path.abspath("__file__")), "PyBitmessage") + '/' - dataFolder = path.join('/sdcard/', 'DCIM/', APPNAME) + '/' + dataFolder = path.join(os.environ['ANDROID_PRIVATE'] + '/', APPNAME) + '/' + # dataFolder = path.join('/sdcard/', 'DCIM/', APPNAME) + '/' elif 'win32' in sys.platform or 'win64' in sys.platform: dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 97510cc1..4c8c4973 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -534,6 +534,8 @@ def loadOpenSSL(): elif platform == "android": libdir.append('libcrypto1.0.2p.so') libdir.append('libssl1.0.2p.so') + libdir.append('libcrypto1.1.so') + libdir.append('libssl1.1.so') else: libdir.append('libcrypto.so') @@ -541,7 +543,10 @@ def loadOpenSSL(): libdir.append('libcrypto.so.1.0.0') libdir.append('libssl.so.1.0.0') if 'linux' in sys.platform or 'darwin' in sys.platform or 'bsd' in sys.platform: - libdir.append(find_library('ssl')) + try: + libdir.append(find_library('ssl')) + except OSError: + pass elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append(find_library('libeay32')) for library in libdir: From 76d8f51a37c4d6063f2a9d06a953a8bcedb802e7 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 7 Aug 2019 13:42:41 +0530 Subject: [PATCH 025/306] Flakes8 and Autopep8 after pull --- src/bitmessagekivy/mpybit.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index f00ef6c4..26cb4d42 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1039,6 +1039,7 @@ class NavigateApp(App): shutdown.doCleanShutdown() def mail_count(self, text): + """Counting Mail numbers.""" if state.association == '': if BMConfigParser().addresses(): state.association = BMConfigParser().addresses()[0] @@ -1081,7 +1082,7 @@ class NavigateApp(App): return '' def searchQuery(self, instance, *args): - '''This method is used for showing searched mails''' + """Method used for showing searched mails.""" state.search_screen = self.root.ids.scr_mngr.current state.searcing_text = str(instance.text).strip() if state.search_screen == 'inbox': @@ -1093,12 +1094,14 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = state.search_screen def check_search_screen(self, instance): - """Method used for showing search button only on inbox or sent screen.""" + """Method show search button only on inbox or sent screen.""" if instance.text == 'Inbox' or instance.text == 'Sent': if not self.root.ids.search_bar.children: - self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) - text_field = MDTextField(id='search_field', hint_text='Search icon') - text_field.bind(text = self.searchQuery) + self.root.ids.search_bar.add_widget( + MDIconButton(icon='magnify')) + text_field = MDTextField( + id='search_field', hint_text='Search icon') + text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) state.searcing_text = '' self.root.ids.sc1.clear_widgets() @@ -1110,13 +1113,15 @@ class NavigateApp(App): return def add_search_bar(self): - """This method is used for adding search function on screen""" + """Method used for adding search function on screen.""" if not self.root.ids.search_bar.children: - self.root.ids.search_bar.add_widget(MDIconButton(icon = 'magnify')) - text_field = MDTextField(id='search_field', hint_text='Search icon') - text_field.bind(text = self.searchQuery) + self.root.ids.search_bar.add_widget(MDIconButton(icon='magnify')) + text_field = MDTextField( + id='search_field', hint_text='Search icon') + text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) + class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1540,4 +1545,5 @@ class CustomSpinner(Spinner): def remove_search_bar(self): + """Remove search bar.""" self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() From d5f99cc20959bfd49bb268e928b7f919c0185eaa Mon Sep 17 00:00:00 2001 From: cis Date: Wed, 7 Aug 2019 21:09:46 +0530 Subject: [PATCH 026/306] wokred on addressbook search functionality implementation --- .gitignore | 2 ++ src/bitmessagekivy/kivy_helper_search.py | 22 ++++++++++------- src/bitmessagekivy/mpybit.py | 30 ++++++++++++++++-------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 2bcb5340..90a31335 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ dist docs/_*/* docs/autodoc/ pyan/ +.buildozer/ +bin/ \ No newline at end of file diff --git a/src/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index eae6be01..39d4ab3e 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -11,9 +11,12 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w sqlStatementBase = ''' SELECT toaddress, fromaddress, subject, message, status, ackdata, lastactiontime FROM sent ''' + elif folder == "addressbook": + sqlStatementBase = '''SELECT label, address From addressbook ''' else: sqlStatementBase = '''SELECT folder, msgid, toaddress, message, fromaddress, subject, received, read FROM inbox ''' + sqlStatementParts = [] sqlArguments = [] if account is not None: @@ -24,15 +27,16 @@ def search_sql(xAddress="toaddress", account=None, folder="inbox", where=None, w else: sqlStatementParts.append(xAddress + " = ? ") sqlArguments.append(account) - if folder is not None: - if folder == "new": - folder = "inbox" - unreadOnly = True - sqlStatementParts.append("folder = ? ") - sqlArguments.append(folder) - else: - sqlStatementParts.append("folder != ?") - sqlArguments.append("trash") + if folder is not "addressbook": + if folder is not None: + if folder == "new": + folder = "inbox" + unreadOnly = True + sqlStatementParts.append("folder = ? ") + sqlArguments.append(folder) + else: + sqlStatementParts.append("folder != ?") + sqlArguments.append("trash") if what is not None: for colmns in where: if len(where) > 1: diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 26cb4d42..53f37dbb 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -290,10 +290,20 @@ class AddressBook(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method inbox accounts.""" - data = sqlQuery("SELECT label, address from addressbook") - if data: - for item in data: + """Clock Schdule for method AddressBook""" + self.loadAddresslist(None, 'All', '') + print(dt) + + def loadAddresslist(self, account, where="", what=""): + """Clock Schdule for method AddressBook""" + if state.searcing_text: + where = ['label', 'address'] + what = state.searcing_text + xAddress = '' + queryreturn = kivy_helper_search.search_sql( + xAddress, account, "addressbook", where, what, False) + if queryreturn: + for item in queryreturn: meny = TwoLineAvatarIconListItem( text=item[0], secondary_text=item[1], @@ -1088,6 +1098,9 @@ class NavigateApp(App): if state.search_screen == 'inbox': self.root.ids.sc1.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) + elif state.search_screen == 'addressbook': + self.root.ids.sc11.clear_widgets() + self.root.ids.sc11.add_widget(AddressBook()) else: self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) @@ -1095,7 +1108,7 @@ class NavigateApp(App): def check_search_screen(self, instance): """Method show search button only on inbox or sent screen.""" - if instance.text == 'Inbox' or instance.text == 'Sent': + if instance.text in ['Inbox', 'Sent', 'Address Book']: if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget( MDIconButton(icon='magnify')) @@ -1103,13 +1116,10 @@ class NavigateApp(App): id='search_field', hint_text='Search icon') text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) - state.searcing_text = '' - self.root.ids.sc1.clear_widgets() - self.root.ids.sc4.clear_widgets() - self.root.ids.sc1.add_widget(Inbox()) - self.root.ids.sc4.add_widget(Sent()) + self.root.ids.search_bar.children[0].text = '' else: self.root.ids.search_bar.clear_widgets() + state.searcing_text = '' return def add_search_bar(self): From fb44c8aaf711c7b94518e8a9de1d2a51d2ee9265 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 8 Aug 2019 13:03:17 +0530 Subject: [PATCH 027/306] Pychecker Fixes --- src/bitmessagekivy/mpybit.py | 76 +++++++++++++----------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 53f37dbb..701c3b0b 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -104,12 +104,11 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) + img_latter = item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item[ + 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') - else '!'))) + source='./images/text_images/{}.png'.format(img_latter))) meny.bind(on_press=partial( self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') @@ -233,12 +232,11 @@ class MyAddress(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) + img_latter = item['text'][0].upper() if ( + item['text'][0].upper() >= 'A' and item['text'][ + 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item['text'][0].upper() if ( - item['text'][0].upper() >= 'A' and item['text'][ - 0].upper() <= 'Z') - else '!'))) + source='./images/text_images/{}.png'.format(img_latter))) meny.bind(on_press=partial( self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) @@ -290,12 +288,12 @@ class AddressBook(Screen): Clock.schedule_once(self.init_ui, 0) def init_ui(self, dt=0): - """Clock Schdule for method AddressBook""" + """Clock Schdule for method AddressBook.""" self.loadAddresslist(None, 'All', '') print(dt) def loadAddresslist(self, account, where="", what=""): - """Clock Schdule for method AddressBook""" + """Clock Schdule for method AddressBook.""" if state.searcing_text: where = ['label', 'address'] what = state.searcing_text @@ -309,11 +307,11 @@ class AddressBook(Screen): secondary_text=item[1], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) + img_latter = item[0][0].upper() if ( + item[0][0].upper() >= 'A' and item[0][ + 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item[0][0].upper() if ( - item[0][0].upper() >= 'A' and item[0][ - 0].upper() <= 'Z') else '!'))) + source='./images/text_images/{}.png'.format(img_latter))) meny.bind(on_press=partial( self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') @@ -609,7 +607,6 @@ class Random(Screen): def generateaddress(self): """Method for Address Generator.""" - import queues streamNumberForAddress = 1 label = self.ids.label.text eighteenByteRipe = False @@ -690,12 +687,11 @@ class Sent(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) + img_latter = item['secondary_text'][0].upper() if ( + item['secondary_text'][0].upper() >= 'A' and item[ + 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') - else '!'))) + source='./images/text_images/{}.png'.format(img_latter))) meny.bind(on_press=partial( self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') @@ -814,10 +810,11 @@ class Trash(Screen): secondary_text=item[2], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) + img_latter = item[2][0].upper() if ( + item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( - item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!'))) + source='./images/text_images/{}.png'.format(img_latter))) self.ids.ml.add_widget(meny) @@ -894,17 +891,6 @@ class NavigateApp(App): kivyuisignaler.release() super(NavigateApp, self).run() - def show_address_success(self): - """Showing the succesfull address.""" - content = MDLabel(font_style='Body1', - theme_text_color='Secondary', - text="Successfully Saved your contact address. " - "That's pretty awesome right!", - size_hint_y=None, - valign='top') - content.bind(texture_size=content.setter('size')) - self.dialog.open() - @staticmethod def showmeaddresses(name="text"): """Show the addresses in spinner to make as dropdown.""" @@ -961,14 +947,6 @@ class NavigateApp(App): msg_counter_objs.trash_cnt.badge_text = state.trash_count msg_counter_objs.draft_cnt.badge_text = state.draft_count - def getInboxMessageDetail(self, instance): - """Getting message detail after selected message description.""" - try: - self.root.ids._mngr.current = 'page' - except AttributeError: - self.parent.manager.current = 'page' - print('Message Clicked {}'.format(instance)) - @staticmethod def getCurrentAccount(): """It uses to get current account label.""" @@ -1108,7 +1086,7 @@ class NavigateApp(App): def check_search_screen(self, instance): """Method show search button only on inbox or sent screen.""" - if instance.text in ['Inbox', 'Sent', 'Address Book']: + if instance.text in ['Inbox', 'Sent', 'Address Book']: if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget( MDIconButton(icon='magnify')) @@ -1550,10 +1528,10 @@ class CustomSpinner(Spinner): def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) - max = 2.8 - self.dropdown_cls.max_height = self.height * max + max * 4 + max_value = 2.8 + self.dropdown_cls.max_height = self.height * max_value + max_value * 4 -def remove_search_bar(self): +def remove_search_bar(obj): """Remove search bar.""" - self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() + obj.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() From ec11632297d0969ee9fab7da3c1cb96f1d85d618 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 23 Jul 2019 18:57:19 +0300 Subject: [PATCH 028/306] Introduce pluggable proxy configurators --- setup.py | 4 ++++ src/bitmessagemain.py | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/setup.py b/setup.py index e3f97bac..3a9c7a3c 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ EXTRAS_REQUIRE = { 'prctl': ['python_prctl'], # Named threads 'qrcode': ['qrcode'], 'sound;platform_system=="Windows"': ['winsound'], + 'tor': ['stem'], 'docs': [ 'sphinx', # fab build_docs 'graphviz', # fab build_docs @@ -147,6 +148,9 @@ if __name__ == "__main__": 'libmessaging =' 'pybitmessage.plugins.indicator_libmessaging [gir]' ], + 'bitmessage.proxyconfig': [ + 'stem = pybitmessage.plugins.proxyconfig_stem [tor]' + ], # 'console_scripts': [ # 'pybitmessage = pybitmessage.bitmessagemain:main' # ] diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 5639edae..90e15c52 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -184,6 +184,27 @@ def signal_handler(signum, frame): class Main: + @staticmethod + def start_proxyconfig(config): + """Check socksproxytype and start any proxy configuration plugin""" + proxy_type = config.safeGet('bitmessagesettings', 'socksproxytype') + if proxy_type not in ('none', 'SOCKS4a', 'SOCKS5'): + # pylint: disable=relative-import + from plugins.plugin import get_plugin + try: + proxyconfig_start = time.time() + get_plugin('proxyconfig', name=proxy_type)(config) + except TypeError: + logger.error( + 'Failed to run proxy config plugin %s', + proxy_type, exc_info=True) + shutdown.doCleanShutdown() + sys.exit(2) + else: + logger.info( + 'Started proxy config plugin %s in %s sec', + proxy_type, time.time() - proxyconfig_start) + def start(self): _fixSocket() @@ -343,6 +364,7 @@ class Main: # start network components if networking is enabled if state.enableNetwork: + self.start_proxyconfig(config) BMConnectionPool() asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True From 53d77ce9116d2cbe1f79d63bd5c09b70ac09c60c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 23 Jul 2019 18:57:46 +0300 Subject: [PATCH 029/306] Dumb tor configurator using stem --- src/plugins/proxyconfig_stem.py | 111 ++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/plugins/proxyconfig_stem.py diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py new file mode 100644 index 00000000..567d8253 --- /dev/null +++ b/src/plugins/proxyconfig_stem.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +import os +import logging +import random # noseq +import tempfile + +import stem +import stem.control +import stem.process + + +class DebugLogger(object): + """Safe logger wrapper for tor and plugin's logs""" + # pylint: disable=too-few-public-methods + def __init__(self): + self._logger = logging.getLogger(__name__.split('.', 1)[0]) + self._levels = { + 'err': 40, + 'warn': 30, + 'notice': 20 + } + + def __call__(self, line): + try: + level, line = line.split('[', 1)[1].split(']') + except IndexError: + # Plugin's debug or unexpected log line from tor + self._logger.debug(line) + else: + self._logger.log(self._levels.get(level, 10), '(tor)' + line) + + +def connect_plugin(config): + """Run stem proxy configurator""" + logwrite = DebugLogger() + if config.safeGet('bitmessagesettings', 'sockshostname') not in ( + 'localhost', '127.0.0.1', '' + ): + # remote proxy is choosen for outbound connections, + # nothing to do here, but need to set socksproxytype to SOCKS5! + logwrite( + 'sockshostname is set to remote address,' + ' aborting stem proxy configuration') + return + + datadir = tempfile.mkdtemp() + control_socket = os.path.join(datadir, 'control') + tor_config = { + 'SocksPort': '9050', + # 'DataDirectory': datadir, # had an exception with control socket + 'ControlSocket': control_socket + } + port = config.safeGet('bitmessagesettings', 'socksport', '9050') + for attempt in range(50): + if attempt > 0: + port = random.randint(32767, 65535) + tor_config['SocksPort'] = str(port) + # It's recommended to use separate tor instance for hidden services. + # So if there is a system wide tor, use it for outbound connections. + try: + stem.process.launch_tor_with_config( + tor_config, take_ownership=True, init_msg_handler=logwrite) + except OSError: + continue + else: + logwrite('Started tor on port %s' % port) + break + + if config.safeGetBoolean('bitmessagesettings', 'sockslisten'): + # need a hidden service for inbound connections + try: + controller = stem.control.Controller.from_socket_file( + control_socket) + controller.authenticate() + except stem.SocketError: + # something goes wrong way + logwrite('Failed to instantiate or authenticate on controller') + return + + onionhostname = config.safeGet('bitmessagesettings', 'onionhostname') + onionkey = config.safeGet(onionhostname, 'privsigningkey') + if onionhostname and not onionkey: + logwrite('The hidden service found in config ): %s' % onionhostname) + onionkeytype = config.safeGet(onionhostname, 'keytype') + + response = controller.create_ephemeral_hidden_service( + config.safeGetInt('bitmessagesettings', 'onionport', 8444), + key_type=(onionkeytype or 'NEW'), + key_content=(onionkey or 'BEST') + ) + + if not response.is_ok(): + logwrite('Bad response from controller ):') + return + + if not onionkey: + if not onionhostname: + onionhostname = response.service_id + '.onion' + config.set( + 'bitmessagesettings', 'onionhostname', onionhostname) + else: + onionhostname = response.service_id + '.onion' + logwrite('Started hidden service %s' % onionhostname) + config.add_section(onionhostname) + config.set( + onionhostname, 'privsigningkey', response.private_key) + config.set( + onionhostname, 'keytype', response.private_key_type) + config.save() + config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5') From 97366ede73d1d65c0baeb8ed1e681d91629e5011 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 28 Jul 2019 13:16:34 +0300 Subject: [PATCH 030/306] Do not save hidden service parameters if onionhostname is set --- src/plugins/proxyconfig_stem.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py index 567d8253..75605c07 100644 --- a/src/plugins/proxyconfig_stem.py +++ b/src/plugins/proxyconfig_stem.py @@ -87,7 +87,7 @@ def connect_plugin(config): response = controller.create_ephemeral_hidden_service( config.safeGetInt('bitmessagesettings', 'onionport', 8444), key_type=(onionkeytype or 'NEW'), - key_content=(onionkey or 'BEST') + key_content=(onionkey or onionhostname and 'ED25519-V3' or 'BEST') ) if not response.is_ok(): @@ -95,17 +95,16 @@ def connect_plugin(config): return if not onionkey: + logwrite('Started hidden service %s.onion' % response.service_id) + # only save new service keys if onionhostname was not set previously if not onionhostname: onionhostname = response.service_id + '.onion' config.set( 'bitmessagesettings', 'onionhostname', onionhostname) - else: - onionhostname = response.service_id + '.onion' - logwrite('Started hidden service %s' % onionhostname) - config.add_section(onionhostname) - config.set( - onionhostname, 'privsigningkey', response.private_key) - config.set( - onionhostname, 'keytype', response.private_key_type) - config.save() + config.add_section(onionhostname) + config.set( + onionhostname, 'privsigningkey', response.private_key) + config.set( + onionhostname, 'keytype', response.private_key_type) + config.save() config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5') From f5d0b3dd59ba69744ec8b3970aaf39d494cfa4e9 Mon Sep 17 00:00:00 2001 From: cis Date: Thu, 8 Aug 2019 21:50:58 +0530 Subject: [PATCH 031/306] worked on implementing search for myaddress and fixed issues --- src/bitmessagekivy/mpybit.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 53f37dbb..dfc600a2 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -222,8 +222,13 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" if BMConfigParser().addresses() or state.kivyapp.variable_1: + addresses_list = state.kivyapp.variable_1 + if state.searcing_text: + filtered_list = filter(lambda addr: self.filter_address(addr), BMConfigParser().addresses()) + addresses_list = filtered_list + data = [] - for address in state.kivyapp.variable_1: + for address in addresses_list: data.append({ 'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) @@ -253,6 +258,7 @@ class MyAddress(Screen): valign='top') self.ids.ml.add_widget(content) try: + self.manager.parent.parent.parent.ids.search_bar.clear_widgets() self.manager.current = 'login' except Exception as e: pass @@ -280,6 +286,13 @@ class MyAddress(Screen): Clock.schedule_once(refresh_callback, 1) + def filter_address(self, address): + '''This method will filter the my address list data''' + # if (state.searcing_text).lower() in BMConfigParser().get(address, 'label') or (state.searcing_text).lower() in address: + if filter(lambda x: (state.searcing_text).lower() in x, [BMConfigParser().get(address, 'label').lower(), address.lower()]): + return True + return False + class AddressBook(Screen): """AddressBook Screen uses screen to show widgets of screens.""" @@ -471,7 +484,7 @@ class DropDownWidget(BoxLayout): self.ids.ti.text = '' self.ids.subject.text = '' self.ids.txt_input.text = '' - self.parent.parent.current = 'sent' + self.parent.parent.current = 'inbox' self.ids.btn.text = 'select' self.ids.ti.text = '' @@ -944,11 +957,11 @@ class NavigateApp(App): folder = 'sent' ;".format(state.association))[0][0]) state.inbox_count = str( sqlQuery( - "SELECT COUNT(*) FROM inbox WHERE fromaddress = '{}' and \ + "SELECT COUNT(*) FROM inbox WHERE toaddress = '{}' and \ folder = 'inbox' ;".format(state.association))[0][0]) state.trash_count = str(sqlQuery("SELECT (SELECT count(*) FROM sent \ where fromaddress = '{0}' and folder = 'trash' ) \ - +(SELECT count(*) FROM inbox where fromaddress = '{0}' and \ + +(SELECT count(*) FROM inbox where toaddress = '{0}' and \ folder = 'trash') AS SumCount".format(state.association))[0][0]) state.draft_count = str( sqlQuery( @@ -1061,7 +1074,7 @@ class NavigateApp(App): return state.sent_count elif text == 'Inbox': state.inbox_count = str(sqlQuery( - "SELECT COUNT(*) FROM {0} WHERE fromaddress = '{1}' and \ + "SELECT COUNT(*) FROM {0} WHERE toaddress = '{1}' and \ folder = '{0}' ;".format( text.lower(), state.association))[0][0]) return state.inbox_count @@ -1069,7 +1082,7 @@ class NavigateApp(App): state.trash_count = str(sqlQuery( "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' \ and folder = 'trash' )+(SELECT count(*) FROM inbox where \ - fromaddress = '{0}' and folder = 'trash') AS SumCount".format( + toaddress = '{0}' and folder = 'trash') AS SumCount".format( state.association))[0][0]) return state.trash_count elif text == 'Draft': @@ -1101,6 +1114,9 @@ class NavigateApp(App): elif state.search_screen == 'addressbook': self.root.ids.sc11.clear_widgets() self.root.ids.sc11.add_widget(AddressBook()) + elif state.search_screen == 'myaddress': + self.root.ids.sc10.clear_widgets() + self.root.ids.sc10.add_widget(MyAddress()) else: self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) @@ -1108,7 +1124,7 @@ class NavigateApp(App): def check_search_screen(self, instance): """Method show search button only on inbox or sent screen.""" - if instance.text in ['Inbox', 'Sent', 'Address Book']: + if instance.text in ['Inbox', 'Sent', 'Address Book', 'My Addresses']: if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget( MDIconButton(icon='magnify')) From 8758c4fc9be0f8cdf0af77137f2cf961ead257c0 Mon Sep 17 00:00:00 2001 From: Navjot Date: Tue, 13 Aug 2019 12:58:15 +0530 Subject: [PATCH 032/306] wokred on implementing toast functionality and fixed issues --- src/bitmessagekivy/main.kv | 7 ++-- src/bitmessagekivy/mpybit.py | 68 +++++++++++++++++++++++++++--------- src/buildozer.spec | 6 ++-- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 4b72022b..1188ecb4 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -197,7 +197,7 @@ NavigationLayout: MDTextField: id: search_field - hint_text: 'Search icon' + hint_text: 'Search' on_text: app.searchQuery(self) ScreenManager: id: scr_mngr @@ -369,7 +369,7 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: root.reset_composer() MDLabel: font_style: 'Title' text: 'reset' @@ -667,6 +667,7 @@ NavigationLayout: size_hint: 1.5, None height: dp(40) on_press: root.dismiss() + on_press: root.close_pop() MDLabel: font_style: 'Title' text: 'Cancel' @@ -914,6 +915,7 @@ NavigationLayout: size_hint: 1.5, None height: dp(40) on_press: root.dismiss() + on_press: root.close_pop() MDLabel: font_style: 'Title' text: 'Cancel' @@ -990,6 +992,7 @@ NavigationLayout: size_hint: 1.5, None height: dp(40) on_press: root.dismiss() + on_press: root.close_pop() MDLabel: font_style: 'Title' text: 'Cancel' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index dfc600a2..319f3260 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -48,6 +48,12 @@ from kivy.uix.spinner import Spinner from kivymd.textfields import MDTextField +def toast(text): + if platform == 'linux': + from kivymd.toast.kivytoast import toast + toast(text) + return + class Navigatorss(MDNavigationDrawer): """Navigators class contains image, title and logo.""" @@ -139,7 +145,7 @@ class Inbox(Screen): content = MDLabel( font_style='Body1', theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", + text="No message found!" if state.searcing_text else "yet no message for this account!!!!!!!!!!!!!", halign='center', bold=True, size_hint_y=None, @@ -166,7 +172,7 @@ class Inbox(Screen): "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( data_index)) msg_count_objs = \ - self.parent.parent.parent.parent.children[2].children[0].ids + self.parent.parent.parent.parent.parent.children[2].children[0].ids if int(state.inbox_count) > 0: msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) @@ -175,6 +181,7 @@ class Inbox(Screen): state.inbox_count = str(int(state.inbox_count) - 1) state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') self.update_trash() def archive(self, data_index, instance, *args): @@ -221,12 +228,11 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or state.kivyapp.variable_1: - addresses_list = state.kivyapp.variable_1 - if state.searcing_text: - filtered_list = filter(lambda addr: self.filter_address(addr), BMConfigParser().addresses()) - addresses_list = filtered_list - + addresses_list = state.kivyapp.variable_1 + if state.searcing_text: + filtered_list = filter(lambda addr: self.filter_address(addr), BMConfigParser().addresses()) + addresses_list = filtered_list + if addresses_list: data = [] for address in addresses_list: data.append({ @@ -251,7 +257,7 @@ class MyAddress(Screen): content = MDLabel( font_style='Body1', theme_text_color='Primary', - text="yet no address is created by user!!!!!!!!!!!!!", + text="No address found!" if state.searcing_text else "yet no address is created by user!!!!!!!!!!!!!", halign='center', bold=True, size_hint_y=None, @@ -349,7 +355,7 @@ class AddressBook(Screen): else: content = MDLabel(font_style='Body1', theme_text_color='Primary', - text="No Contact Found yet...... ", + text="No contact found!" if state.searcing_text else "No contact found yet...... ", halign='center', bold=True, size_hint_y=None, @@ -487,7 +493,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'inbox' self.ids.btn.text = 'select' self.ids.ti.text = '' - + toast('send') return None else: msg = 'Enter a valid recipients address' @@ -523,6 +529,13 @@ class DropDownWidget(BoxLayout): self.but.bind(on_press=self.main_pop.dismiss) self.main_pop.open() + def reset_composer(self): + self.ids.ti.text = '' + self.ids.btn.text = 'Select' + self.ids.txt_input.text = '' + self.ids.subject.text = '' + self.ids.body.text = '' + class MyTextInput(TextInput): """Takes the text input in the field.""" @@ -642,6 +655,7 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.disabled = False self.parent.parent.parent.parent.ids.sc10.clear_widgets() self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + toast('New address created') class AddressSuccessful(Screen): @@ -738,7 +752,7 @@ class Sent(Screen): content = MDLabel( font_style='Body1', theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", + text="No message found!" if state.searcing_text else "yet no message for this account!!!!!!!!!!!!!", halign='center', bold=True, size_hint_y=None, @@ -777,6 +791,7 @@ class Sent(Screen): "UPDATE sent SET folder = 'trash' \ WHERE lastactiontime = {};".format(data_index)) self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') self.update_trash() def archive(self, data_index, instance, *args): @@ -1048,6 +1063,8 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" + # self.root.ids.toolbar.left_action_items = '' + # self.root.ids.myButton.opacity = 0 self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' @@ -1129,7 +1146,7 @@ class NavigateApp(App): self.root.ids.search_bar.add_widget( MDIconButton(icon='magnify')) text_field = MDTextField( - id='search_field', hint_text='Search icon') + id='search_field', hint_text='Search') text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) self.root.ids.search_bar.children[0].text = '' @@ -1143,7 +1160,7 @@ class NavigateApp(App): if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget(MDIconButton(icon='magnify')) text_field = MDTextField( - id='search_field', hint_text='Search icon') + id='search_field', hint_text='Search') text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) @@ -1175,12 +1192,14 @@ class GrashofPopup(Popup): label = self.ids.label.text address = self.ids.address.text - if label and address: + stored_address = [addr[1] for addr in kivy_helper_search.search_sql(folder = "addressbook")] + if label and address and address not in stored_address: state.navinstance = self.parent.children[1] queues.UISignalQueue.put(('rerenderAddressBook', '')) self.dismiss() sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) self.parent.children[1].ids.scr_mngr.current = 'addressbook' + toast('Saved') def show_error_message(self): """Showing error message.""" @@ -1201,6 +1220,8 @@ class GrashofPopup(Popup): action=lambda *x: self.dialog.dismiss()) self.dialog.open() + def close_pop(self): + toast('Canceled') class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" @@ -1314,6 +1335,7 @@ class MailDetail(Screen): state.trash_count = str(int(state.trash_count) + 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + toast('Deleted') def inbox_reply(self): """Method used for replying inbox messages.""" @@ -1364,6 +1386,9 @@ class MyaddDetailPopup(Popup): window_obj.scr_mngr.current = 'create' self.dismiss() + def close_pop(self): + toast('Canceled') + class AddbookDetailPopup(Popup): """AddbookDetailPopup pop is used for showing my address detail.""" @@ -1394,6 +1419,7 @@ class AddbookDetailPopup(Popup): self.parent.children[1].ids.sc11.clear_widgets() self.parent.children[1].ids.sc11.add_widget(AddressBook()) self.dismiss() + toast('Saved') def send_message_to(self): """Method used to fill to_address of composer autofield.""" @@ -1406,16 +1432,21 @@ class AddbookDetailPopup(Popup): window_obj.scr_mngr.current = 'create' self.dismiss() + def close_pop(self): + toast('Canceled') + class ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" def qrdisplay(self): """Method used for showing QR Code.""" + self.manager.parent.parent.parent.ids.search_bar.clear_widgets() self.ids.qr.clear_widgets() from kivy.garden.qrcode import QRCodeWidget self.ids.qr.add_widget(QRCodeWidget( data=self.manager.get_parent_window().children[0].address)) + toast('Show QR code') class Draft(Screen): @@ -1511,6 +1542,7 @@ class Draft(Screen): int(state.draft_count) - 1) state.draft_count = str(int(state.draft_count) - 1) self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') def draft_msg(self, src_object): """Method used for saving draft mails.""" @@ -1557,6 +1589,7 @@ class Draft(Screen): state.draft_count = str(int(state.draft_count) + 1) src_object.ids.sc16.clear_widgets() src_object.ids.sc16.add_widget(Draft()) + toast('Save draft') return @@ -1572,4 +1605,7 @@ class CustomSpinner(Spinner): def remove_search_bar(self): """Remove search bar.""" - self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() + try: + self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() + except Exception as e: + self.parent.parent.parent.parent.ids.search_bar.clear_widgets() diff --git a/src/buildozer.spec b/src/buildozer.spec index f6fdacde..82858554 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -1,10 +1,10 @@ [app] # (str) Title of your application -title = messageapp +title = bitapp # (str) Package name -package.name = messageapp +package.name = bitapp # (str) Package domain (needed for android/ios packaging) package.domain = org.test @@ -284,4 +284,4 @@ warn_on_root = 1 # # Then, invoke the command line with the "demo" profile: # -#buildozer --profile demo android debug \ No newline at end of file +#buildozer --profile demo android debug From e8bd427b9f1507f33e4797e3c1b07a81817605de Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 16 Nov 2018 16:58:12 +0200 Subject: [PATCH 033/306] flake8 for bitmessageqt.safehtmlparser (with docstrings from #1368) --- src/bitmessageqt/safehtmlparser.py | 102 ++++++++++++++++++----------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index d1d7910c..edacd4bb 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -1,51 +1,73 @@ -from HTMLParser import HTMLParser +"""Subclass of HTMLParser.HTMLParser for MessageView widget""" + import inspect import re -from urllib import quote, quote_plus +from HTMLParser import HTMLParser + +from urllib import quote_plus from urlparse import urlparse + class SafeHTMLParser(HTMLParser): + """HTML parser with sanitisation""" # from html5lib.sanitiser - acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', - 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', - 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', - 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', - 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', - 'figcaption', 'figure', 'footer', 'font', 'header', 'h1', - 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', - 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter', - 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option', - 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', - 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', - 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', - 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] - replaces_pre = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"]] - replaces_post = [["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] - src_schemes = [ "data" ] - #uriregex1 = re.compile(r'(?i)\b((?:(https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?]))') - uriregex1 = re.compile(r'((https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)') + acceptable_elements = ( + 'a', 'abbr', 'acronym', 'address', 'area', + 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', + 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', + 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', + 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', + 'figcaption', 'figure', 'footer', 'font', 'header', 'h1', + 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', + 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter', + 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option', + 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', + 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', + 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', + 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video' + ) + replaces_pre = ( + ("&", "&"), ("\"", """), ("<", "<"), (">", ">")) + replaces_post = ( + ("\n", "
"), ("\t", "    "), + (" ", "  "), (" ", "  "), ("
", "
 ")) + src_schemes = ["data"] + # uriregex1 = re.compile( + # r'(?i)\b((?:(https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])' + # r'|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)' + # r'(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))' + # r'+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?]))') + uriregex1 = re.compile( + r'((https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])' + r'(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)' + ) uriregex2 = re.compile(r'
1 and text[0] == " ": text = " " + text[1:] return text def __init__(self, *args, **kwargs): HTMLParser.__init__(self, *args, **kwargs) + self.reset() self.reset_safe() - + def reset_safe(self): + """Reset runtime variables specific to this class""" self.elements = set() self.raw = u"" self.sanitised = u"" @@ -53,8 +75,9 @@ class SafeHTMLParser(HTMLParser): self.allow_picture = False self.allow_external_src = False - def add_if_acceptable(self, tag, attrs = None): - if tag not in SafeHTMLParser.acceptable_elements: + def add_if_acceptable(self, tag, attrs=None): + """Add tag if it passes sanitisation""" + if tag not in self.acceptable_elements: return self.sanitised += "<" if inspect.stack()[1][3] == "handle_endtag": @@ -66,7 +89,7 @@ class SafeHTMLParser(HTMLParser): val = "" elif attr == "src" and not self.allow_external_src: url = urlparse(val) - if url.scheme not in SafeHTMLParser.src_schemes: + if url.scheme not in self.src_schemes: val = "" self.sanitised += " " + quote_plus(attr) if not (val is None): @@ -74,26 +97,26 @@ class SafeHTMLParser(HTMLParser): if inspect.stack()[1][3] == "handle_startendtag": self.sanitised += "/" self.sanitised += ">" - + def handle_starttag(self, tag, attrs): - if tag in SafeHTMLParser.acceptable_elements: + if tag in self.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) def handle_endtag(self, tag): self.add_if_acceptable(tag) - + def handle_startendtag(self, tag, attrs): - if tag in SafeHTMLParser.acceptable_elements: + if tag in self.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) - + def handle_data(self, data): self.sanitised += data - + def handle_charref(self, name): self.sanitised += "&#" + name + ";" - + def handle_entityref(self, name): self.sanitised += "&" + name + ";" @@ -104,15 +127,14 @@ class SafeHTMLParser(HTMLParser): data = unicode(data, 'utf-8', errors='replace') HTMLParser.feed(self, data) tmp = SafeHTMLParser.replace_pre(data) - tmp = SafeHTMLParser.uriregex1.sub( - r'\1', - tmp) - tmp = SafeHTMLParser.uriregex2.sub(r'\1', tmp) + tmp = self.uriregex1.sub(r'\1', tmp) + tmp = self.uriregex2.sub(r'\1', tmp) tmp = SafeHTMLParser.replace_post(tmp) self.raw += tmp - def is_html(self, text = None, allow_picture = False): + def is_html(self, text=None, allow_picture=False): + """Detect if string contains HTML tags""" if text: self.reset() self.reset_safe() From 862e68445b658a7198468136cfc19ceffa141d3f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 13 Aug 2019 18:16:19 +0530 Subject: [PATCH 034/306] Pylint Fixes part1 --- src/bitmessagekivy/mpybit.py | 57 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index d87f3b6e..03f1d18b 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -80,7 +80,7 @@ class Inbox(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" self.inboxaccounts() - print(dt) + print dt def inboxaccounts(self): """Load inbox accounts.""" @@ -103,8 +103,8 @@ class Inbox(Screen): 'text': mail[4].strip(), 'secondary_text': mail[5][:10] + '...........' if len( mail[3]) > 10 else mail[3] + '\n' + " " + ( - third_text[:25] + '...!') if len( - third_text) > 25 else third_text, + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, 'receivedTime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem( @@ -198,7 +198,7 @@ class Inbox(Screen): try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) - except Exception as e: + except Exception: self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) @@ -211,7 +211,7 @@ class Inbox(Screen): self.remove_widget(self.children[1]) try: screens_obj = self.parent.screens[0] - except Exception as e: + except Exception: screens_obj = self.parent.parent.screens[0] screens_obj.add_widget(Inbox()) self.ids.refresh_layout.refresh_done() @@ -270,7 +270,7 @@ class MyAddress(Screen): self.manager.parent.parent\ .parent.ids.search_bar.clear_widgets() self.manager.current = 'login' - except Exception as e: + except Exception: pass def myadd_detail(self, fromaddress, label, *args): @@ -288,7 +288,7 @@ class MyAddress(Screen): self.remove_widget(self.children[1]) try: screens_obj = self.parent.screens[9] - except Exception as e: + except Exception: screens_obj = self.parent.parent.screens[9] screens_obj.add_widget(MyAddress()) self.ids.refresh_layout.refresh_done() @@ -318,7 +318,7 @@ class AddressBook(Screen): def init_ui(self, dt=0): """Clock Schdule for method AddressBook.""" self.loadAddresslist(None, 'All', '') - print(dt) + print dt def loadAddresslist(self, account, where="", what=""): """Clock Schdule for method AddressBook.""" @@ -420,7 +420,7 @@ class SelectableLabel(RecycleDataViewBehavior, Label): """Respond to the selection of items in the view.""" self.selected = is_selected if is_selected: - print("selection changed to {0}".format(rv.data[index])) + print "selection changed to {0}".format(rv.data[index]) rv.parent.txt_input.text = rv.parent.txt_input.text.replace( rv.parent.txt_input.text, rv.data[index]['text']) @@ -446,7 +446,7 @@ class DropDownWidget(BoxLayout): subject = str(self.ids.subject.text) message = str(self.ids.body.text) encoding = 3 - print("message: ", self.ids.body.text) + print "message: ", self.ids.body.text sendMessageToPeople = True if sendMessageToPeople: if toAddress != '' and subject and message: @@ -458,12 +458,12 @@ class DropDownWidget(BoxLayout): toAddress = addBMIfNotPresent(toAddress) statusIconColor = 'red' if addressVersionNumber > 4 or addressVersionNumber <= 1: - print("addressVersionNumber > 4 \ - or addressVersionNumber <= 1") + print "addressVersionNumber > 4 \ + or addressVersionNumber <= 1" if streamNumber > 1 or streamNumber == 0: - print("streamNumber > 1 or streamNumber == 0") + print "streamNumber > 1 or streamNumber == 0" if statusIconColor == 'red': - print("shared.statusIconColor == 'red'") + print "shared.statusIconColor == 'red'" stealthLevel = BMConfigParser().safeGetInt( 'bitmessagesettings', 'ackstealthlevel') from helper_ackPayload import genAckPayload @@ -494,7 +494,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.screens[3].add_widget(Sent()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) - print("sqlExecute successfully #######################") + print "sqlExecute successfully #######################" self.ids.body.text = '' self.ids.ti.text = '' self.ids.subject.text = '' @@ -565,7 +565,7 @@ class MyTextInput(TextInput): self.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]] + i][:self.starting_no] == value[:self.starting_no]] display_data = [] for i in matches: display_data.append({'text': i}) @@ -656,8 +656,7 @@ class Random(Screen): 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, - payloadLengthExtraBytes) - ) + payloadLengthExtraBytes)) self.manager.current = 'myaddress' self.ids.label.text = '' self.parent.parent.parent.parent.ids.toolbar.opacity = 1 @@ -689,7 +688,7 @@ class Sent(Screen): def init_ui(self, dt=0): """Clock Schdule for method sent accounts.""" self.sentaccounts() - print(dt) + print dt def sentaccounts(self): """Load sent accounts.""" @@ -717,8 +716,8 @@ class Sent(Screen): '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, + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem( @@ -786,7 +785,7 @@ class Sent(Screen): try: msg_count_objs = self.parent.parent.parent.parent.children[ 2].children[0].ids - except Exception as e: + except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids if int(state.sent_count) > 0: @@ -816,7 +815,7 @@ class Sent(Screen): try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) - except Exception as e: + except Exception: self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) @@ -1065,7 +1064,7 @@ class NavigateApp(App): def on_stop(self): """On stop methos is used for stoping the runing script.""" - print("*******************EXITING FROM APPLICATION*******************") + print "*******************EXITING FROM APPLICATION*******************" import shutdown shutdown.doCleanShutdown() @@ -1461,7 +1460,7 @@ class Draft(Screen): def init_ui(self, dt=0): """Clock Schdule for method draft accounts.""" self.sentaccounts() - print(dt) + print dt def sentaccounts(self): """Load draft accounts.""" @@ -1483,8 +1482,8 @@ class Draft(Screen): '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, + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, 'lastactiontime': mail[6]}) for item in self.data: meny = TwoLineAvatarIconListItem( @@ -1530,7 +1529,7 @@ class Draft(Screen): try: msg_count_objs = \ self.parent.parent.parent.parent.children[2].children[0].ids - except Exception as e: + except Exception: msg_count_objs = self.parent.parent.parent.parent.parent.children[ 2].children[0].ids if int(state.draft_count) > 0: @@ -1603,5 +1602,5 @@ def remove_search_bar(obj): """Remove search bar.""" try: obj.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() - except Exception as e: + except Exception: obj.parent.parent.parent.parent.ids.search_bar.clear_widgets() From de39ac89ae2bc4b0555692b28fabbee6a5ac0dbf Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 14 Aug 2019 20:25:34 +0530 Subject: [PATCH 035/306] wokred on all mail listing functionality --- src/bitmessagekivy/main.kv | 20 ++++- src/bitmessagekivy/mpybit.py | 141 ++++++++++++++++++++++++++++++++--- src/state.py | 2 + 3 files changed, 150 insertions(+), 13 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1188ecb4..c1db9c94 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -116,11 +116,12 @@ on_release: app.root.ids.scr_mngr.current = 'trash' badge_text: app.mail_count(self.text) on_press: app.check_search_screen(self) - NavigationDrawerIconButton: + NavigationDrawerIconButton: + id: allmail_cnt text: "All Mails" icon:'contact-mail' - on_release: app.root.ids.scr_mngr.current = 'inbox' - badge_text: "999+" + on_release: app.root.ids.scr_mngr.current = 'allmails' + badge_text: app.mail_count(self.text) on_press: app.check_search_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: @@ -233,6 +234,8 @@ NavigationLayout: id:sc15 Draft: id:sc16 + Allmails: + id:sc17 : @@ -269,6 +272,17 @@ NavigationLayout: MDList: id: ml ComposerButton: + +: + name: 'allmails' + FloatLayout: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml + ComposerButton: : name: 'test' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 319f3260..0318a6cc 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -699,6 +699,8 @@ class Sent(Screen): state.check_sent_acc: state.msg_counter_objs.send_cnt.badge_text = str(len(queryreturn)) state.sent_count = str(int(state.sent_count) + 1) + state.all_count = str(int(state.all_count) + 1) + state.msg_counter_objs.allmail_cnt.badge_text = state.all_count state.check_sent_acc = None if queryreturn: @@ -785,8 +787,11 @@ class Sent(Screen): int(state.sent_count) - 1) msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str( + int(state.all_count) - 1) state.sent_count = str(int(state.sent_count) - 1) state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) sqlExecute( "UPDATE sent SET folder = 'trash' \ WHERE lastactiontime = {};".format(data_index)) @@ -827,25 +832,25 @@ class Trash(Screen): state.association = BMConfigParser().addresses()[0] inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message from inbox \ - WHERE folder = 'trash' and fromaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from inbox \ + WHERE folder = 'trash' and toaddress = '{}';".format( state.association)) sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message from sent \ + "SELECT toaddress, fromaddress, subject, message, folder from sent \ WHERE folder = 'trash' and fromaddress = '{}';".format( state.association)) trash_data = inbox + sent for item in trash_data: meny = ThreeLineAvatarIconListItem( - text=item[1], - secondary_text=item[2], + text= 'Draft' if item[4] == 'draft' else item[1], + secondary_text=item[2] if item[2] else item[1], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format( + img_latter = './images/avatar.png' if item[4] == 'draft' else './images/text_images/{}.png'.format( item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!'))) + 2][0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget(source=img_latter)) self.ids.ml.add_widget(meny) @@ -1108,6 +1113,13 @@ class NavigateApp(App): folder = '{0}' ;".format( text.lower(), state.association))[0][0]) return state.draft_count + elif text == 'All Mails': + state.all_count = str(sqlQuery( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and \ + folder != 'trash' )+(SELECT count(*) FROM inbox where \ + toaddress = '{0}' and folder != 'trash') AS SumCount".format( + state.association))[0][0]) + return state.all_count def current_address_label(self, current_address=None): """Getting current address labels.""" @@ -1332,7 +1344,9 @@ class MailDetail(Screen): self.parent.parent.screens[0].add_widget(Inbox()) self.parent.parent.current = 'inbox' msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) toast('Deleted') @@ -1479,6 +1493,9 @@ class Draft(Screen): xAddress, account, "draft", where, what, False) if state.msg_counter_objs: state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) + state.all_count = str(int(state.all_count) + 1) + state.msg_counter_objs.allmail_cnt.badge_text = state.all_count + state.msg_counter_objs = None if queryreturn: for mail in queryreturn: @@ -1529,8 +1546,14 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( - data_index)) + sqlExecute( + "UPDATE sent SET folder = 'draft, trash' WHERE lastactiontime = {};".format( + data_index)) + # sqlExecute( + # "UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( + # data_index)) + # sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( + # data_index)) try: msg_count_objs = \ self.parent.parent.parent.parent.children[2].children[0].ids @@ -1540,7 +1563,13 @@ class Draft(Screen): if int(state.draft_count) > 0: msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) + msg_count_objs.allmail_cnt.badge_text = str( + int(state.all_count) - 1) + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) + state.all_count = str(int(state.all_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') @@ -1609,3 +1638,95 @@ def remove_search_bar(self): self.parent.parent.parent.parent.parent.ids.search_bar.clear_widgets() except Exception as e: self.parent.parent.parent.parent.ids.search_bar.clear_widgets() + + +class Allmails(Screen): + """all mails Screen uses screen to show widgets of screens.""" + + data = ListProperty() + + def __init__(self, *args, **kwargs): + """Method Parsing the address.""" + super(Allmails, self).__init__(*args, **kwargs) + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method all mails.""" + self.mailaccounts() + print(dt) + + def mailaccounts(self): + """Load all mails for account.""" + account = state.association + self.loadMessagelist(account, 'All', '') + + def loadMessagelist(self, account, where="", what=""): + """Load Inbox, Sent anf Draft list of messages.""" + inbox = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder from inbox \ + WHERE folder = 'inbox' and toaddress = '{}';".format( + account)) + sent_and_draft = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder from sent \ + WHERE folder != 'trash' and fromaddress = '{}';".format( + account)) + + all_mails = inbox + sent_and_draft + if all_mails: + for item in all_mails: + meny = ThreeLineAvatarIconListItem( + text='Draft' if item[4] == 'draft' else item[1], + secondary_text=item[1] if item[4] == 'draft' else item[2], + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + img_latter = './images/avatar.png' if item[4] == 'draft' else './images/text_images/{}.png'.format( + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget( + source=img_latter)) + carousel = Carousel(direction='right') + if platform == 'android': + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + else: + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def refresh_callback(self, *args): + """A method that updates the state of your application.""" + """While the spinner remains on the screen.""" + def refresh_callback(interval): + """Method used for loading the allmails screen data.""" + self.ids.ml.clear_widgets() + self.remove_widget(self.children[1]) + try: + screens_obj = self.parent.screens[16] + except Exception as e: + screens_obj = self.parent.parent.screens[16] + screens_obj.add_widget(Allmails()) + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) diff --git a/src/state.py b/src/state.py index 745f2f4c..3ec4b9ac 100644 --- a/src/state.py +++ b/src/state.py @@ -98,6 +98,8 @@ trash_count = 0 draft_count = 0 +all_count = 0 + searcing_text = '' search_screen = '' \ No newline at end of file From 709e1943471218b658643ccecbd27fcb8db8e1ac Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 16 Aug 2019 12:32:16 +0300 Subject: [PATCH 036/306] Fix #1504 (regression introduced in 0c1e516) --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 507e6ca0..2c5f1485 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3270,8 +3270,8 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) idCount = len(inventoryHashesToTrash) sqlExecuteChunked( - "DELETE FROM inbox" if folder == "trash" or shifted else - "UPDATE inbox SET folder='trash'" + ("DELETE FROM inbox" if folder == "trash" or shifted else + "UPDATE inbox SET folder='trash'") + " WHERE msgid IN ({0})", idCount, *inventoryHashesToTrash) tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) tableWidget.setUpdatesEnabled(True) From 7f272e8ababf3c5663185593500162901e248678 Mon Sep 17 00:00:00 2001 From: Navjot Date: Fri, 16 Aug 2019 20:26:19 +0530 Subject: [PATCH 037/306] wokred on updating database query of sent table --- src/bitmessagekivy/mpybit.py | 10 +++++----- src/class_singleCleaner.py | 2 +- src/class_singleWorker.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 0318a6cc..c7c5d266 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1546,14 +1546,14 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - sqlExecute( - "UPDATE sent SET folder = 'draft, trash' WHERE lastactiontime = {};".format( - data_index)) + # sqlExecute( + # "UPDATE sent SET folder = 'draft, trash' WHERE lastactiontime = {};".format( + # data_index)) # sqlExecute( # "UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( # data_index)) - # sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( - # data_index)) + sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( + data_index)) try: msg_count_objs = \ self.parent.parent.parent.parent.children[2].children[0].ids diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index e2cdbb89..2e9d1c3f 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -96,7 +96,7 @@ class singleCleaner(threading.Thread, StoppableThread): queryreturn = sqlQuery( "SELECT toaddress, ackdata, status FROM sent" " WHERE ((status='awaitingpubkey' OR status='msgsent')" - " AND folder='sent' AND sleeptill?)", + " AND folder LIKE '%sent%' AND sleeptill?)", int(time.time()), int(time.time()) - shared.maximumLengthOfTimeToBotherResendingMessages ) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 55ecc63a..6ed7c32e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -73,7 +73,7 @@ class singleWorker(threading.Thread, StoppableThread): # Initialize the neededPubkeys dictionary. queryreturn = sqlQuery( '''SELECT DISTINCT toaddress FROM sent''' - ''' WHERE (status='awaitingpubkey' AND folder='sent')''') + ''' WHERE (status='awaitingpubkey' AND folder LIKE '%sent%')''') for row in queryreturn: toAddress, = row # toStatus @@ -516,7 +516,7 @@ class singleWorker(threading.Thread, StoppableThread): queryreturn = sqlQuery( '''SELECT fromaddress, subject, message, ''' ''' ackdata, ttl, encodingtype FROM sent ''' - ''' WHERE status=? and folder='sent' ''', 'broadcastqueued') + ''' WHERE status=? and folder LIKE '%sent%' ''', 'broadcastqueued') for row in queryreturn: fromaddress, subject, body, ackdata, TTL, encoding = row @@ -686,7 +686,7 @@ class singleWorker(threading.Thread, StoppableThread): '''SELECT toaddress, fromaddress, subject, message, ''' ''' ackdata, status, ttl, retrynumber, encodingtype FROM ''' ''' sent WHERE (status='msgqueued' or status='forcepow') ''' - ''' and folder='sent' ''') + ''' and folder LIKE '%sent%' ''') # while we have a msg that needs some work for row in queryreturn: toaddress, fromaddress, subject, message, \ From f7c440fee687269513770fe9565581be1fc0335f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 17 Aug 2019 18:13:10 +0530 Subject: [PATCH 038/306] Pylint Fixes part3 --- src/bitmessagekivy/mpybit.py | 170 +++++++++++++++++++---------------- 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ff4f12c1..fe57fb20 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,51 +1,65 @@ """Coding: utf-8.""" +import time +from functools import partial + +from bmconfigparser import BMConfigParser + +from helper_sql import sqlExecute, sqlQuery + from kivy.app import App +from kivy.clock import Clock +from kivy.core.window import Window from kivy.lang import Builder from kivy.metrics import dp -from kivy.properties import ObjectProperty +from kivy.properties import ( + BooleanProperty, + ListProperty, + NumericProperty, + ObjectProperty, + StringProperty) +from kivy.uix.behaviors import FocusBehavior +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Button +from kivy.uix.carousel import Carousel +from kivy.uix.floatlayout import FloatLayout from kivy.uix.image import Image +from kivy.uix.label import Label +from kivy.uix.popup import Popup +from kivy.uix.recycleboxlayout import RecycleBoxLayout +from kivy.uix.recycleview import RecycleView +from kivy.uix.recycleview.layout import LayoutSelectionBehavior +from kivy.uix.recycleview.views import RecycleDataViewBehavior from kivy.uix.screenmanager import Screen +from kivy.uix.spinner import Spinner +from kivy.uix.textinput import TextInput +from kivy.utils import platform + +import kivy_helper_search + from kivymd.button import MDIconButton from kivymd.dialog import MDDialog from kivymd.label import MDLabel -from kivymd.list import ILeftBody, ILeftBodyTouch, IRightBodyTouch +from kivymd.list import ( + ILeftBody, + ILeftBodyTouch, + IRightBodyTouch, + ThreeLineAvatarIconListItem, + TwoLineAvatarIconListItem, + TwoLineListItem) from kivymd.navigationdrawer import ( MDNavigationDrawer, NavigationDrawerHeaderBase) from kivymd.selectioncontrols import MDCheckbox -from kivymd.theming import ThemeManager -from kivymd.list import ( - ThreeLineAvatarIconListItem, - TwoLineAvatarIconListItem, - TwoLineListItem) -from kivy.properties import ListProperty, StringProperty, BooleanProperty -from kivy.clock import Clock -from bmconfigparser import BMConfigParser -import state -import queues -from kivy.uix.popup import Popup -from helper_sql import sqlQuery, sqlExecute -from kivy.uix.textinput import TextInput -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.floatlayout import FloatLayout -from kivy.properties import NumericProperty -from kivy.uix.recycleview import RecycleView -from kivy.uix.recycleview.views import RecycleDataViewBehavior -from kivy.uix.label import Label -from kivy.uix.recycleboxlayout import RecycleBoxLayout -from kivy.uix.behaviors import FocusBehavior -from kivy.uix.recycleview.layout import LayoutSelectionBehavior -import time -from uikivysignaler import UIkivySignaler -from semaphores import kivyuisignaler -from kivy.uix.button import Button -import kivy_helper_search -from kivy.core.window import Window -from functools import partial -from kivy.uix.carousel import Carousel -from kivy.utils import platform -from kivy.uix.spinner import Spinner from kivymd.textfields import MDTextField +from kivymd.theming import ThemeManager + +import queues + +from semaphores import kivyuisignaler + +import state + +from uikivysignaler import UIkivySignaler def toast(text): @@ -58,7 +72,7 @@ def toast(text): class Navigatorss(MDNavigationDrawer): """Navigators class contains image, title and logo.""" - + # pylint: disable=too-few-public-methods image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() @@ -204,8 +218,8 @@ class Inbox(Screen): self.parent.parent.screens[4].add_widget(Trash()) def refresh_callback(self, *args): - """A method that updates the state of your application.""" - """While the spinner remains on the screen.""" + """Method updates the state of application, \ + While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" self.ids.ml.clear_widgets() @@ -233,8 +247,9 @@ class MyAddress(Screen): """Clock Schdule for method inbox accounts.""" addresses_list = state.kivyapp.variable_1 if state.searcing_text: - filtered_list = filter(lambda addr: self.filter_address( - addr), BMConfigParser().addresses()) + filtered_list = filter( + lambda addr: self.filter_address( + addr), BMConfigParser().addresses()) addresses_list = filtered_list if addresses_list: data = [] @@ -282,8 +297,8 @@ class MyAddress(Screen): p.set_address(fromaddress, label) def refresh_callback(self, *args): - """A method that updates the state of your application.""" - """While the spinner remains on the screen.""" + """Method updates the state of application, \ + While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the myaddress screen data.""" self.ids.ml.clear_widgets() @@ -304,8 +319,7 @@ class MyAddress(Screen): if filter(lambda x: ( state.searcing_text).lower() in x, [ BMConfigParser().get( - address, - 'label').lower(), address.lower()]): + address, 'label').lower(), address.lower()]): return True return False @@ -397,7 +411,7 @@ class AddressBook(Screen): class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view.""" - + # pylint: disable=too-few-public-methods pass @@ -432,6 +446,7 @@ class SelectableLabel(RecycleDataViewBehavior, Label): class RV(RecycleView): """Recycling View.""" + # pylint: disable=too-few-public-methods def __init__(self, **kwargs): """Recycling Method.""" @@ -592,19 +607,19 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" - + # pylint: disable=too-few-public-methods pass class Login(Screen): """Login Screeen.""" - + # pylint: disable=too-few-public-methods pass class NetworkStat(Screen): """Method used to show network stat.""" - + # pylint: disable=too-few-public-methods text_variable_1 = StringProperty( '{0}::{1}'.format('Total Connections', '0')) text_variable_2 = StringProperty( @@ -639,13 +654,13 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): """Navigate Content Drawer.""" - + # pylint: disable=too-few-public-methods pass class Random(Screen): """Generates Random Address.""" - + # pylint: disable=too-few-public-methods is_active = BooleanProperty(False) checked = StringProperty("") @@ -674,7 +689,7 @@ class Random(Screen): class AddressSuccessful(Screen): """Getting Address Detail.""" - + # pylint: disable=too-few-public-methods pass @@ -833,6 +848,7 @@ class Sent(Screen): class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" + # pylint: disable=too-few-public-methods def __init__(self, *args, **kwargs): """Trash method, delete sent message and add in Trash.""" @@ -846,12 +862,12 @@ class Trash(Screen): state.association = BMConfigParser().addresses()[0] inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from inbox \ - WHERE folder = 'trash' and toaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from \ + inbox WHERE folder = 'trash' and toaddress = '{}';".format( state.association)) sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from sent \ - WHERE folder = 'trash' and fromaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from \ + sent WHERE folder = 'trash' and fromaddress = '{}';".format( state.association)) trash_data = inbox + sent @@ -871,12 +887,13 @@ class Trash(Screen): class Page(Screen): """Page Screen show widgets of page.""" - + # pylint: disable=too-few-public-methods pass class Create(Screen): """Creates the screen widgets.""" + # pylint: disable=too-few-public-methods def __init__(self, **kwargs): """Getting Labels and address from addressbook.""" @@ -891,7 +908,7 @@ class Create(Screen): class Setting(Screen): """Setting the Screen components.""" - + # pylint: disable=too-few-public-methods pass @@ -1068,8 +1085,6 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" - # self.root.ids.toolbar.left_action_items = '' - # self.root.ids.myButton.opacity = 0 self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' @@ -1078,7 +1093,7 @@ class NavigateApp(App): composer_obj.subject.text = '' @staticmethod - def on_stop(self): + def on_stop(): """On stop methos is used for stoping the runing script.""" print "*******************EXITING FROM APPLICATION*******************" import shutdown @@ -1117,8 +1132,8 @@ class NavigateApp(App): return state.draft_count elif text == 'All Mails': state.all_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and \ - folder != 'trash' )+(SELECT count(*) FROM inbox where \ + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}'\ + and folder != 'trash' )+(SELECT count(*) FROM inbox where \ toaddress = '{0}' and folder != 'trash') AS SumCount".format( state.association))[0][0]) return state.all_count @@ -1236,26 +1251,27 @@ class GrashofPopup(Popup): action=lambda *x: self.dialog.dismiss()) self.dialog.open() - def close_pop(self): + @staticmethod + def close_pop(): """Pop is Canceled.""" toast('Canceled') class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" - + # pylint: disable=too-few-public-methods pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): """Left icon sample widget.""" - + # pylint: disable=too-few-public-methods pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): """Right icon sample widget.""" - + # pylint: disable=too-few-public-methods pass @@ -1462,6 +1478,7 @@ class AddbookDetailPopup(Popup): class ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" + # pylint: disable=too-few-public-methods def qrdisplay(self): """Method used for showing QR Code.""" @@ -1556,12 +1573,6 @@ class Draft(Screen): def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" - # sqlExecute( - # "UPDATE sent SET folder = 'draft, trash' WHERE lastactiontime = {};".format( - # data_index)) - # sqlExecute( - # "UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( - # data_index)) sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( data_index)) try: @@ -1583,7 +1594,8 @@ class Draft(Screen): self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') - def draft_msg(self, src_object): + @staticmethod + def draft_msg(src_object): """Method used for saving draft mails.""" # pylint: disable=too-many-locals composer_object = src_object.children[1].children[0].children[ @@ -1635,6 +1647,7 @@ class Draft(Screen): class CustomSpinner(Spinner): """This class is used for setting spinner size.""" + # pylint: disable=too-few-public-methods def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" @@ -1677,12 +1690,12 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from inbox \ - WHERE folder = 'inbox' and toaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from\ + inbox WHERE folder = 'inbox' and toaddress = '{}';".format( account)) sent_and_draft = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from sent \ - WHERE folder != 'trash' and fromaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from\ + sent WHERE folder != 'trash' and fromaddress = '{}';".format( account)) all_mails = inbox + sent_and_draft @@ -1728,8 +1741,8 @@ class Allmails(Screen): self.ids.ml.add_widget(content) def refresh_callback(self, *args): - """A method that updates the state of your application.""" - """While the spinner remains on the screen.""" + """Method updates the state of application, \ + While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the allmails screen data.""" self.ids.ml.clear_widgets() @@ -1741,5 +1754,4 @@ class Allmails(Screen): screens_obj.add_widget(Allmails()) self.ids.refresh_layout.refresh_done() self.tick = 0 - Clock.schedule_once(refresh_callback, 1) From f180b1a5b0efdf5f32bd363ffeb0f1c4cf1eceec Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 14 Aug 2019 18:48:24 +0300 Subject: [PATCH 039/306] Moved randomtrackingdict to network, it's used only there --- src/{ => network}/randomtrackingdict.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => network}/randomtrackingdict.py (100%) diff --git a/src/randomtrackingdict.py b/src/network/randomtrackingdict.py similarity index 100% rename from src/randomtrackingdict.py rename to src/network/randomtrackingdict.py From a3964aee5a05237796c20867d92a71065d59ac60 Mon Sep 17 00:00:00 2001 From: Navjot Date: Mon, 19 Aug 2019 16:36:24 +0530 Subject: [PATCH 040/306] worekd on draft mail detail page or sent draft mail functionality --- src/bitmessagekivy/main.kv | 4 +- src/bitmessagekivy/mpybit.py | 131 +++++++++++++++++++++++------------ src/state.py | 4 +- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index c1db9c94..82357087 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -828,10 +828,10 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() if root.page_type == 'sent' else root.write_msg() MDLabel: font_style: 'Title' - text: 'Reply' if root.page_type == 'inbox' else 'Copy' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' font_size: '13sp' color: (1,1,1,1) halign: 'center' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index fe57fb20..f9efc106 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -475,44 +475,54 @@ class DropDownWidget(BoxLayout): status, addressVersionNumber, streamNumber, ripe = \ decodeAddress(toAddress) if status == 'success': - from addresses import addBMIfNotPresent - toAddress = addBMIfNotPresent(toAddress) - statusIconColor = 'red' - if addressVersionNumber > 4 or addressVersionNumber <= 1: - print "addressVersionNumber > 4 \ - or addressVersionNumber <= 1" - if streamNumber > 1 or streamNumber == 0: - print "streamNumber > 1 or streamNumber == 0" - if statusIconColor == 'red': - print "shared.statusIconColor == 'red'" - stealthLevel = BMConfigParser().safeGetInt( - 'bitmessagesettings', 'ackstealthlevel') - from helper_ackPayload import genAckPayload - ackdata = genAckPayload(streamNumber, stealthLevel) - t = () - sqlExecute( - '''INSERT INTO sent VALUES - (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, - int(time.time()), - int(time.time()), - 0, - 'msgqueued', - 0, - 'sent', - encoding, - BMConfigParser().getint('bitmessagesettings', 'ttl')) + if state.detailPageType == 'draft' and state.send_draft_mail: + sqlExecute( + "UPDATE sent SET toaddress = '{0}', fromaddress ='{1}' , subject = '{2}', message = '{3}', folder = 'sent' \ + WHERE lastactiontime = '{4}';".format(toAddress, fromAddress, subject, message, state.send_draft_mail)) + self.parent.parent.screens[15].clear_widgets() + self.parent.parent.screens[15].add_widget(Draft()) + state.detailPageType = 'draft' + else: + from addresses import addBMIfNotPresent + toAddress = addBMIfNotPresent(toAddress) + statusIconColor = 'red' + if addressVersionNumber > 4 or addressVersionNumber <= 1: + print "addressVersionNumber > 4 \ + or addressVersionNumber <= 1" + if streamNumber > 1 or streamNumber == 0: + print "streamNumber > 1 or streamNumber == 0" + if statusIconColor == 'red': + print "shared.statusIconColor == 'red'" + stealthLevel = BMConfigParser().safeGetInt( + 'bitmessagesettings', 'ackstealthlevel') + from helper_ackPayload import genAckPayload + ackdata = genAckPayload(streamNumber, stealthLevel) + t = () + sqlExecute( + '''INSERT INTO sent VALUES + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'sent', + encoding, + BMConfigParser().getint('bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[0].children[2].children[0].ids self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) + self.parent.parent.screens[16].clear_widgets() + self.parent.parent.screens[16].add_widget(Allmails()) toLabel = '' queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" @@ -984,10 +994,12 @@ class NavigateApp(App): self.root.ids.sc4.clear_widgets() self.root.ids.sc5.clear_widgets() self.root.ids.sc16.clear_widgets() + self.root.ids.sc17.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) self.root.ids.sc4.add_widget(Sent()) self.root.ids.sc5.add_widget(Trash()) self.root.ids.sc16.add_widget(Draft()) + self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = \ @@ -1008,12 +1020,14 @@ class NavigateApp(App): sqlQuery( "SELECT COUNT(*) FROM sent WHERE fromaddress = '{}' and \ folder = 'draft' ;".format(state.association))[0][0]) + state.all_count = str(int(state.sent_count) + int(state.inbox_count)) if msg_counter_objs: msg_counter_objs.send_cnt.badge_text = state.sent_count msg_counter_objs.inbox_cnt.badge_text = state.inbox_count msg_counter_objs.trash_cnt.badge_text = state.trash_count msg_counter_objs.draft_cnt.badge_text = state.draft_count + msg_counter_objs.allmail_cnt.badge_text = state.all_count @staticmethod def getCurrentAccount(): @@ -1048,15 +1062,16 @@ class NavigateApp(App): if key == 27: if self.root.ids.scr_mngr.current == "mailDetail": self.root.ids.scr_mngr.current = \ - 'sent' if state.detailPageType == 'sent' else 'inbox' - self.add_search_bar() + 'sent' if state.detailPageType == 'sent' else 'inbox' if state.detailPageType == 'inbox' else 'draft' + if state.detailPageType in ['sent', 'inbox']: + self.add_search_bar() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root from_addr = str(self.root.children[1].children[0].children[ 0].children[0].children[0].ids.ti.text) to_addr = str(self.root.children[1].children[0].children[ 0].children[0].children[0].ids.txt_input.text) - if from_addr and to_addr: + if from_addr and to_addr and state.detailPageType != 'draft': Draft().draft_msg(composer_objs) self.root.ids.scr_mngr.current = 'inbox' self.add_search_bar() @@ -1132,9 +1147,9 @@ class NavigateApp(App): return state.draft_count elif text == 'All Mails': state.all_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}'\ - and folder != 'trash' )+(SELECT count(*) FROM inbox where \ - toaddress = '{0}' and folder != 'trash') AS SumCount".format( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and \ + folder = 'sent' )+(SELECT count(*) FROM inbox where \ + toaddress = '{0}' and folder != 'trash') AS SumCount".format( state.association))[0][0]) return state.all_count @@ -1319,7 +1334,7 @@ class MailDetail(Screen): def init_ui(self, dt=0): """Clock Schdule for method MailDetail mails.""" self.page_type = state.detailPageType if state.detailPageType else '' - if state.detailPageType == 'sent': + if state.detailPageType == 'sent' or state.detailPageType == 'draft': data = sqlQuery( "select toaddress, fromaddress, subject, message, status, \ ackdata from sent where lastactiontime = {};".format( @@ -1337,7 +1352,7 @@ class MailDetail(Screen): """Assigning mail details.""" self.to_addr = data[0][0] self.from_addr = data[0][1] - self.subject = data[0][2].upper() + self.subject = data[0][2].upper() if data[0][2].upper() else '(no subject)' self.message = data[0][3] if len(data[0]) == 6: self.status = data[0][4] @@ -1389,6 +1404,17 @@ class MailDetail(Screen): """Method used for copying sent mail to the composer.""" pass + def write_msg(self): + """This method is used to write on draft mail.""" + state.send_draft_mail = state.sentMailTime + composer_ids = self.parent.parent.parent.parent.parent.ids.sc3.children[0].ids + composer_ids.ti.text = self.from_addr + composer_ids.btn.text = self.from_addr + composer_ids.txt_input.text = self.to_addr + composer_ids.subject.text = '' if self.subject == '(no subject)' else self.subject.lower() + composer_ids.body.text = self.message + self.parent.parent.current = 'create' + class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail.""" @@ -1520,9 +1546,9 @@ class Draft(Screen): xAddress, account, "draft", where, what, False) if state.msg_counter_objs: state.msg_counter_objs.draft_cnt.badge_text = str(len(queryreturn)) - state.all_count = str(int(state.all_count) + 1) - state.msg_counter_objs.allmail_cnt.badge_text = state.all_count - state.msg_counter_objs = None + # state.all_count = str(int(state.all_count) + 1) + # state.msg_counter_objs.allmail_cnt.badge_text = state.all_count + # state.msg_counter_objs = None if queryreturn: for mail in queryreturn: @@ -1542,6 +1568,8 @@ class Draft(Screen): text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( source='./images/avatar.png')) + meny.bind(on_press=partial( + self.draft_detail, item['lastactiontime'])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 @@ -1571,6 +1599,17 @@ class Draft(Screen): valign='top') self.ids.ml.add_widget(content) + def draft_detail(self, lastsenttime, *args): + state.detailPageType = 'draft' + state.sentMailTime = lastsenttime + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + def delete_draft(self, data_index, instance, *args): """Method used to delete draft message permanently.""" sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( @@ -1694,8 +1733,8 @@ class Allmails(Screen): inbox WHERE folder = 'inbox' and toaddress = '{}';".format( account)) sent_and_draft = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from\ - sent WHERE folder != 'trash' and fromaddress = '{}';".format( + "SELECT toaddress, fromaddress, subject, message, folder from sent \ + WHERE folder = 'sent' and fromaddress = '{}';".format( account)) all_mails = inbox + sent_and_draft diff --git a/src/state.py b/src/state.py index 3ec4b9ac..2fc10ca2 100644 --- a/src/state.py +++ b/src/state.py @@ -102,4 +102,6 @@ all_count = 0 searcing_text = '' -search_screen = '' \ No newline at end of file +search_screen = '' + +send_draft_mail = None \ No newline at end of file From 37e0257396ff0a2ce0a58202c13a9e3560e62b3e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 20 Aug 2019 18:41:18 +0530 Subject: [PATCH 041/306] Pylint Fixes --- src/bitmessagekivy/mpybit.py | 60 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index fe57fb20..7f924d00 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -72,6 +72,7 @@ def toast(text): class Navigatorss(MDNavigationDrawer): """Navigators class contains image, title and logo.""" + # pylint: disable=too-few-public-methods image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') @@ -178,7 +179,6 @@ class Inbox(Screen): src_mng_obj = self.manager else: src_mng_obj = self.parent.parent - src_mng_obj.screens[13].clear_widgets() src_mng_obj.screens[13].add_widget(MailDetail()) src_mng_obj.current = 'mailDetail' @@ -195,16 +195,20 @@ class Inbox(Screen): int(state.inbox_count) - 1) msg_count_objs.trash_cnt.badge_text = str( int(state.trash_count) + 1) - state.inbox_count = str(int(state.inbox_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) - self.ids.ml.remove_widget(instance.parent.parent) + state.inbox_count = str( + int(state.inbox_count) - 1) + state.trash_count = str( + int(state.trash_count) + 1) + self.ids.ml.remove_widget( + instance.parent.parent) toast('Deleted') self.update_trash() def archive(self, data_index, instance, *args): """Archive inbox mail from inbox listing.""" - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE \ - received = {};".format(data_index)) + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + data_index)) self.ids.ml.remove_widget(instance.parent.parent) self.update_trash() @@ -218,7 +222,7 @@ class Inbox(Screen): self.parent.parent.screens[4].add_widget(Trash()) def refresh_callback(self, *args): - """Method updates the state of application, \ + """Method updates the state of application,\ While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" @@ -247,9 +251,8 @@ class MyAddress(Screen): """Clock Schdule for method inbox accounts.""" addresses_list = state.kivyapp.variable_1 if state.searcing_text: - filtered_list = filter( - lambda addr: self.filter_address( - addr), BMConfigParser().addresses()) + filtered_list = filter(lambda addr: self.filter_address( + addr), BMConfigParser().addresses()) addresses_list = filtered_list if addresses_list: data = [] @@ -310,16 +313,14 @@ class MyAddress(Screen): screens_obj.add_widget(MyAddress()) self.ids.refresh_layout.refresh_done() self.tick = 0 - Clock.schedule_once(refresh_callback, 1) @staticmethod def filter_address(address): """Method will filter the my address list data.""" - if filter(lambda x: ( - state.searcing_text).lower() in x, [ - BMConfigParser().get( - address, 'label').lower(), address.lower()]): + if filter(lambda x: (state.searcing_text).lower() in x, [ + BMConfigParser().get( + address, 'label').lower(), address.lower()]): return True return False @@ -411,6 +412,7 @@ class AddressBook(Screen): class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view.""" + # pylint: disable=too-few-public-methods pass @@ -428,6 +430,7 @@ class SelectableLabel(RecycleDataViewBehavior, Label): return super(SelectableLabel, self).refresh_view_attrs( rv, index, data) + # pylint: disable=inconsistent-return-statements def on_touch_down(self, touch): """Add selection on touch down.""" if super(SelectableLabel, self).on_touch_down(touch): @@ -446,6 +449,7 @@ class SelectableLabel(RecycleDataViewBehavior, Label): class RV(RecycleView): """Recycling View.""" + # pylint: disable=too-few-public-methods def __init__(self, **kwargs): @@ -459,6 +463,7 @@ class DropDownWidget(BoxLayout): txt_input = ObjectProperty() rv = ObjectProperty() + # pylint: disable=inconsistent-return-statements def send(self): """Send message from one address to another.""" # pylint: disable=too-many-locals @@ -607,18 +612,21 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" + # pylint: disable=too-few-public-methods pass class Login(Screen): """Login Screeen.""" + # pylint: disable=too-few-public-methods pass class NetworkStat(Screen): """Method used to show network stat.""" + # pylint: disable=too-few-public-methods text_variable_1 = StringProperty( '{0}::{1}'.format('Total Connections', '0')) @@ -654,12 +662,14 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): """Navigate Content Drawer.""" + # pylint: disable=too-few-public-methods pass class Random(Screen): """Generates Random Address.""" + # pylint: disable=too-few-public-methods is_active = BooleanProperty(False) checked = StringProperty("") @@ -689,6 +699,7 @@ class Random(Screen): class AddressSuccessful(Screen): """Getting Address Detail.""" + # pylint: disable=too-few-public-methods pass @@ -848,6 +859,7 @@ class Sent(Screen): class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" + # pylint: disable=too-few-public-methods def __init__(self, *args, **kwargs): @@ -887,12 +899,14 @@ class Trash(Screen): class Page(Screen): """Page Screen show widgets of page.""" + # pylint: disable=too-few-public-methods pass class Create(Screen): """Creates the screen widgets.""" + # pylint: disable=too-few-public-methods def __init__(self, **kwargs): @@ -908,6 +922,7 @@ class Create(Screen): class Setting(Screen): """Setting the Screen components.""" + # pylint: disable=too-few-public-methods pass @@ -959,20 +974,19 @@ class NavigateApp(App): kivyuisignaler.release() super(NavigateApp, self).run() + # pylint: disable=inconsistent-return-statements @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] + '..' - else: - return "textdemo" + return "textdemo" elif name == "values": if BMConfigParser().addresses(): return [address[:16] + '..' for address in BMConfigParser().addresses()] - else: - return "valuesdemo" + return "valuesdemo" def getCurrentAccountData(self, text): """Get Current Address Account Data.""" @@ -1020,8 +1034,7 @@ class NavigateApp(App): """It uses to get current account label.""" if state.association: return state.association - else: - return "Bitmessage Login" + return "Bitmessage Login" @staticmethod def addingtoaddressbook(): @@ -1259,18 +1272,21 @@ class GrashofPopup(Popup): class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" + # pylint: disable=too-few-public-methods pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): """Left icon sample widget.""" + # pylint: disable=too-few-public-methods pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): """Right icon sample widget.""" + # pylint: disable=too-few-public-methods pass @@ -1478,6 +1494,7 @@ class AddbookDetailPopup(Popup): class ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" + # pylint: disable=too-few-public-methods def qrdisplay(self): @@ -1647,6 +1664,7 @@ class Draft(Screen): class CustomSpinner(Spinner): """This class is used for setting spinner size.""" + # pylint: disable=too-few-public-methods def __init__(self, *args, **kwargs): From 54eefe757f14ccf1f21d3b657dbb8e578da5a20d Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 21 Aug 2019 13:37:47 +0530 Subject: [PATCH 042/306] worked on implelemting back screen functionality for composer and fixed issues --- src/bitmessagekivy/main.kv | 8 ++++---- src/bitmessagekivy/mpybit.py | 40 ++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 82357087..adbcb0e9 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -304,7 +304,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(600) + height: dp(500) padding: dp(32) spacing: 15 BoxLayout: @@ -326,7 +326,7 @@ NavigationLayout: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 - on_text: ti.text = self.text if self.text != 'Select' else '' + on_text: root.auto_fill_fromaddr() if self.text != 'Select' else '' option_cls: Factory.get("MySpinnerOption") background_color: color_button if self.state == 'normal' else color_button_pressed background_down: 'atlas://data/images/defaulttheme/spinner' @@ -344,7 +344,7 @@ NavigationLayout: id: txt_input size_hint_y: None font_size: '13sp' - height: 100 + height: 70 hint_text: 'type or search recipients address starting with BM-' RV: id: rv @@ -525,7 +525,7 @@ NavigationLayout: MDRaisedButton: size_hint: .5, None height: dp(40) - on_release: root.generateaddress() + on_release: root.generateaddress(app) opposite_colors: True MDLabel: font_style: 'Title' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index f9efc106..a5ab9d31 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -577,6 +577,10 @@ class DropDownWidget(BoxLayout): self.ids.subject.text = '' self.ids.body.text = '' + def auto_fill_fromaddr(self): + self.ids.ti.text = self.ids.btn.text + self.ids.ti.focus = True + class MyTextInput(TextInput): """Takes the text input in the field.""" @@ -674,7 +678,7 @@ class Random(Screen): is_active = BooleanProperty(False) checked = StringProperty("") - def generateaddress(self): + def generateaddress(self, navApp): """Method for Address Generator.""" streamNumberForAddress = 1 label = self.ids.label.text @@ -694,6 +698,7 @@ class Random(Screen): self.parent.parent.parent.parent.ids.toolbar.disabled = False self.parent.parent.parent.parent.ids.sc10.clear_widgets() self.parent.parent.parent.parent.ids.sc10.add_widget(MyAddress()) + navApp.add_search_bar() toast('New address created') @@ -1067,14 +1072,13 @@ class NavigateApp(App): self.add_search_bar() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root - from_addr = str(self.root.children[1].children[0].children[ - 0].children[0].children[0].ids.ti.text) - to_addr = str(self.root.children[1].children[0].children[ - 0].children[0].children[0].ids.txt_input.text) + from_addr = str(self.root.ids.sc3.children[0].ids.ti.text) + to_addr = str(self.root.ids.sc3.children[0].ids.txt_input.text) if from_addr and to_addr and state.detailPageType != 'draft': Draft().draft_msg(composer_objs) self.root.ids.scr_mngr.current = 'inbox' self.add_search_bar() + self.back_press() elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' elif self.root.ids.scr_mngr.current == "random": @@ -1083,13 +1087,13 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = 'inbox' self.add_search_bar() self.root.ids.scr_mngr.transition.direction = 'right' - self.root.ids.scr_mngr.transition.bind(on_complete=self.restart) + self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) return True - def restart(self, *args): + def reset(self, *args): """Method used to set transition direction.""" self.root.ids.scr_mngr.transition.direction = 'left' - self.root.ids.scr_mngr.transition.unbind(on_complete=self.restart) + self.root.ids.scr_mngr.transition.unbind(on_complete=self.reset) @staticmethod def status_dispatching(data): @@ -1100,6 +1104,9 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" + self.root.ids.toolbar.left_action_items = [['arrow-left', lambda x: self.back_press()]] + self.root.ids.myButton.opacity = 0 + self.root.ids.myButton.disabled = True self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' @@ -1107,6 +1114,16 @@ class NavigateApp(App): composer_obj.txt_input.text = '' composer_obj.subject.text = '' + def back_press(self): + """This method is used for going back from composer to previous page""" + self.root.ids.myButton.opacity = 1 + self.root.ids.myButton.disabled = False + self.root.ids.toolbar.left_action_items = [['menu', lambda x: self.root.toggle_nav_drawer()]] + 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) + self.add_search_bar() + @staticmethod def on_stop(): """On stop methos is used for stoping the runing script.""" @@ -1227,12 +1244,13 @@ class GrashofPopup(Popup): """Method is used for Saving Contacts.""" my_addresses = \ self.parent.children[1].children[2].children[0].ids.btn.values - entered_text = str(self.ids.label.text) + entered_text = str(self.ids.address.text) if entered_text in my_addresses: - self.ids.label.focus = True - self.ids.label.helper_text = 'Please Enter corrent address' + self.ids.address.focus = False + self.ids.address.helper_text = 'Please Enter corrent address' elif entered_text == '': self.ids.label.focus = True + # self.ids.address.focus = True self.ids.label.helper_text = 'This field is required' label = self.ids.label.text From 74850d4fddbac10312782021ca477afa7742eb00 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 21 Aug 2019 19:54:56 +0530 Subject: [PATCH 043/306] Code Fixes After Pull --- src/bitmessagekivy/mpybit.py | 69 ++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 0e880658..78a577cb 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -61,6 +61,9 @@ import state from uikivysignaler import UIkivySignaler +# pylint: disable=unused-argument +# pylint: disable=broad-except + def toast(text): """Method will display the toast message.""" @@ -221,9 +224,9 @@ class Inbox(Screen): self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application,\ - While the spinner remains on the screen.""" + """Method updates the state of application, While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the inbox screen data.""" self.ids.ml.clear_widgets() @@ -299,9 +302,9 @@ class MyAddress(Screen): p.open() p.set_address(fromaddress, label) + # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application, \ - While the spinner remains on the screen.""" + """Method updates the state of application, While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the myaddress screen data.""" self.ids.ml.clear_widgets() @@ -451,7 +454,6 @@ class RV(RecycleView): """Recycling View.""" # pylint: disable=too-few-public-methods - def __init__(self, **kwargs): """Recycling Method.""" super(RV, self).__init__(**kwargs) @@ -464,6 +466,8 @@ class DropDownWidget(BoxLayout): rv = ObjectProperty() # pylint: disable=inconsistent-return-statements + # pylint: disable=unused-variable + # pylint: disable=too-many-statements def send(self): """Send message from one address to another.""" # pylint: disable=too-many-locals @@ -482,8 +486,15 @@ class DropDownWidget(BoxLayout): if status == 'success': if state.detailPageType == 'draft' and state.send_draft_mail: sqlExecute( - "UPDATE sent SET toaddress = '{0}', fromaddress ='{1}' , subject = '{2}', message = '{3}', folder = 'sent' \ - WHERE lastactiontime = '{4}';".format(toAddress, fromAddress, subject, message, state.send_draft_mail)) + "UPDATE sent SET toaddress = '{0}' \ + , fromaddress ='{1}' , subject = '{2}'\ + , message = '{3}', folder = 'sent'\ + WHERE lastactiontime = '{4}';".format( + toAddress, + fromAddress, + subject, + message, + state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) state.detailPageType = 'draft' @@ -520,7 +531,8 @@ class DropDownWidget(BoxLayout): 0, 'sent', encoding, - BMConfigParser().getint('bitmessagesettings', 'ttl')) + BMConfigParser().getint( + 'bitmessagesettings', 'ttl')) state.check_sent_acc = fromAddress state.msg_counter_objs = self.parent.parent.parent.parent\ .parent.parent.children[0].children[2].children[0].ids @@ -548,6 +560,7 @@ class DropDownWidget(BoxLayout): msg = 'Please fill the form' self.address_error_message(msg) + # pylint: disable=attribute-defined-outside-init def address_error_message(self, msg): """Show Error Message.""" self.box = FloatLayout() @@ -583,6 +596,7 @@ class DropDownWidget(BoxLayout): self.ids.body.text = '' def auto_fill_fromaddr(self): + """Mehtod used to fill the text automatically From Address.""" self.ids.ti.text = self.ids.btn.text self.ids.ti.focus = True @@ -1079,9 +1093,10 @@ class NavigateApp(App): """Method is used for going on previous screen.""" if key == 27: if 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' - if state.detailPageType in ['sent', 'inbox']: + self.root.ids.scr_mngr.current = 'sent'\ + if state.detailPageType == 'sent' else 'inbox' \ + if state.detailPageType == 'inbox' else 'draft' + if state.detailPageType in ['sent', 'inbox']: self.add_search_bar() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root @@ -1117,7 +1132,8 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" - self.root.ids.toolbar.left_action_items = [['arrow-left', lambda x: self.back_press()]] + self.root.ids.toolbar.left_action_items = [ + ['arrow-left', lambda x: self.back_press()]] self.root.ids.myButton.opacity = 0 self.root.ids.myButton.disabled = True self.root.ids.search_bar.clear_widgets() @@ -1128,10 +1144,11 @@ class NavigateApp(App): composer_obj.subject.text = '' def back_press(self): - """This method is used for going back from composer to previous page""" + """Method used for going back from composer to previous page.""" self.root.ids.myButton.opacity = 1 self.root.ids.myButton.disabled = False - 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.toggle_nav_drawer()]] 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) @@ -1177,9 +1194,9 @@ class NavigateApp(App): return state.draft_count elif text == 'All Mails': state.all_count = str(sqlQuery( - "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' and \ - folder = 'sent' )+(SELECT count(*) FROM inbox where \ - toaddress = '{0}' and folder != 'trash') AS SumCount".format( + "SELECT (SELECT count(*) FROM sent where fromaddress = '{0}' \ + and folder = 'sent' )+(SELECT count(*) FROM inbox where \ + toaddress = '{0}' and folder != 'trash') AS SumCount".format( state.association))[0][0]) return state.all_count @@ -1278,6 +1295,7 @@ class GrashofPopup(Popup): self.parent.children[1].ids.scr_mngr.current = 'addressbook' toast('Saved') + # pylint: disable=attribute-defined-outside-init def show_error_message(self): """Showing error message.""" content = MDLabel( @@ -1386,7 +1404,8 @@ class MailDetail(Screen): """Assigning mail details.""" self.to_addr = data[0][0] self.from_addr = data[0][1] - self.subject = data[0][2].upper() if data[0][2].upper() else '(no subject)' + self.subject = data[0][2].upper( + ) if data[0][2].upper() else '(no subject)' self.message = data[0][3] if len(data[0]) == 6: self.status = data[0][4] @@ -1439,13 +1458,15 @@ class MailDetail(Screen): pass def write_msg(self): - """This method is used to write on draft mail.""" + """Method used to write on draft mail.""" state.send_draft_mail = state.sentMailTime - composer_ids = self.parent.parent.parent.parent.parent.ids.sc3.children[0].ids + composer_ids = \ + self.parent.parent.parent.parent.parent.ids.sc3.children[0].ids composer_ids.ti.text = self.from_addr composer_ids.btn.text = self.from_addr composer_ids.txt_input.text = self.to_addr - composer_ids.subject.text = '' if self.subject == '(no subject)' else self.subject.lower() + composer_ids.subject.text = '' \ + if self.subject == '(no subject)' else self.subject.lower() composer_ids.body.text = self.message self.parent.parent.current = 'create' @@ -1635,6 +1656,7 @@ class Draft(Screen): self.ids.ml.add_widget(content) def draft_detail(self, lastsenttime, *args): + """Method used to show draft Details.""" state.detailPageType = 'draft' state.sentMailTime = lastsenttime if self.manager: @@ -1668,6 +1690,7 @@ class Draft(Screen): self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') + # pylint: disable=unused-variable @staticmethod def draft_msg(src_object): """Method used for saving draft mails.""" @@ -1815,9 +1838,9 @@ class Allmails(Screen): valign='top') self.ids.ml.add_widget(content) + # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): - """Method updates the state of application, \ - While the spinner remains on the screen.""" + """Method updates the state of application, While the spinner remains on the screen.""" def refresh_callback(interval): """Method used for loading the allmails screen data.""" self.ids.ml.clear_widgets() From 1351080e49ace5349c7a10e708e93d82615c2587 Mon Sep 17 00:00:00 2001 From: Navjot Date: Thu, 22 Aug 2019 21:07:50 +0530 Subject: [PATCH 044/306] fixed issues with draft mail and trash mail listing --- src/bitmessagekivy/main.kv | 2 +- src/bitmessagekivy/mpybit.py | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index adbcb0e9..29dc2691 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -372,7 +372,7 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - on_press: root.send() + on_press: root.send(app) MDLabel: font_style: 'Title' text: 'send' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a5ab9d31..6c92d518 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -459,7 +459,7 @@ class DropDownWidget(BoxLayout): txt_input = ObjectProperty() rv = ObjectProperty() - def send(self): + def send(self, navApp): """Send message from one address to another.""" # pylint: disable=too-many-locals fromAddress = str(self.ids.ti.text) @@ -533,6 +533,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.current = 'inbox' self.ids.btn.text = 'select' self.ids.ti.text = '' + navApp.back_press() toast('send') return None else: @@ -888,12 +889,11 @@ class Trash(Screen): for item in trash_data: meny = ThreeLineAvatarIconListItem( - text='Draft' if item[4] == 'draft' else item[1], - secondary_text=item[2] if item[2] else item[1], + text=item[1], + secondary_text=item[2], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/avatar.png' if item[ - 4] == 'draft' else './images/text_images/{}.png'.format( + img_latter = './images/text_images/{}.png'.format( item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget(source=img_latter)) @@ -992,7 +992,7 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" address_label = self.current_address_label( - BMConfigParser().get(text, 'label')) + BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label state.association = text self.root.ids.sc1.clear_widgets() @@ -1171,16 +1171,19 @@ class NavigateApp(App): return state.all_count @staticmethod - def current_address_label(current_address=None): + def current_address_label(current_add_label = None, current_addr = None): """Getting current address labels.""" - if BMConfigParser().addresses() or current_address: - if current_address: - first_name = current_address + if BMConfigParser().addresses(): + if current_add_label: + first_name = current_add_label + addr = current_addr else: - first_name = BMConfigParser().get( - BMConfigParser().addresses()[0], 'label') + addr = BMConfigParser().addresses()[0] + first_name = BMConfigParser().get(addr, 'label') f_name = first_name.split() - return f_name[0][:14] + '...' if len(f_name[0]) > 15 else f_name[0] + label = f_name[0][:14].capitalize() + '...' if len(f_name[0]) > 15 else f_name[0].capitalize() + address = ' (' + addr[:6] + '...)' + return label + address return '' def searchQuery(self, instance, *args): @@ -1643,11 +1646,11 @@ class Draft(Screen): int(state.draft_count) - 1) msg_count_objs.allmail_cnt.badge_text = str( int(state.all_count) - 1) - msg_count_objs.trash_cnt.badge_text = str( - int(state.trash_count) + 1) + # msg_count_objs.trash_cnt.badge_text = str( + # int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) state.all_count = str(int(state.all_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) + # state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') From ecbb144ee4419b6644f726429da24c2a7cf615e6 Mon Sep 17 00:00:00 2001 From: Navjot Date: Fri, 23 Aug 2019 15:56:35 +0530 Subject: [PATCH 045/306] fixed issues --- src/bitmessagekivy/main.kv | 2 +- src/bitmessagekivy/mpybit.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 29dc2691..08847957 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -828,7 +828,7 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() if root.page_type == 'sent' else root.write_msg() + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() if root.page_type == 'sent' else root.write_msg(app) MDLabel: font_style: 'Title' text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 11f65e78..a0983585 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -494,7 +494,8 @@ class DropDownWidget(BoxLayout): state.send_draft_mail)) self.parent.parent.screens[15].clear_widgets() self.parent.parent.screens[15].add_widget(Draft()) - state.detailPageType = 'draft' + state.detailPageType = '' + state.send_draft_mail = None else: from addresses import addBMIfNotPresent toAddress = addBMIfNotPresent(toAddress) @@ -1139,6 +1140,7 @@ class NavigateApp(App): composer_obj.btn.text = 'Select' composer_obj.txt_input.text = '' composer_obj.subject.text = '' + composer_obj.body.text = '' def back_press(self): """Method used for going back from composer to previous page.""" @@ -1150,6 +1152,7 @@ class NavigateApp(App): self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) self.add_search_bar() + state.detailPageType = '' @staticmethod def on_stop(): @@ -1457,7 +1460,7 @@ class MailDetail(Screen): """Method used for copying sent mail to the composer.""" pass - def write_msg(self): + def write_msg(self, navApp): """Method used to write on draft mail.""" state.send_draft_mail = state.sentMailTime composer_ids = \ @@ -1469,6 +1472,7 @@ class MailDetail(Screen): if self.subject == '(no subject)' else self.subject.lower() composer_ids.body.text = self.message self.parent.parent.current = 'create' + navApp.clear_composer() class MyaddDetailPopup(Popup): From d6f006198c66d9211470ca69a0cf1f9f2b2cef30 Mon Sep 17 00:00:00 2001 From: Navjot Date: Mon, 26 Aug 2019 20:58:12 +0530 Subject: [PATCH 046/306] worked on all mail detail page functionality --- src/bitmessagekivy/mpybit.py | 86 ++++++++++++++++++++++++++++++++---- src/state.py | 4 +- 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index a0983585..66583d21 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -539,6 +539,7 @@ class DropDownWidget(BoxLayout): self.parent.parent.screens[16].clear_widgets() self.parent.parent.screens[16].add_widget(Allmails()) toLabel = '' + queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" self.ids.body.text = '' @@ -1130,10 +1131,7 @@ class NavigateApp(App): def clear_composer(self): """If slow down the nwe will make new composer edit screen.""" - self.root.ids.toolbar.left_action_items = [ - ['arrow-left', lambda x: self.back_press()]] - self.root.ids.myButton.opacity = 0 - self.root.ids.myButton.disabled = True + self.set_navbar_for_composer() self.root.ids.search_bar.clear_widgets() composer_obj = self.root.ids.sc3.children[0].ids composer_obj.ti.text = '' @@ -1142,6 +1140,13 @@ class NavigateApp(App): composer_obj.subject.text = '' composer_obj.body.text = '' + def set_navbar_for_composer(self): + """This method is used for clearing toolbar data when composer open""" + self.root.ids.toolbar.left_action_items = [ + ['arrow-left', lambda x: self.back_press()]] + self.root.ids.myButton.opacity = 0 + self.root.ids.myButton.disabled = True + def back_press(self): """Method used for going back from composer to previous page.""" self.root.ids.myButton.opacity = 1 @@ -1425,7 +1430,6 @@ class MailDetail(Screen): state.sent_count = str(int(state.sent_count) - 1) self.parent.parent.screens[3].clear_widgets() self.parent.parent.screens[3].add_widget(Sent()) - self.parent.parent.current = 'sent' elif state.detailPageType == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ @@ -1435,7 +1439,11 @@ class MailDetail(Screen): state.inbox_count = str(int(state.inbox_count) - 1) self.parent.parent.screens[0].clear_widgets() self.parent.parent.screens[0].add_widget(Inbox()) - self.parent.parent.current = 'inbox' + if state.is_allmail: + self.parent.parent.current = 'allmails' + state.is_allmail = False + else: + self.parent.parent.current = state.detailPageType msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) @@ -1472,7 +1480,7 @@ class MailDetail(Screen): if self.subject == '(no subject)' else self.subject.lower() composer_ids.body.text = self.message self.parent.parent.current = 'create' - navApp.clear_composer() + navApp.set_navbar_for_composer() class MyaddDetailPopup(Popup): @@ -1792,11 +1800,11 @@ class Allmails(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox, Sent anf Draft list of messages.""" inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from\ + "SELECT toaddress, fromaddress, subject, message, folder, received from\ inbox WHERE folder = 'inbox' and toaddress = '{}';".format( account)) sent_and_draft = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from sent \ + "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from sent \ WHERE folder = 'sent' and fromaddress = '{}';".format( account)) @@ -1815,6 +1823,8 @@ class Allmails(Screen): 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget( source=img_latter)) + meny.bind(on_press=partial( + self.mail_detail, item[5], item[4])) carousel = Carousel(direction='right') if platform == 'android': carousel.height = 150 @@ -1827,6 +1837,8 @@ class Allmails(Screen): del_btn = Button(text='Delete') del_btn.background_normal = '' del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.bind(on_press=partial( + self.swipe_delete, item[5], item[4])) carousel.add_widget(del_btn) carousel.add_widget(meny) carousel.index = 1 @@ -1842,6 +1854,62 @@ class Allmails(Screen): valign='top') self.ids.ml.add_widget(content) + def mail_detail(self, unique_id, folder, *args): + """Load sent and inbox mail details.""" + remove_search_bar(self) + state.detailPageType = folder + state.is_allmail = True + state.sentMailTime = unique_id + if self.manager: + src_mng_obj = self.manager + else: + src_mng_obj = self.parent.parent + src_mng_obj.screens[13].clear_widgets() + src_mng_obj.screens[13].add_widget(MailDetail()) + src_mng_obj.current = 'mailDetail' + + def swipe_delete(self, unique_id, folder, instance, *args): + """Delete inbox mail from all mail listing listing.""" + if folder == 'inbox': + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE received = {};".format( + unique_id)) + else: + sqlExecute( + "UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format( + unique_id)) + self.ids.ml.remove_widget(instance.parent.parent) + try: + msg_count_objs = self.parent.parent.parent.parent.children[ + 2].children[0].ids + nav_lay_obj = self.parent.parent.parent.parent.ids + except Exception: + msg_count_objs = self.parent.parent.parent.parent.parent.children[ + 2].children[0].ids + nav_lay_obj = self.parent.parent.parent.parent.parent.ids + if folder == 'inbox': + msg_count_objs.inbox_cnt.badge_text = str( + int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) + nav_lay_obj.sc1.clear_widgets() + nav_lay_obj.sc1.add_widget(Inbox()) + else: + msg_count_objs.send_cnt.badge_text = str( + int(state.sent_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) + nav_lay_obj.sc4.clear_widgets() + nav_lay_obj.sc4.add_widget(Sent()) + msg_count_objs.trash_cnt.badge_text = str( + int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str( + int(state.all_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) + nav_lay_obj.sc5.clear_widgets() + nav_lay_obj.sc5.add_widget(Trash()) + nav_lay_obj.sc17.clear_widgets() + nav_lay_obj.sc17.add_widget(Allmails()) + # pylint: disable=attribute-defined-outside-init def refresh_callback(self, *args): """Method updates the state of application, While the spinner remains on the screen.""" diff --git a/src/state.py b/src/state.py index 2fc10ca2..c3e71382 100644 --- a/src/state.py +++ b/src/state.py @@ -104,4 +104,6 @@ searcing_text = '' search_screen = '' -send_draft_mail = None \ No newline at end of file +send_draft_mail = None + +is_allmail = False \ No newline at end of file From bc320ba2d75419a00f59eb98c96722d1c27b37fa Mon Sep 17 00:00:00 2001 From: Navjot Date: Mon, 26 Aug 2019 21:06:44 +0530 Subject: [PATCH 047/306] fixed issues --- src/bitmessagekivy/mpybit.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 66583d21..ca82f405 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1450,6 +1450,8 @@ class MailDetail(Screen): state.all_count = str(int(state.all_count) - 1) self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + self.parent.parent.screens[16].clear_widgets() + self.parent.parent.screens[16].add_widget(Allmails()) toast('Deleted') def inbox_reply(self): From 2e0f7755c609a9209d3ae3c46da9a769e4cf9ea4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 26 Aug 2019 17:46:25 +0200 Subject: [PATCH 048/306] Blind signature support in pyelliptic - add blind signature functionality to pyelliptic as described in #1409 - add tests for blind signatures - PEP8 fixes for pyelliptic - some minor refactoring is necessary for further integration, this is just a minimal implementation to pass a test --- src/pyelliptic/__init__.py | 12 +- src/pyelliptic/cipher.py | 2 +- src/pyelliptic/ecc.py | 6 +- src/pyelliptic/eccblind.py | 179 ++++++++++++++++++++++++++++++ src/pyelliptic/hash.py | 2 +- src/pyelliptic/openssl.py | 222 ++++++++++++++++++++++++++++++------- src/tests/test_blindsig.py | 22 ++++ 7 files changed, 394 insertions(+), 51 deletions(-) create mode 100644 src/pyelliptic/eccblind.py create mode 100644 src/tests/test_blindsig.py diff --git a/src/pyelliptic/__init__.py b/src/pyelliptic/__init__.py index 761d08af..1d6a928f 100644 --- a/src/pyelliptic/__init__.py +++ b/src/pyelliptic/__init__.py @@ -2,18 +2,20 @@ # Author: Yann GUIBET # Contact: +from .openssl import OpenSSL +from .ecc import ECC +from .eccblind import ECCBlind +from .cipher import Cipher +from .hash import hmac_sha256, hmac_sha512, pbkdf2 + __version__ = '1.3' __all__ = [ 'OpenSSL', 'ECC', + 'ECCBlind', 'Cipher', 'hmac_sha256', 'hmac_sha512', 'pbkdf2' ] - -from .openssl import OpenSSL -from .ecc import ECC -from .cipher import Cipher -from .hash import hmac_sha256, hmac_sha512, pbkdf2 diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index b597cafa..bc1af6b0 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -4,7 +4,7 @@ # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. -from pyelliptic.openssl import OpenSSL +from openssl import OpenSSL class Cipher: diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index fb0d6773..2de0bfe9 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -12,9 +12,9 @@ src/pyelliptic/ecc.py from hashlib import sha512 from struct import pack, unpack -from pyelliptic.cipher import Cipher -from pyelliptic.hash import equals, hmac_sha256 -from pyelliptic.openssl import OpenSSL +from cipher import Cipher +from hash import equals, hmac_sha256 +from openssl import OpenSSL class ECC(object): diff --git a/src/pyelliptic/eccblind.py b/src/pyelliptic/eccblind.py new file mode 100644 index 00000000..f8b43da5 --- /dev/null +++ b/src/pyelliptic/eccblind.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +""" +ECC blind signature functionality based on "An Efficient Blind Signature Scheme +Based on the Elliptic CurveDiscrete Logarithm Problem" by Morteza Nikooghadama + and Ali Zakerolhosseini , +http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf +""" + +# variable names are based on the math in the paper, so they don't conform +# to PEP8 +# pylint: disable=invalid-name + +from .openssl import OpenSSL + + +class ECCBlind(object): # pylint: disable=too-many-instance-attributes + """ + Class for ECC blind signature functionality + """ + + # init + k = None + R = None + keypair = None + F = None + Q = None + a = None + b = None + c = None + binv = None + r = None + m = None + m_ = None + s_ = None + signature = None + + @staticmethod + def ec_get_random(group, ctx): + """ + Random point from finite field + """ + order = OpenSSL.BN_new() + OpenSSL.EC_GROUP_get_order(group, order, ctx) + OpenSSL.BN_rand(order, OpenSSL.BN_num_bits(order), 0, 0) + return order + + @staticmethod + def ec_invert(group, a, ctx): + """ + ECC inversion + """ + order = OpenSSL.BN_new() + OpenSSL.EC_GROUP_get_order(group, order, ctx) + inverse = OpenSSL.BN_mod_inverse(0, a, order, ctx) + return inverse + + @staticmethod + def ec_gen_keypair(group, ctx): + """ + Generate an ECC keypair + """ + d = ECCBlind.ec_get_random(group, ctx) + Q = OpenSSL.EC_POINT_new(group) + OpenSSL.EC_POINT_mul(group, Q, d, 0, 0, 0) + return (d, Q) + + def __init__(self, curve="secp256k1"): + self.group = OpenSSL.EC_GROUP_new_by_curve_name(OpenSSL.get_curve(curve)) + self.ctx = OpenSSL.BN_CTX_new() + + # Order n + self.n = OpenSSL.BN_new() + OpenSSL.EC_GROUP_get_order(self.group, self.n, self.ctx) + + # Identity O (infinity) + self.iO = OpenSSL.EC_POINT_new(self.group) + OpenSSL.EC_POINT_set_to_infinity(self.group, self.iO) + + # Generator G + self.G = OpenSSL.EC_GROUP_get0_generator(self.group) + + # Certifier's pubkey + self.pubkey = (self.group, self.G, self.n) + + def signer_init(self): + """ + Init signer + """ + # Signer: Random integer k + self.k = ECCBlind.ec_get_random(self.group, self.ctx) + + # R = kG + self.R = OpenSSL.EC_POINT_new(self.group) + OpenSSL.EC_POINT_mul(self.group, self.R, self.k, 0, 0, 0) + + def create_signing_request(self, msg): + """ + Requester creates a new signing request + """ + # new keypair + self.keypair = ECCBlind.ec_gen_keypair(self.group, self.ctx) + + # Requester: 3 random blinding factors + self.F = OpenSSL.EC_POINT_new(self.group) + OpenSSL.EC_POINT_set_to_infinity(self.group, self.F) + temp = OpenSSL.EC_POINT_new(self.group) + self.Q = self.keypair[1] + abinv = OpenSSL.BN_new() + + # F != O + while OpenSSL.EC_POINT_cmp(self.group, self.F, self.iO, self.ctx) == 0: + self.a = ECCBlind.ec_get_random(self.group, self.ctx) + self.b = ECCBlind.ec_get_random(self.group, self.ctx) + self.c = ECCBlind.ec_get_random(self.group, self.ctx) + + # F = b^-1 * R... + self.binv = ECCBlind.ec_invert(self.group, self.b, self.ctx) + OpenSSL.EC_POINT_mul(self.group, temp, 0, self.R, self.binv, 0) + OpenSSL.EC_POINT_copy(self.F, temp) + + # ... + a*b^-1 * Q... + OpenSSL.BN_mul(abinv, self.a, self.binv, self.ctx) + OpenSSL.EC_POINT_mul(self.group, temp, 0, self.Q, abinv, 0) + OpenSSL.EC_POINT_add(self.group, self.F, self.F, temp, 0) + + # ... + c*G + OpenSSL.EC_POINT_mul(self.group, temp, 0, self.G, self.c, 0) + OpenSSL.EC_POINT_add(self.group, self.F, self.F, temp, 0) + + # F = (x0, y0) + x0 = OpenSSL.BN_new() + y0 = OpenSSL.BN_new() + OpenSSL.EC_POINT_get_affine_coordinates_GFp(self.group, self.F, x0, y0, + self.ctx) + self.r = x0 + + # Requester: Blinding (m' = br(m) + a) + self.m = OpenSSL.BN_new() + OpenSSL.BN_bin2bn(msg, len(msg), self.m) + + self.m_ = OpenSSL.BN_new() + OpenSSL.BN_mod_mul(self.m_, self.b, self.r, self.n, self.ctx) + OpenSSL.BN_mod_mul(self.m_, self.m_, self.m, self.n, self.ctx) + OpenSSL.BN_mod_add(self.m_, self.m_, self.a, self.n, self.ctx) + + def blind_sign(self): + """ + Signer blind-signs the request + """ + self.s_ = OpenSSL.BN_new() + OpenSSL.BN_mod_mul(self.s_, self.keypair[0], self.m_, self.n, self.ctx) + OpenSSL.BN_mod_add(self.s_, self.s_, self.k, self.n, self.ctx) + + def unblind(self): + """ + Requester unblinds the signature + """ + s = OpenSSL.BN_new() + OpenSSL.BN_mod_mul(s, self.binv, self.s_, self.n, self.ctx) + OpenSSL.BN_mod_add(s, s, self.c, self.n, self.ctx) + self.signature = (s, self.F) + + def verify(self): + """ + Verify signature with certifier's pubkey + """ + lhs = OpenSSL.EC_POINT_new(self.group) + rhs = OpenSSL.EC_POINT_new(self.group) + + OpenSSL.EC_POINT_mul(self.group, lhs, self.signature[0], 0, 0, 0) + OpenSSL.EC_POINT_mul(self.group, rhs, 0, self.Q, self.m, 0) + OpenSSL.EC_POINT_mul(self.group, rhs, 0, rhs, self.r, 0) + OpenSSL.EC_POINT_add(self.group, rhs, rhs, self.F, self.ctx) + + retval = OpenSSL.EC_POINT_cmp(self.group, lhs, rhs, self.ctx) + if retval == -1: + raise RuntimeError("EC_POINT_cmp returned an error") + else: + return retval == 0 diff --git a/src/pyelliptic/hash.py b/src/pyelliptic/hash.py index fb910dd4..f2240500 100644 --- a/src/pyelliptic/hash.py +++ b/src/pyelliptic/hash.py @@ -4,7 +4,7 @@ # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. -from pyelliptic.openssl import OpenSSL +from openssl import OpenSSL # For python3 diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 115bdc08..ab2990e6 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -19,7 +19,9 @@ class CipherName: self._blocksize = blocksize def __str__(self): - return "Cipher : " + self._name + " | Blocksize : " + str(self._blocksize) + " | Fonction pointer : " + str(self._pointer) + return "Cipher : " + self._name + \ + " | Blocksize : " + str(self._blocksize) + \ + " | Function pointer : " + str(self._pointer) def get_pointer(self): return self._pointer() @@ -36,7 +38,7 @@ def get_version(library): hexversion = None cflags = None try: - #OpenSSL 1.1 + # OpenSSL 1.1 OPENSSL_VERSION = 0 OPENSSL_CFLAGS = 1 library.OpenSSL_version.argtypes = [ctypes.c_int] @@ -47,7 +49,7 @@ def get_version(library): hexversion = library.OpenSSL_version_num() except AttributeError: try: - #OpenSSL 1.0 + # OpenSSL 1.0 SSLEAY_VERSION = 0 SSLEAY_CFLAGS = 2 library.SSLeay.restype = ctypes.c_long @@ -57,7 +59,7 @@ def get_version(library): cflags = library.SSLeay_version(SSLEAY_CFLAGS) hexversion = library.SSLeay() except AttributeError: - #raise NotImplementedError('Cannot determine version of this OpenSSL library.') + # raise NotImplementedError('Cannot determine version of this OpenSSL library.') pass return (version, hexversion, cflags) @@ -130,7 +132,11 @@ class _OpenSSL: self.EC_POINT_get_affine_coordinates_GFp = self._lib.EC_POINT_get_affine_coordinates_GFp self.EC_POINT_get_affine_coordinates_GFp.restype = ctypes.c_int - self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key self.EC_KEY_set_private_key.restype = ctypes.c_int @@ -144,11 +150,16 @@ class _OpenSSL: self.EC_KEY_set_group = self._lib.EC_KEY_set_group self.EC_KEY_set_group.restype = ctypes.c_int - self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] self.EC_POINT_set_affine_coordinates_GFp = self._lib.EC_POINT_set_affine_coordinates_GFp self.EC_POINT_set_affine_coordinates_GFp.restype = ctypes.c_int - self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] self.EC_POINT_new = self._lib.EC_POINT_new self.EC_POINT_new.restype = ctypes.c_void_p @@ -164,7 +175,11 @@ class _OpenSSL: self.EC_POINT_mul = self._lib.EC_POINT_mul self.EC_POINT_mul.restype = None - self.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + self.EC_POINT_mul.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key self.EC_KEY_set_private_key.restype = ctypes.c_int @@ -175,10 +190,11 @@ class _OpenSSL: self.EC_KEY_OpenSSL = self._lib.EC_KEY_OpenSSL self._lib.EC_KEY_OpenSSL.restype = ctypes.c_void_p self._lib.EC_KEY_OpenSSL.argtypes = [] - + self.EC_KEY_set_method = self._lib.EC_KEY_set_method self._lib.EC_KEY_set_method.restype = ctypes.c_int - self._lib.EC_KEY_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self._lib.EC_KEY_set_method.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] else: self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p @@ -186,7 +202,8 @@ class _OpenSSL: self.ECDH_set_method = self._lib.ECDH_set_method self._lib.ECDH_set_method.restype = ctypes.c_int - self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] self.BN_CTX_new = self._lib.BN_CTX_new self._lib.BN_CTX_new.restype = ctypes.c_void_p @@ -195,12 +212,15 @@ class _OpenSSL: self.ECDH_compute_key = self._lib.ECDH_compute_key self.ECDH_compute_key.restype = ctypes.c_int self.ECDH_compute_key.argtypes = [ctypes.c_void_p, - ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] + ctypes.c_int, + ctypes.c_void_p, + ctypes.c_void_p] self.EVP_CipherInit_ex = self._lib.EVP_CipherInit_ex self.EVP_CipherInit_ex.restype = ctypes.c_int self.EVP_CipherInit_ex.argtypes = [ctypes.c_void_p, - ctypes.c_void_p, ctypes.c_void_p] + ctypes.c_void_p, + ctypes.c_void_p] self.EVP_CIPHER_CTX_new = self._lib.EVP_CIPHER_CTX_new self.EVP_CIPHER_CTX_new.restype = ctypes.c_void_p @@ -223,13 +243,13 @@ class _OpenSSL: self.EVP_aes_256_cbc.restype = ctypes.c_void_p self.EVP_aes_256_cbc.argtypes = [] - #self.EVP_aes_128_ctr = self._lib.EVP_aes_128_ctr - #self.EVP_aes_128_ctr.restype = ctypes.c_void_p - #self.EVP_aes_128_ctr.argtypes = [] + # self.EVP_aes_128_ctr = self._lib.EVP_aes_128_ctr + # self.EVP_aes_128_ctr.restype = ctypes.c_void_p + # self.EVP_aes_128_ctr.argtypes = [] - #self.EVP_aes_256_ctr = self._lib.EVP_aes_256_ctr - #self.EVP_aes_256_ctr.restype = ctypes.c_void_p - #self.EVP_aes_256_ctr.argtypes = [] + # self.EVP_aes_256_ctr = self._lib.EVP_aes_256_ctr + # self.EVP_aes_256_ctr.restype = ctypes.c_void_p + # self.EVP_aes_256_ctr.argtypes = [] self.EVP_aes_128_ofb = self._lib.EVP_aes_128_ofb self.EVP_aes_128_ofb.restype = ctypes.c_void_p @@ -250,7 +270,7 @@ class _OpenSSL: self.EVP_rc4 = self._lib.EVP_rc4 self.EVP_rc4.restype = ctypes.c_void_p self.EVP_rc4.argtypes = [] - + if self._hexversion >= 0x10100000 and not self._libreSSL: self.EVP_CIPHER_CTX_reset = self._lib.EVP_CIPHER_CTX_reset self.EVP_CIPHER_CTX_reset.restype = ctypes.c_int @@ -281,7 +301,7 @@ class _OpenSSL: self.EVP_DigestInit_ex = self._lib.EVP_DigestInit_ex self.EVP_DigestInit_ex.restype = ctypes.c_int self._lib.EVP_DigestInit_ex.argtypes = 3 * [ctypes.c_void_p] - + self.EVP_DigestUpdate = self._lib.EVP_DigestUpdate self.EVP_DigestUpdate.restype = ctypes.c_int self.EVP_DigestUpdate.argtypes = [ctypes.c_void_p, @@ -296,7 +316,7 @@ class _OpenSSL: self.EVP_DigestFinal_ex.restype = ctypes.c_int self.EVP_DigestFinal_ex.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - + self.ECDSA_sign = self._lib.ECDSA_sign self.ECDSA_sign.restype = ctypes.c_int self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, @@ -311,7 +331,7 @@ class _OpenSSL: self.EVP_MD_CTX_new = self._lib.EVP_MD_CTX_new self.EVP_MD_CTX_new.restype = ctypes.c_void_p self.EVP_MD_CTX_new.argtypes = [] - + self.EVP_MD_CTX_reset = self._lib.EVP_MD_CTX_reset self.EVP_MD_CTX_reset.restype = None self.EVP_MD_CTX_reset.argtypes = [ctypes.c_void_p] @@ -329,11 +349,11 @@ class _OpenSSL: self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create self.EVP_MD_CTX_create.restype = ctypes.c_void_p self.EVP_MD_CTX_create.argtypes = [] - + self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init self.EVP_MD_CTX_init.restype = None self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p] - + self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy self.EVP_MD_CTX_destroy.restype = None self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p] @@ -370,13 +390,131 @@ class _OpenSSL: except: # The above is not compatible with all versions of OSX. self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC_SHA1 - + self.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int self.PKCS5_PBKDF2_HMAC.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] + # Blind signature requirements + self.BN_CTX_new = self._lib.BN_CTX_new + self.BN_CTX_new.restype = ctypes.c_void_p + self.BN_CTX_new.argtypes = [] + + self.BN_dup = self._lib.BN_dup + self.BN_dup.restype = ctypes.c_void_p + self.BN_dup.argtypes = [ctypes.c_void_p] + + self.BN_rand = self._lib.BN_rand + self.BN_rand.restype = ctypes.c_int + self.BN_rand.argtypes = [ctypes.c_void_p, + ctypes.c_int, + ctypes.c_int] + + self.BN_set_word = self._lib.BN_set_word + self.BN_set_word.restype = ctypes.c_int + self.BN_set_word.argtypes = [ctypes.c_void_p, + ctypes.c_ulong] + + self.BN_mul = self._lib.BN_mul + self.BN_mul.restype = ctypes.c_int + self.BN_mul.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.BN_mod_add = self._lib.BN_mod_add + self.BN_mod_add.restype = ctypes.c_int + self.BN_mod_add.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.BN_mod_inverse = self._lib.BN_mod_inverse + self.BN_mod_inverse.restype = ctypes.c_void_p + self.BN_mod_inverse.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.BN_mod_mul = self._lib.BN_mod_mul + self.BN_mod_mul.restype = ctypes.c_int + self.BN_mod_mul.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.BN_lshift = self._lib.BN_lshift + self.BN_lshift.restype = ctypes.c_int + self.BN_lshift.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_int] + + self.BN_sub_word = self._lib.BN_sub_word + self.BN_sub_word.restype = ctypes.c_int + self.BN_sub_word.argtypes = [ctypes.c_void_p, + ctypes.c_ulong] + + self.BN_cmp = self._lib.BN_cmp + self.BN_cmp.restype = ctypes.c_int + self.BN_cmp.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] + + self.BN_bn2dec = self._lib.BN_bn2dec + self.BN_bn2dec.restype = ctypes.c_char_p + self.BN_bn2dec.argtypes = [ctypes.c_void_p] + + self.BN_CTX_free = self._lib.BN_CTX_free + self.BN_CTX_free.argtypes = [ctypes.c_void_p] + + self.EC_GROUP_new_by_curve_name = self._lib.EC_GROUP_new_by_curve_name + self.EC_GROUP_new_by_curve_name.restype = ctypes.c_void_p + self.EC_GROUP_new_by_curve_name.argtypes = [ctypes.c_int] + + self.EC_GROUP_get_order = self._lib.EC_GROUP_get_order + self.EC_GROUP_get_order.restype = ctypes.c_int + self.EC_GROUP_get_order.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.EC_GROUP_get_cofactor = self._lib.EC_GROUP_get_cofactor + self.EC_GROUP_get_cofactor.restype = ctypes.c_int + self.EC_GROUP_get_cofactor.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.EC_GROUP_get0_generator = self._lib.EC_GROUP_get0_generator + self.EC_GROUP_get0_generator.restype = ctypes.c_void_p + self.EC_GROUP_get0_generator.argtypes = [ctypes.c_void_p] + + self.EC_POINT_copy = self._lib.EC_POINT_copy + self.EC_POINT_copy.restype = ctypes.c_int + self.EC_POINT_copy.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] + + self.EC_POINT_add = self._lib.EC_POINT_add + self.EC_POINT_add.restype = ctypes.c_int + self.EC_POINT_add.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.EC_POINT_cmp = self._lib.EC_POINT_cmp + self.EC_POINT_cmp.restype = ctypes.c_int + self.EC_POINT_cmp.argtypes = [ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_void_p] + + self.EC_POINT_set_to_infinity = self._lib.EC_POINT_set_to_infinity + self.EC_POINT_set_to_infinity.restype = ctypes.c_int + self.EC_POINT_set_to_infinity.argtypes = [ctypes.c_void_p, + ctypes.c_void_p] + self._set_ciphers() self._set_curves() @@ -388,11 +526,11 @@ class _OpenSSL: 'aes-256-cfb': CipherName('aes-256-cfb', self.EVP_aes_256_cfb128, 16), 'aes-128-ofb': CipherName('aes-128-ofb', self._lib.EVP_aes_128_ofb, 16), 'aes-256-ofb': CipherName('aes-256-ofb', self._lib.EVP_aes_256_ofb, 16), - #'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), - #'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), + # 'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), + # 'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), 'bf-cfb': CipherName('bf-cfb', self.EVP_bf_cfb64, 8), 'bf-cbc': CipherName('bf-cbc', self.EVP_bf_cbc, 8), - 'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size + 'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size } def _set_curves(self): @@ -470,11 +608,11 @@ class _OpenSSL: OpenSSL random function """ buffer = self.malloc(0, size) - # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is + # This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is # evidently possible that it returned an error and not-actually-random data. However, in - # tests on various operating systems, while generating hundreds of gigabytes of random + # tests on various operating systems, while generating hundreds of gigabytes of random # strings of various sizes I could not get an error to occur. Also Bitcoin doesn't check - # the return value of RAND_bytes either. + # the return value of RAND_bytes either. # Fixed in Bitmessage version 0.4.2 (in source code on 2013-10-13) while self.RAND_bytes(buffer, size) != 1: import time @@ -494,22 +632,23 @@ class _OpenSSL: buffer = self.create_string_buffer(size) return buffer + def loadOpenSSL(): global OpenSSL from os import path, environ from ctypes.util import find_library - + libdir = [] - if getattr(sys,'frozen', None): + if getattr(sys, 'frozen', None): if 'darwin' in sys.platform: libdir.extend([ - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.1.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.2.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.1.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.0.9.8.dylib'), - ]) + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.dylib'), + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.1.0.dylib'), + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.2.dylib'), + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.1.dylib'), + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.1.0.0.dylib'), + path.join(environ['RESOURCEPATH'], '..', 'Frameworks', 'libcrypto.0.9.8.dylib'), + ]) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append(path.join(sys._MEIPASS, 'libeay32.dll')) else: @@ -548,4 +687,5 @@ def loadOpenSSL(): pass raise Exception("Couldn't find and load the OpenSSL library. You must install it.") + loadOpenSSL() diff --git a/src/tests/test_blindsig.py b/src/tests/test_blindsig.py new file mode 100644 index 00000000..737ee485 --- /dev/null +++ b/src/tests/test_blindsig.py @@ -0,0 +1,22 @@ +""" +Test for ECC blind signatures +""" +import os +import unittest + +from src.pyelliptic.eccblind import ECCBlind + + +class TestBlindSig(unittest.TestCase): + """ + Test case for ECC blind signature + """ + def test_blind_sig(self): + """Test full sequence using a random certifier key and a random message""" + blind_sig = ECCBlind() + blind_sig.signer_init() + msg = os.urandom(64) + blind_sig.create_signing_request(msg) + blind_sig.blind_sign() + blind_sig.unblind() + self.assertTrue(blind_sig.verify()) From 076aeaa19f559569b2c2b68b688ae322c5acd1bf Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 27 Aug 2019 12:42:28 +0200 Subject: [PATCH 049/306] Import path changes as requested --- src/tests/test_blindsig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/test_blindsig.py b/src/tests/test_blindsig.py index 737ee485..4aaf8660 100644 --- a/src/tests/test_blindsig.py +++ b/src/tests/test_blindsig.py @@ -4,7 +4,7 @@ Test for ECC blind signatures import os import unittest -from src.pyelliptic.eccblind import ECCBlind +from pybitmessage.pyelliptic.eccblind import ECCBlind class TestBlindSig(unittest.TestCase): From b934c4e01e26f29848f810a69a3c853756d50fc9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 27 Aug 2019 23:11:42 +0200 Subject: [PATCH 050/306] Minor refactoring to separate objects --- src/pyelliptic/eccblind.py | 79 ++++++++++++++++++++++++++------------ src/tests/test_blindsig.py | 25 +++++++++--- 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/pyelliptic/eccblind.py b/src/pyelliptic/eccblind.py index f8b43da5..2ca2581a 100644 --- a/src/pyelliptic/eccblind.py +++ b/src/pyelliptic/eccblind.py @@ -64,24 +64,43 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes OpenSSL.EC_POINT_mul(group, Q, d, 0, 0, 0) return (d, Q) - def __init__(self, curve="secp256k1"): - self.group = OpenSSL.EC_GROUP_new_by_curve_name(OpenSSL.get_curve(curve)) + @staticmethod + def ec_Ftor(F, group, ctx): + """ + x0 coordinate of F + """ + # F = (x0, y0) + x0 = OpenSSL.BN_new() + y0 = OpenSSL.BN_new() + OpenSSL.EC_POINT_get_affine_coordinates_GFp(group, F, x0, y0, + ctx) + return x0 + + def __init__(self, curve="secp256k1", pubkey=None): self.ctx = OpenSSL.BN_CTX_new() - # Order n - self.n = OpenSSL.BN_new() - OpenSSL.EC_GROUP_get_order(self.group, self.n, self.ctx) + if pubkey: + self.group, self.G, self.n, self.Q = pubkey + else: + self.group = OpenSSL.EC_GROUP_new_by_curve_name(OpenSSL.get_curve(curve)) + # Order n + self.n = OpenSSL.BN_new() + OpenSSL.EC_GROUP_get_order(self.group, self.n, self.ctx) + + # Generator G + self.G = OpenSSL.EC_GROUP_get0_generator(self.group) + + # new keypair + self.keypair = ECCBlind.ec_gen_keypair(self.group, self.ctx) + + self.Q = self.keypair[1] + + self.pubkey = (self.group, self.G, self.n, self.Q) # Identity O (infinity) self.iO = OpenSSL.EC_POINT_new(self.group) OpenSSL.EC_POINT_set_to_infinity(self.group, self.iO) - # Generator G - self.G = OpenSSL.EC_GROUP_get0_generator(self.group) - - # Certifier's pubkey - self.pubkey = (self.group, self.G, self.n) - def signer_init(self): """ Init signer @@ -93,18 +112,18 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes self.R = OpenSSL.EC_POINT_new(self.group) OpenSSL.EC_POINT_mul(self.group, self.R, self.k, 0, 0, 0) - def create_signing_request(self, msg): + return self.R + + def create_signing_request(self, R, msg): """ Requester creates a new signing request """ - # new keypair - self.keypair = ECCBlind.ec_gen_keypair(self.group, self.ctx) + self.R = R # Requester: 3 random blinding factors self.F = OpenSSL.EC_POINT_new(self.group) OpenSSL.EC_POINT_set_to_infinity(self.group, self.F) temp = OpenSSL.EC_POINT_new(self.group) - self.Q = self.keypair[1] abinv = OpenSSL.BN_new() # F != O @@ -128,11 +147,7 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes OpenSSL.EC_POINT_add(self.group, self.F, self.F, temp, 0) # F = (x0, y0) - x0 = OpenSSL.BN_new() - y0 = OpenSSL.BN_new() - OpenSSL.EC_POINT_get_affine_coordinates_GFp(self.group, self.F, x0, y0, - self.ctx) - self.r = x0 + self.r = ECCBlind.ec_Ftor(self.F, self.group, self.ctx) # Requester: Blinding (m' = br(m) + a) self.m = OpenSSL.BN_new() @@ -142,32 +157,48 @@ class ECCBlind(object): # pylint: disable=too-many-instance-attributes OpenSSL.BN_mod_mul(self.m_, self.b, self.r, self.n, self.ctx) OpenSSL.BN_mod_mul(self.m_, self.m_, self.m, self.n, self.ctx) OpenSSL.BN_mod_add(self.m_, self.m_, self.a, self.n, self.ctx) + return self.m_ - def blind_sign(self): + def blind_sign(self, m_): """ Signer blind-signs the request """ + self.m_ = m_ self.s_ = OpenSSL.BN_new() OpenSSL.BN_mod_mul(self.s_, self.keypair[0], self.m_, self.n, self.ctx) OpenSSL.BN_mod_add(self.s_, self.s_, self.k, self.n, self.ctx) + return self.s_ - def unblind(self): + def unblind(self, s_): """ Requester unblinds the signature """ + self.s_ = s_ s = OpenSSL.BN_new() OpenSSL.BN_mod_mul(s, self.binv, self.s_, self.n, self.ctx) OpenSSL.BN_mod_add(s, s, self.c, self.n, self.ctx) self.signature = (s, self.F) + return self.signature - def verify(self): + def verify(self, msg, signature): """ Verify signature with certifier's pubkey """ + + # convert msg to BIGNUM + self.m = OpenSSL.BN_new() + OpenSSL.BN_bin2bn(msg, len(msg), self.m) + + # init + s, self.F = signature + if self.r is None: + self.r = ECCBlind.ec_Ftor(self.F, self.group, self.ctx) + lhs = OpenSSL.EC_POINT_new(self.group) rhs = OpenSSL.EC_POINT_new(self.group) - OpenSSL.EC_POINT_mul(self.group, lhs, self.signature[0], 0, 0, 0) + OpenSSL.EC_POINT_mul(self.group, lhs, s, 0, 0, 0) + OpenSSL.EC_POINT_mul(self.group, rhs, 0, self.Q, self.m, 0) OpenSSL.EC_POINT_mul(self.group, rhs, 0, rhs, self.r, 0) OpenSSL.EC_POINT_add(self.group, rhs, rhs, self.F, self.ctx) diff --git a/src/tests/test_blindsig.py b/src/tests/test_blindsig.py index 4aaf8660..ad44af98 100644 --- a/src/tests/test_blindsig.py +++ b/src/tests/test_blindsig.py @@ -13,10 +13,23 @@ class TestBlindSig(unittest.TestCase): """ def test_blind_sig(self): """Test full sequence using a random certifier key and a random message""" - blind_sig = ECCBlind() - blind_sig.signer_init() + # See page 127 of the paper + # (1) Initialization + signer_obj = ECCBlind() + point_r = signer_obj.signer_init() + + # (2) Request + requester_obj = ECCBlind(pubkey=signer_obj.pubkey) + # only 64 byte messages are planned to be used in Bitmessage msg = os.urandom(64) - blind_sig.create_signing_request(msg) - blind_sig.blind_sign() - blind_sig.unblind() - self.assertTrue(blind_sig.verify()) + msg_blinded = requester_obj.create_signing_request(point_r, msg) + + # (3) Signature Generation + signature_blinded = signer_obj.blind_sign(msg_blinded) + + # (4) Extraction + signature = requester_obj.unblind(signature_blinded) + + # (5) Verification + verifier_obj = ECCBlind(pubkey=signer_obj.pubkey) + self.assertTrue(verifier_obj.verify(msg, signature)) From 395fbcd0f090fc389f7c1e7ac2fc8bb58a5ea4d7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 28 Aug 2019 13:21:44 +0200 Subject: [PATCH 051/306] Add intermediary tests - primitive serialisation (BN_bn2bin and ctypes) used in intermediary tests --- src/tests/test_blindsig.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tests/test_blindsig.py b/src/tests/test_blindsig.py index ad44af98..b8d0248a 100644 --- a/src/tests/test_blindsig.py +++ b/src/tests/test_blindsig.py @@ -3,8 +3,10 @@ Test for ECC blind signatures """ import os import unittest +from ctypes import cast, c_char_p from pybitmessage.pyelliptic.eccblind import ECCBlind +from pybitmessage.pyelliptic.openssl import OpenSSL class TestBlindSig(unittest.TestCase): @@ -24,12 +26,27 @@ class TestBlindSig(unittest.TestCase): msg = os.urandom(64) msg_blinded = requester_obj.create_signing_request(point_r, msg) + # check + msg_blinded_str = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(msg_blinded)) + OpenSSL.BN_bn2bin(msg_blinded, msg_blinded_str) + self.assertNotEqual(msg, cast(msg_blinded_str, c_char_p).value) + # (3) Signature Generation signature_blinded = signer_obj.blind_sign(msg_blinded) # (4) Extraction signature = requester_obj.unblind(signature_blinded) + # check + signature_blinded_str = OpenSSL.malloc(0, + OpenSSL.BN_num_bytes( + signature_blinded)) + signature_str = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(signature[0])) + OpenSSL.BN_bn2bin(signature_blinded, signature_blinded_str) + OpenSSL.BN_bn2bin(signature[0], signature_str) + self.assertNotEqual(cast(signature_str, c_char_p).value, + cast(signature_blinded_str, c_char_p).value) + # (5) Verification verifier_obj = ECCBlind(pubkey=signer_obj.pubkey) self.assertTrue(verifier_obj.verify(msg, signature)) From cc869d042665841c132a9e6282ebcc7c06e21fc3 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 29 Aug 2019 15:33:14 +0530 Subject: [PATCH 052/306] bitmessagemain flake8 Fixes --- src/bitmessagemain.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 90e15c52..5dcfea6c 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -87,10 +87,10 @@ def connectToStream(streamNumber): with knownnodes.knownNodesLock: if streamNumber not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber] = {} - if streamNumber*2 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2] = {} - if streamNumber*2+1 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2+1] = {} + if streamNumber * 2 not in knownnodes.knownNodes: + knownnodes.knownNodes[streamNumber * 2] = {} + if streamNumber * 2 + 1 not in knownnodes.knownNodes: + knownnodes.knownNodes[streamNumber * 2 + 1] = {} BMConnectionPool().connectToStream(streamNumber) @@ -419,8 +419,8 @@ class Main: if daemon: while state.shutdown == 0: time.sleep(1) - if (state.testmode and - time.time() - state.last_api_response >= 30): + if ( + state.testmode and time.time() - state.last_api_response >= 30): self.stop() elif not state.enableGUI: from tests import core as test_core # pylint: disable=relative-import From b48197ff0d6d1f91eebabfb70583c0608df48050 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 29 Aug 2019 16:32:14 +0530 Subject: [PATCH 053/306] build_osx file flake8 Fixes --- src/build_osx.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/build_osx.py b/src/build_osx.py index 1d8f470e..7ab74dc2 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,3 +1,4 @@ +"""Building osx.""" from glob import glob import os from PyQt4 import QtCore @@ -17,15 +18,15 @@ DATA_FILES = [ ] setup( - name = name, - version = version, - app = mainscript, - data_files = DATA_FILES, - setup_requires = ["py2app"], - options = dict( - py2app = dict( - includes = ['sip', 'PyQt4._qt'], - iconfile = "images/bitmessage.icns" + name=name, + version=version, + app=mainscript, + data_files=DATA_FILES, + setup_requires=["py2app"], + options=dict( + py2app=dict( + includes=['sip', 'PyQt4._qt'], + iconfile="images/bitmessage.icns" ) ) ) From 548fcf0d0a9f1005f730382f60e7aae0b6fdda20 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 29 Aug 2019 19:24:13 +0530 Subject: [PATCH 054/306] announcethread Flake8 Fixes --- src/network/announcethread.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index e7bec45a..b71ab496 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -29,5 +29,8 @@ class AnnounceThread(StoppableThread): if not connection.announcing: continue for stream in state.streamsInWhichIAmParticipating: - addr = (stream, state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), time.time()) + addr = ( + stream, + state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), + time.time()) connection.append_write_buf(BMProto.assembleAddr([addr])) From 469d289a971887ae3b389e43970202aad6460c53 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 29 Aug 2019 19:46:03 +0530 Subject: [PATCH 055/306] Announcethread Pylint Fixes --- src/network/announcethread.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index b71ab496..59fad128 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -1,3 +1,7 @@ +""" +src/network/announcethread.py +================================= +""" import time from bmconfigparser import BMConfigParser @@ -10,6 +14,7 @@ import state class AnnounceThread(StoppableThread): + """A thread to manage regular announcing of this node""" def __init__(self): super(AnnounceThread, self).__init__(name="Announcer") logger.info("init announce thread") @@ -24,7 +29,9 @@ class AnnounceThread(StoppableThread): if processed == 0: self.stop.wait(10) - def announceSelf(self): + @staticmethod + def announceSelf(): + """Announce our presence""" for connection in BMConnectionPool().udpSockets.values(): if not connection.announcing: continue From 5521c16478b922cb196b5a43abf9c2157d64ffc7 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 30 Aug 2019 16:12:39 +0530 Subject: [PATCH 056/306] bmproto pylint fixes --- src/network/bmproto.py | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index c8efe91e..0a2cdc7e 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -1,3 +1,8 @@ +""" +src/network/bmproto.py +================================== +""" +# pylint: disable=attribute-defined-outside-init import base64 import hashlib import socket @@ -43,6 +48,7 @@ class BMProtoExcessiveDataError(BMProtoError): class BMProto(AdvancedDispatcher, ObjectTracker): """A parser for the Bitmessage Protocol""" + # pylint: disable=too-many-instance-attributes, too-many-public-methods # ~1.6 MB which is the maximum possible size of an inv message. maxMessageSize = 1600100 # 2**18 = 256kB is the maximum size of an object payload @@ -57,7 +63,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): maxTimeOffset = 3600 timeOffsetWrongCount = 0 - def __init__(self, address=None, sock=None): + def __init__(self, address=None, sock=None): # pylint: disable=unused-argument, super-init-not-called AdvancedDispatcher.__init__(self, sock) self.isOutbound = False # packet/connection from a local IP @@ -97,7 +103,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): length=protocol.Header.size, expectBytes=self.payloadLength) return True - def state_bm_command(self): + def state_bm_command(self): # pylint: disable=too-many-branches """Process incoming command""" self.payload = self.read_buf[:self.payloadLength] if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: @@ -181,7 +187,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return Node(services, host, port) - def decode_payload_content(self, pattern="v"): + def decode_payload_content(self, pattern="v"): # pylint: disable=too-many-branches, too-many-statements + """ Decode the payload depending on pattern: @@ -197,7 +204,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): , = end of array """ - def decode_simple(self, char="v"): + def decode_simple(self, char="v"): # pylint: disable=inconsistent-return-statements """Decode the payload using one char pattern""" if char == "v": return self.decode_payload_varint() @@ -230,7 +237,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): while True: i = parserStack[-1][3][parserStack[-1][4]] if i in "0123456789" and ( - size is None or parserStack[-1][3][parserStack[-1][4] - 1] + size is None or parserStack[-1][3][parserStack[-1][4] - 1] not in "lL"): try: size = size * 10 + int(i) @@ -251,6 +258,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): for j in range(parserStack[-1][4], len(parserStack[-1][3])): if parserStack[-1][3][j] not in "lL0123456789": break + # pylint: disable=undefined-loop-variable parserStack.append([ size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j + 1], 0, [] @@ -422,16 +430,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def bm_command_addr(self): """Incoming addresses, process them""" - addresses = self._decode_addr() + addresses = self._decode_addr() # pylint: disable=redefined-outer-name for i in addresses: seenTime, stream, services, ip, port = i decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if ( - decodedIP and time.time() - seenTime > 0 and - seenTime > time.time() - BMProto.addressAlive and - port > 0 + decodedIP and time.time() - seenTime > 0 and + seenTime > time.time() - BMProto.addressAlive and + port > 0 ): peer = state.Peer(decodedIP, port) try: @@ -462,7 +470,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.append_write_buf(protocol.CreatePacket('pong')) return True - def bm_command_pong(self): + def bm_command_pong(self): # pylint: disable=no-self-use """ Incoming pong. Ignore it. PyBitmessage pings connections after about 5 minutes @@ -530,7 +538,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): length=self.payloadLength, expectBytes=0) return False - def peerValidityChecks(self): + def peerValidityChecks(self): # pylint: disable=too-many-return-statements """Check the validity of the peer""" if self.remoteProtocolVersion < 3: self.append_write_buf(protocol.assembleErrorMessage( @@ -584,12 +592,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # incoming from a peer we're connected to as outbound, # or server full report the same error to counter deanonymisation if ( - state.Peer(self.destination.host, self.peerNode.port) in - connectionpool.BMConnectionPool().inboundConnections or - len(connectionpool.BMConnectionPool().inboundConnections) + - len(connectionpool.BMConnectionPool().outboundConnections) > - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") + state.Peer(self.destination.host, self.peerNode.port) in + connectionpool.BMConnectionPool().inboundConnections or + len(connectionpool.BMConnectionPool().inboundConnections) + + len(connectionpool.BMConnectionPool().outboundConnections) > + BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + + BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") ): self.append_write_buf(protocol.assembleErrorMessage( errorText="Server full, please try again later.", fatal=2)) @@ -636,8 +644,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def stopDownloadingObject(hashId, forwardAnyway=False): """Stop downloading an object""" for connection in ( - connectionpool.BMConnectionPool().inboundConnections.values() + - connectionpool.BMConnectionPool().outboundConnections.values() + connectionpool.BMConnectionPool().inboundConnections.values() + + connectionpool.BMConnectionPool().outboundConnections.values() ): try: del connection.objectsNewToMe[hashId] From f1b6b16940c9ac27cdf8977caef37631cfedbb0c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 31 Aug 2019 14:36:53 +0530 Subject: [PATCH 057/306] connectionpool.py pylint fixes --- src/network/connectionpool.py | 51 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 077f44a5..461c2b77 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -1,3 +1,7 @@ +""" +src/network/connectionpool.py +================================== +""" import errno import re import socket @@ -20,6 +24,7 @@ from udp import UDPSocket @Singleton +# pylint: disable=too-many-instance-attributes class BMConnectionPool(object): """Pool of all existing connections""" def __init__(self): @@ -68,8 +73,8 @@ class BMConnectionPool(object): def isAlreadyConnected(self, nodeid): """Check if we're already connected to this peer""" for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() + self.inboundConnections.values() + + self.outboundConnections.values() ): try: if nodeid == i.nodeid: @@ -113,7 +118,8 @@ class BMConnectionPool(object): pass connection.handle_close() - def getListeningIP(self): + @staticmethod + def getListeningIP(): """What IP are we supposed to be listening on?""" if BMConfigParser().safeGet( "bitmessagesettings", "onionhostname").endswith(".onion"): @@ -123,8 +129,8 @@ class BMConnectionPool(object): host = '127.0.0.1' if (BMConfigParser().safeGetBoolean( "bitmessagesettings", "sockslisten") or - BMConfigParser().safeGet( - "bitmessagesettings", "socksproxytype") == "none"): + BMConfigParser().safeGet( + "bitmessagesettings", "socksproxytype") == "none"): # python doesn't like bind + INADDR_ANY? # host = socket.INADDR_ANY host = BMConfigParser().get("network", "bind") @@ -154,7 +160,7 @@ class BMConnectionPool(object): udpSocket = UDPSocket(host=bind, announcing=True) self.udpSockets[udpSocket.listening.host] = udpSocket - def loop(self): + def loop(self): # pylint: disable=too-many-branches, too-many-statements """Main Connectionpool's loop""" # defaults to empty loop if outbound connections are maxed spawnConnections = False @@ -170,12 +176,13 @@ class BMConnectionPool(object): onionsocksproxytype = BMConfigParser().safeGet( 'bitmessagesettings', 'onionsocksproxytype', '') if (socksproxytype[:5] == 'SOCKS' and - not BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'sockslisten') and - '.onion' not in BMConfigParser().safeGet( - 'bitmessagesettings', 'onionhostname', '')): + not BMConfigParser().safeGetBoolean( + 'bitmessagesettings', 'sockslisten') and + '.onion' not in BMConfigParser().safeGet( + 'bitmessagesettings', 'onionhostname', '')): acceptConnections = False + # pylint: disable=too-many-nested-blocks if spawnConnections: if not knownnodes.knownNodesActual: helper_bootstrap.dns() @@ -241,8 +248,8 @@ class BMConnectionPool(object): self.lastSpawned = time.time() else: for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() + self.inboundConnections.values() + + self.outboundConnections.values() ): # FIXME: rating will be increased after next connection i.handle_close() @@ -253,8 +260,8 @@ class BMConnectionPool(object): self.startListening() else: for bind in re.sub( - "[^\w.]+", " ", - BMConfigParser().safeGet('network', 'bind') + '[^\w.]+', ' ', # pylint: disable=anomalous-backslash-in-string + BMConfigParser().safeGet('network', 'bind') ).split(): self.startListening(bind) logger.info('Listening for incoming connections.') @@ -263,8 +270,8 @@ class BMConnectionPool(object): self.startUDPSocket() else: for bind in re.sub( - "[^\w.]+", " ", - BMConfigParser().safeGet('network', 'bind') + '[^\w.]+', ' ', # pylint: disable=anomalous-backslash-in-string + BMConfigParser().safeGet('network', 'bind') ).split(): self.startUDPSocket(bind) self.startUDPSocket(False) @@ -288,8 +295,8 @@ class BMConnectionPool(object): reaper = [] for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() + self.inboundConnections.values() + + self.outboundConnections.values() ): minTx = time.time() - 20 if i.fullyEstablished: @@ -302,10 +309,10 @@ class BMConnectionPool(object): time.time() - i.lastTx) i.set_state("close") for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() + - self.listeningSockets.values() + - self.udpSockets.values() + self.inboundConnections.values() + + self.outboundConnections.values() + + self.listeningSockets.values() + + self.udpSockets.values() ): if not (i.accepting or i.connecting or i.connected): reaper.append(i) From b927d51eb39314d808e601de72babfabaade2a29 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Sat, 31 Aug 2019 18:41:05 +0530 Subject: [PATCH 058/306] dandelion.py pylint fixes --- src/network/dandelion.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 2678ca57..fa9081cb 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,3 +1,7 @@ +""" +src/network/dandelion.py +======================== +""" from collections import namedtuple from random import choice, sample, expovariate from threading import RLock @@ -22,7 +26,7 @@ Stem = namedtuple('Stem', ['child', 'stream', 'timeout']) @Singleton -class Dandelion(): +class Dandelion(): # pylint: disable=old-style-class """Dandelion class for tracking stem/fluff stages.""" def __init__(self): # currently assignable child stems @@ -35,7 +39,8 @@ class Dandelion(): self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() - def poissonTimeout(self, start=None, average=0): + @staticmethod + def poissonTimeout(start=None, average=0): """Generate deadline using Poisson distribution""" if start is None: start = time() @@ -97,8 +102,8 @@ class Dandelion(): for k in (k for k, v in self.nodeMap.iteritems() if v is None): self.nodeMap[k] = connection for k, v in { - k: v for k, v in self.hashMap.iteritems() - if v.child is None + k: v for k, v in self.hashMap.iteritems() + if v.child is None }.iteritems(): self.hashMap[k] = Stem( connection, v.stream, self.poissonTimeout()) @@ -115,12 +120,12 @@ class Dandelion(): self.stem.remove(connection) # active mappings to pointing to the removed node for k in ( - k for k, v in self.nodeMap.iteritems() if v == connection + k for k, v in self.nodeMap.iteritems() if v == connection ): self.nodeMap[k] = None for k, v in { - k: v for k, v in self.hashMap.iteritems() - if v.child == connection + k: v for k, v in self.hashMap.iteritems() + if v.child == connection }.iteritems(): self.hashMap[k] = Stem( None, v.stream, self.poissonTimeout()) From 8589f01d3d167e0195083bff231717b5037eb42c Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 2 Sep 2019 16:56:38 +0530 Subject: [PATCH 059/306] downloadthread.py flake8 fixes --- src/network/downloadthread.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 308dffcb..5aaff614 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -38,10 +38,13 @@ class DownloadThread(StoppableThread): while not self._stopped: requested = 0 # Choose downloading peers randomly - connections = [x for x in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() if x.fullyEstablished] + connections = [ + x for x in + BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() + if x.fullyEstablished] helper_random.randomshuffle(connections) try: - requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) + requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) except ZeroDivisionError: requestChunk = 1 for i in connections: From d8ea0afe409d013685364d6b578b8fa2da68241e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 2 Sep 2019 19:15:15 +0530 Subject: [PATCH 060/306] downloadthread.py Pylint fixes --- src/network/downloadthread.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 5aaff614..a4b58862 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,3 +1,7 @@ +""" +src/network/downloadthread.py +============================= +""" import time import addresses @@ -12,6 +16,7 @@ from objectracker import missingObjects class DownloadThread(StoppableThread): + """Thread-based class for downloading from connections""" minPending = 200 maxRequestChunk = 1000 requestTimeout = 60 @@ -24,6 +29,7 @@ class DownloadThread(StoppableThread): self.lastCleaned = time.time() def cleanPending(self): + """Expire pending downloads eventually""" deadline = time.time() - DownloadThread.requestExpires try: toDelete = [k for k, v in missingObjects.iteritems() if v < deadline] From 5fcb7fc05ea618bb8e520f9cc4caaf9abe69bd2e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 3 Sep 2019 14:34:17 +0530 Subject: [PATCH 061/306] http-old flake8 fixes --- src/network/http-old.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/http-old.py b/src/network/http-old.py index 56d24915..d38ba8b6 100644 --- a/src/network/http-old.py +++ b/src/network/http-old.py @@ -24,7 +24,7 @@ class HTTPClient(asyncore.dispatcher): self.close() def handle_read(self): -# print self.recv(8192) + # print self.recv(8192) self.recv(8192) def writable(self): @@ -34,6 +34,7 @@ class HTTPClient(asyncore.dispatcher): sent = self.send(self.buffer) self.buffer = self.buffer[sent:] + if __name__ == "__main__": # initial fill for i in range(parallel): @@ -44,6 +45,6 @@ if __name__ == "__main__": for i in range(parallel - len(asyncore.socket_map)): HTTPClient('127.0.0.1', '/') print "Active connections: %i" % (len(asyncore.socket_map)) - asyncore.loop(count=len(asyncore.socket_map)/2) + asyncore.loop(count=len(asyncore.socket_map) / 2) if requestCount % 100 == 0: print "Processed %i total messages" % (requestCount) From 68e09a5e3016c3fa0b48d114208f2894cfcf826e Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 3 Sep 2019 18:41:24 +0530 Subject: [PATCH 062/306] http-old pylint fixes --- src/network/http-old.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/network/http-old.py b/src/network/http-old.py index d38ba8b6..c97927d9 100644 --- a/src/network/http-old.py +++ b/src/network/http-old.py @@ -1,3 +1,7 @@ +""" +src/network/http-old.py +======================= +""" import asyncore import socket import time @@ -8,6 +12,7 @@ duration = 60 class HTTPClient(asyncore.dispatcher): + """An asyncore dispatcher""" port = 12345 def __init__(self, host, path, connect=True): @@ -19,6 +24,7 @@ class HTTPClient(asyncore.dispatcher): self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path def handle_close(self): + # pylint: disable=global-statement global requestCount requestCount += 1 self.close() @@ -28,7 +34,7 @@ class HTTPClient(asyncore.dispatcher): self.recv(8192) def writable(self): - return (len(self.buffer) > 0) + return len(self.buffer) > 0 def handle_write(self): sent = self.send(self.buffer) @@ -40,8 +46,8 @@ if __name__ == "__main__": for i in range(parallel): HTTPClient('127.0.0.1', '/') start = time.time() - while (time.time() - start < duration): - if (len(asyncore.socket_map) < parallel): + while time.time() - start < duration: + if len(asyncore.socket_map) < parallel: for i in range(parallel - len(asyncore.socket_map)): HTTPClient('127.0.0.1', '/') print "Active connections: %i" % (len(asyncore.socket_map)) From 7eced454d10d2c2b4eb3c0b7da86083347cfb1de Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 3 Sep 2019 19:56:59 +0530 Subject: [PATCH 063/306] http flake8 fixes --- src/network/http.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/network/http.py b/src/network/http.py index 55cb81a1..8bab0c92 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -2,11 +2,13 @@ import socket from advanceddispatcher import AdvancedDispatcher import asyncore_pollchoose as asyncore -from proxy import Proxy, ProxyError, GeneralProxyError -from socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error -from socks4a import Socks4aConnection, Socks4aResolver, Socks4aError +from proxy import ProxyError +from socks5 import Socks5Connection, Socks5Resolver +from socks4a import Socks4aConnection, Socks4aResolver -class HttpError(ProxyError): pass + +class HttpError(ProxyError): + pass class HttpConnection(AdvancedDispatcher): @@ -19,8 +21,10 @@ class HttpConnection(AdvancedDispatcher): print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) def state_init(self): - self.append_write_buf("GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (self.path, self.destination[0])) - print "Sending %ib" % (len(self.write_buf)) + self.append_write_buf( + "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % ( + self.path, self.destination[0])) + print "Sending %ib" % (len(self.write_buf)) self.set_state("http_request_sent", 0) return False @@ -72,15 +76,15 @@ if __name__ == "__main__": for host in ("bitmessage.org",): direct = HttpConnection(host) while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (direct.state) + # print "loop, state = %s" % (direct.state) asyncore.loop(timeout=1, count=1) proxy = Socks5HttpConnection(host) while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) + # print "loop, state = %s" % (proxy.state) asyncore.loop(timeout=1, count=1) proxy = Socks4aHttpConnection(host) while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) + # print "loop, state = %s" % (proxy.state) asyncore.loop(timeout=1, count=1) From 81284422df04b19693a27e6254a0e4168dc1f32e Mon Sep 17 00:00:00 2001 From: Navjot Date: Fri, 6 Sep 2019 20:50:58 +0530 Subject: [PATCH 064/306] identicon or subscription package functionality implementation --- src/bitmessagekivy/main.kv | 196 ++++++++++++++++++++++++---- src/bitmessagekivy/mpybit.py | 243 +++++++++++++++++++++++------------ src/identiconGeneration.py | 82 ++++++++++++ src/images/copy_text.png | Bin 0 -> 2701 bytes 4 files changed, 415 insertions(+), 106 deletions(-) create mode 100644 src/identiconGeneration.py create mode 100644 src/images/copy_text.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 08847957..e5b0340c 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -53,15 +53,15 @@ color: color_font : - drawer_logo: './images/drawer_logo1.png' + drawer_logo: app.address_identicon() NavigationDrawerDivider: - + NavigationDrawerTwoLineListItem: text: "Accounts" NavigationDrawerIconButton: CustomSpinner: - pos_hint:{"x":0,"y":.25} id: btn + pos_hint:{"x":0,"y":.25} option_cls: Factory.get("MySpinnerOption") font_size: '12.5sp' text: app.getDefaultAccData() @@ -70,6 +70,11 @@ color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) + Image: + source: app.get_default_image() + x: self.width/4 + y: self.parent.y + self.parent.height/2 - self.height + 10 + size: 20, 20 ArrowImg: NavigationDrawerIconButton: id: inbox_cnt @@ -200,6 +205,7 @@ NavigationLayout: id: search_field hint_text: 'Search' on_text: app.searchQuery(self) + ScreenManager: id: scr_mngr Inbox: @@ -304,7 +310,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(500) + height: self.minimum_height + 2 * self.parent.height/4 padding: dp(32) spacing: 15 BoxLayout: @@ -634,7 +640,118 @@ NavigationLayout: : name: 'payment' - + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'horizontal' + padding: dp(20) + spacing: 10 + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Platinum' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 50.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Silver' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 100.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Gold' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 500.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + : id: popup @@ -663,10 +780,12 @@ NavigationLayout: hint_text: "Address" required: True helper_text_mode: "on_error" + on_text: root.checkAddress_valid(self) BoxLayout: spacing:5 orientation: 'horizontal' MDRaisedButton: + id: save_addr size_hint: 1.5, None height: dp(40) on_release: @@ -698,6 +817,7 @@ NavigationLayout: color: (1,1,1,1) halign: 'center' + : name: 'networkstat' MDTabbedPanel: @@ -795,23 +915,27 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(400) + height: dp(400) + self.minimum_height padding: dp(32) MDLabel: font_style: 'Headline' theme_text_color: 'Primary' text: root.subject halign: 'left' + font_size: '20sp' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: "From: " + root.from_addr halign: 'left' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: "To: " + root.to_addr halign: 'left' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' @@ -823,28 +947,46 @@ NavigationLayout: text: root.message halign: 'left' bold: True + CopyTextBtn: BoxLayout: - spacing:20 - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() if root.page_type == 'sent' else root.write_msg(app) - MDLabel: - font_style: 'Title' - text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.delete_mail() - MDLabel: - font_style: 'Title' - text: 'Delete' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' + orientation: 'vertical' + size_hint_y: None + height: dp(100) + self.minimum_height + BoxLayout: + spacing:20 + MDRaisedButton: + size_hint: 1, None + height: dp(40) + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.write_msg(app) if root.page_type == 'draft' else root.copy_sent_mail() + MDLabel: + font_style: 'Title' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + on_press: root.delete_mail() + MDLabel: + font_style: 'Title' + text: 'Delete' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + id: cpyButton + color: 0,0,0,1 + background_color: (0,0,0,0) + center_x: self.parent.center_x * 2 - self.parent.parent.padding[0]/2 + center_y: self.parent.center_y + on_press:app.root.ids.sc14.copy_composer_text(self) + Image: + source: './images/copy_text.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 20, 20 : size_hint_y: None diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ca82f405..48ff4738 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -61,6 +61,12 @@ import state from uikivysignaler import UIkivySignaler +import identiconGeneration + +import os + +from kivy.core.clipboard import Clipboard + # pylint: disable=unused-argument # pylint: disable=broad-except @@ -120,10 +126,7 @@ class Inbox(Screen): third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), - 'secondary_text': mail[5][:10] + '...........' if len( - mail[3]) > 10 else mail[3] + '\n' + " " + ( - third_text[:25] + '...!') if len( - third_text) > 25 else third_text, + 'secondary_text': mail[5][:50] + '........' if len(mail[5]) >= 50 else (mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'receivedTime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem( @@ -131,11 +134,11 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') else '!' + # img_latter = item['secondary_text'][0].upper() if ( + # item['secondary_text'][0].upper() >= 'A' and item[ + # 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') @@ -269,11 +272,8 @@ class MyAddress(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['text'][0].upper() if ( - item['text'][0].upper() >= 'A' and item['text'][ - 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['text'].strip())))) meny.bind(on_press=partial( self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) @@ -356,11 +356,8 @@ class AddressBook(Screen): secondary_text=item[1], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item[0][0].upper() if ( - item[0][0].upper() >= 'A' and item[0][ - 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[0].strip())))) meny.bind(on_press=partial( self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') @@ -470,8 +467,8 @@ class DropDownWidget(BoxLayout): # pylint: disable=too-many-locals fromAddress = str(self.ids.ti.text) toAddress = str(self.ids.txt_input.text) - subject = str(self.ids.subject.text) - message = str(self.ids.body.text) + subject = self.ids.subject.text.encode('utf-8').strip() + message = self.ids.body.text.encode('utf-8').strip() encoding = 3 print "message: ", self.ids.body.text sendMessageToPeople = True @@ -542,13 +539,7 @@ class DropDownWidget(BoxLayout): queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" - self.ids.body.text = '' - self.ids.ti.text = '' - self.ids.subject.text = '' - self.ids.txt_input.text = '' self.parent.parent.current = 'inbox' - self.ids.btn.text = 'select' - self.ids.ti.text = '' navApp.back_press() toast('send') return None @@ -709,7 +700,7 @@ class Random(Screen): eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - if self.ids.label.text: + if str(self.ids.label.text).strip(): queues.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, @@ -774,13 +765,9 @@ class Sent(Screen): if queryreturn: for mail in queryreturn: - third_text = mail[3].replace('\n', ' ') self.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, + 'secondary_text': mail[2][:50] + '........' if len(mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem( @@ -788,11 +775,8 @@ class Sent(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') @@ -806,7 +790,7 @@ class Sent(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.delete, item['lastactiontime'])) carousel.add_widget(del_btn) @@ -881,9 +865,13 @@ class Sent(Screen): try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) + self.parent.screens[16].clear_widgets() + self.parent.screens[16].add_widget(Allmails()) except Exception: self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + self.parent.parent.screens[16].clear_widgets() + self.parent.parent.screens[16].add_widget(Allmails()) class Trash(Screen): @@ -903,26 +891,58 @@ class Trash(Screen): state.association = BMConfigParser().addresses()[0] inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from \ + "SELECT toaddress, fromaddress, subject, message, folder, received from \ inbox WHERE folder = 'trash' and toaddress = '{}';".format( state.association)) sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from \ + "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from \ sent WHERE folder = 'trash' and fromaddress = '{}';".format( state.association)) trash_data = inbox + sent - for item in trash_data: - meny = ThreeLineAvatarIconListItem( - text=item[1], - secondary_text=item[2], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/text_images/{}.png'.format( - item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') - meny.add_widget(AvatarSampleWidget(source=img_latter)) - self.ids.ml.add_widget(meny) + if trash_data: + for item in trash_data: + meny = ThreeLineAvatarIconListItem( + text=item[1], + secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + img_latter = './images/text_images/{}.png'.format( + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget(source=img_latter)) + carousel = Carousel(direction='right') + if platform == 'android': + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete_permanently, item[5])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + else: + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no trashed message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def delete_permanently(self, data_index, instance, *args): + """Deleting trash mail permanently.""" + pass class Page(Screen): @@ -986,7 +1006,6 @@ class NavigateApp(App): def build(self): """Method builds the widget.""" - import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -1018,6 +1037,7 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" + self.set_identicon(text) address_label = self.current_address_label( BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label @@ -1074,13 +1094,29 @@ class NavigateApp(App): p = GrashofPopup() p.open() - @staticmethod - def getDefaultAccData(): + def getDefaultAccData(self): """Getting Default Account Data.""" if BMConfigParser().addresses(): + img = identiconGeneration.generate(BMConfigParser().addresses()[0]) + self.createFolder('./images/default_identicon/') + img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' + def createFolder(self, directory): + """This method is used to create the directory when app starts""" + try: + if not os.path.exists(directory): + os.makedirs(directory) + except OSError: + print ('Error: Creating directory. ' + directory) + + def get_default_image(self): + if BMConfigParser().addresses(): + # BMConfigParser().addresses()[0] + return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + return '' + @staticmethod def addressexist(): """Checking address existence.""" @@ -1206,7 +1242,7 @@ class NavigateApp(App): return state.all_count @staticmethod - def current_address_label(current_add_label = None, current_addr = None): + def current_address_label(current_add_label=None, current_addr=None): """Getting current address labels.""" if BMConfigParser().addresses(): if current_add_label: @@ -1264,6 +1300,17 @@ class NavigateApp(App): text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) + def set_identicon(self, text): + """This method is use for showing identicon in address spinner""" + img = identiconGeneration.generate(text) + img.size = 20, 20 + img.y = self.root.children[2].children[0].ids.btn.children[0].y + img.x = 5 + self.root.children[2].children[0].ids.btn.add_widget(img) + + def address_identicon(self): + return './images/drawer_logo1.png' + class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1280,19 +1327,16 @@ class GrashofPopup(Popup): def savecontact(self): """Method is used for Saving Contacts.""" - my_addresses = \ - self.parent.children[1].children[2].children[0].ids.btn.values - entered_text = str(self.ids.address.text) - if entered_text in my_addresses: - self.ids.address.focus = False - self.ids.address.helper_text = 'Please Enter corrent address' - elif entered_text == '': + label = self.ids.label.text.strip() + address = self.ids.address.text.strip() + if label == '' and address == '': + self.ids.label.focus = True + self.ids.address.focus = True + elif address == '': + self.ids.address.focus = True + elif label == '': self.ids.label.focus = True - # self.ids.address.focus = True - self.ids.label.helper_text = 'This field is required' - label = self.ids.label.text - address = self.ids.address.text stored_address = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] if label and address and address not in stored_address: @@ -1328,6 +1372,30 @@ class GrashofPopup(Popup): """Pop is Canceled.""" toast('Canceled') + def checkAddress_valid(self, instance): + my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + add_book = [addr[1] for addr in kivy_helper_search.search_sql( + folder="addressbook")] + entered_text = str(instance.text).strip() + if entered_text in add_book: + text = 'Address is already in the addressbook.' + elif entered_text in my_addresses: + text = 'You can not save your own address.' + + if entered_text in my_addresses or entered_text in add_book: + if len(self.ids.popup_box.children) <= 2: + err_msg = MDLabel( + id='erro_msg', + font_style='Body2', + text=text, + font_size=5) + err_msg.color = 1, 0, 0, 1 + self.ids.popup_box.add_widget(err_msg) + self.ids.save_addr.disabled = True + elif len(self.ids.popup_box.children) > 2: + self.ids.popup_box.remove_widget(self.ids.popup_box.children[0]) + self.ids.save_addr.disabled = False + class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" @@ -1443,7 +1511,7 @@ class MailDetail(Screen): self.parent.parent.current = 'allmails' state.is_allmail = False else: - self.parent.parent.current = state.detailPageType + self.parent.parent.current = state.detailPageType msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) @@ -1484,6 +1552,15 @@ class MailDetail(Screen): self.parent.parent.current = 'create' navApp.set_navbar_for_composer() + def copy_composer_text(self, instance, *args): + """This method is used for copying the data from mail detail page""" + if len(instance.parent.text.split(':')) > 1: + cpy_text = instance.parent.text.split(':')[1].strip() + else: + cpy_text = instance.parent.text + Clipboard.copy(cpy_text) + toast('Copied') + class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail.""" @@ -1651,7 +1728,7 @@ class Draft(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.delete_draft, item['lastactiontime'])) carousel.add_widget(del_btn) @@ -1694,12 +1771,12 @@ class Draft(Screen): if int(state.draft_count) > 0: msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) - msg_count_objs.allmail_cnt.badge_text = str( - int(state.all_count) - 1) + # msg_count_objs.allmail_cnt.badge_text = str( + # int(state.all_count) - 1) # msg_count_objs.trash_cnt.badge_text = str( # int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) - state.all_count = str(int(state.all_count) - 1) + # state.all_count = str(int(state.all_count) - 1) # state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') @@ -1764,8 +1841,9 @@ class CustomSpinner(Spinner): def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) - max_value = 2.8 - self.dropdown_cls.max_height = self.height * max_value + max_value * 4 + # max_value = 2.8 + # self.dropdown_cls.max_height = self.height / 2 * max_value + max_value * 4 + self.dropdown_cls.max_height = Window.size[1] / 3 def remove_search_bar(obj): @@ -1814,17 +1892,12 @@ class Allmails(Screen): if all_mails: for item in all_mails: meny = ThreeLineAvatarIconListItem( - text='Draft' if item[4] == 'draft' else item[1], - secondary_text=item[1] if item[4] == 'draft' else item[2], + text=item[1], + secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/avatar.png' if item[ - 4] == 'draft' else './images/text_images/{}.png'.format( - item[2][0].upper() if ( - item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget( - source=img_latter)) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[2].strip())))) meny.bind(on_press=partial( self.mail_detail, item[5], item[4])) carousel = Carousel(direction='right') @@ -1838,7 +1911,7 @@ class Allmails(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.swipe_delete, item[5], item[4])) carousel.add_widget(del_btn) @@ -1927,3 +2000,15 @@ class Allmails(Screen): self.ids.refresh_layout.refresh_done() self.tick = 0 Clock.schedule_once(refresh_callback, 1) + + +def avatarImageFirstLetter(letter_string): + """This method is used to the first letter for the avatar image""" + 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 = '!' + + return img_latter \ No newline at end of file diff --git a/src/identiconGeneration.py b/src/identiconGeneration.py new file mode 100644 index 00000000..2465c030 --- /dev/null +++ b/src/identiconGeneration.py @@ -0,0 +1,82 @@ +import hashlib +from PIL import Image +from kivy.core.image import Image as CoreImage +# Core classes for loading images and converting them to a Texture. The raw image data can be keep in memory for further access +from kivy.uix.image import Image as kiImage +from io import BytesIO + +# constants +RESOLUTION = 128, 128 +V_RESOLUTION = 7, 7 +BACKGROUND_COLOR = 255, 255, 255, 255 +MODE = "RGB" + + +def generate(Generate_string=None): + hash_string = generate_hash(Generate_string) + color = random_color(hash_string) + image = Image.new(MODE, V_RESOLUTION, BACKGROUND_COLOR) + image = generate_image(image, color, hash_string) + image = image.resize(RESOLUTION, 0) + + data = BytesIO() + image.save(data, format='png') + data.seek(0) + # yes you actually need this + im = CoreImage(BytesIO(data.read()), ext='png') + beeld = kiImage() + # only use this line in first code instance + beeld.texture = im.texture + return beeld + # image.show() + + +def generate_hash(string): + try: + # make input case insensitive + string = str.lower(string) + hash_object = hashlib.md5(str.encode(string)) + print(hash_object.hexdigest()) + + # returned object is a hex string + return hash_object.hexdigest() + + except IndexError: + print("Error: Please enter a string as an argument.") + + +def random_color(hash_string): + # remove first three digits from hex string + split = 6 + rgb = hash_string[:split] + + split = 2 + r = rgb[:split] + g = rgb[split:2 * split] + b = rgb[2 * split:3 * split] + + color = (int(r, 16), int(g, 16), + int(b, 16), 0xFF) + + return color + + +def generate_image(image, color, hash_string): + hash_string = hash_string[6:] + + lower_x = 1 + lower_y = 1 + upper_x = int(V_RESOLUTION[0] / 2) + 1 + upper_y = V_RESOLUTION[1] - 1 + limit_x = V_RESOLUTION[0] - 1 + index = 0 + + for x in range(lower_x, upper_x): + for y in range(lower_y, upper_y): + if int(hash_string[index], 16) % 2 == 0: + image.putpixel((x, y), color) + image.putpixel((limit_x - x, y), color) + + index = index + 1 + + return image diff --git a/src/images/copy_text.png b/src/images/copy_text.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc63611a604fd7e6071c82bef2c3689c689c91d GIT binary patch literal 2701 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 z Date: Sat, 7 Sep 2019 20:11:42 +0530 Subject: [PATCH 065/306] mpybit flake8 fix --- src/bitmessagekivy/mpybit.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 48ff4738..3d8d33aa 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -126,7 +126,9 @@ class Inbox(Screen): third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), - 'secondary_text': mail[5][:50] + '........' if len(mail[5]) >= 50 else (mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + 'secondary_text': mail[5][:50] + '........' if len( + mail[5]) >= 50 else ( + mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'receivedTime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem( @@ -138,7 +140,8 @@ class Inbox(Screen): # item['secondary_text'][0].upper() >= 'A' and item[ # 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') @@ -767,7 +770,9 @@ class Sent(Screen): for mail in queryreturn: self.data.append({ 'text': mail[1].strip(), - 'secondary_text': mail[2][:50] + '........' if len(mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', + 'secondary_text': mail[2][:50] + '........' if len( + mail[2]) >= 50 else ( + mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem( @@ -776,7 +781,8 @@ class Sent(Screen): theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') @@ -904,12 +910,14 @@ class Trash(Screen): for item in trash_data: meny = ThreeLineAvatarIconListItem( text=item[1], - secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + secondary_text=item[2][:50] + '........' if len( + item[2]) >= 50 else ( + item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) img_latter = './images/text_images/{}.png'.format( - item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget(source=img_latter)) carousel = Carousel(direction='right') if platform == 'android': @@ -1109,7 +1117,7 @@ class NavigateApp(App): if not os.path.exists(directory): os.makedirs(directory) except OSError: - print ('Error: Creating directory. ' + directory) + print('Error: Creating directory. ' + directory) def get_default_image(self): if BMConfigParser().addresses(): @@ -1774,7 +1782,7 @@ class Draft(Screen): # msg_count_objs.allmail_cnt.badge_text = str( # int(state.all_count) - 1) # msg_count_objs.trash_cnt.badge_text = str( - # int(state.trash_count) + 1) + # int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) # state.all_count = str(int(state.all_count) - 1) # state.trash_count = str(int(state.trash_count) + 1) @@ -1893,11 +1901,14 @@ class Allmails(Screen): for item in all_mails: meny = ThreeLineAvatarIconListItem( text=item[1], - secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + secondary_text=item[2][:50] + '........' if len( + item[2]) >= 50 else ( + item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[2].strip())))) + source='./images/text_images/{}.png'.format( + avatarImageFirstLetter(item[2].strip())))) meny.bind(on_press=partial( self.mail_detail, item[5], item[4])) carousel = Carousel(direction='right') @@ -2011,4 +2022,4 @@ def avatarImageFirstLetter(letter_string): else: img_latter = '!' - return img_latter \ No newline at end of file + return img_latter From dfe518520bd43864187b1095188a1ae381dcd3df Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 9 Sep 2019 19:47:07 +0530 Subject: [PATCH 066/306] mpybit pylint fixes --- src/bitmessagekivy/mpybit.py | 70 ++++++++++++------------------------ 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 3d8d33aa..7b7dcf07 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,11 +1,8 @@ """Coding: utf-8.""" import time from functools import partial - from bmconfigparser import BMConfigParser - from helper_sql import sqlExecute, sqlQuery - from kivy.app import App from kivy.clock import Clock from kivy.core.window import Window @@ -33,9 +30,7 @@ from kivy.uix.screenmanager import Screen from kivy.uix.spinner import Spinner from kivy.uix.textinput import TextInput from kivy.utils import platform - import kivy_helper_search - from kivymd.button import MDIconButton from kivymd.dialog import MDDialog from kivymd.label import MDLabel @@ -52,23 +47,14 @@ from kivymd.navigationdrawer import ( from kivymd.selectioncontrols import MDCheckbox from kivymd.textfields import MDTextField from kivymd.theming import ThemeManager - import queues - from semaphores import kivyuisignaler - import state - from uikivysignaler import UIkivySignaler - import identiconGeneration - import os - from kivy.core.clipboard import Clipboard - -# pylint: disable=unused-argument -# pylint: disable=broad-except +# pylint: disable=unused-argument, too-few-public-methods def toast(text): @@ -82,7 +68,6 @@ def toast(text): class Navigatorss(MDNavigationDrawer): """Navigators class contains image, title and logo.""" - # pylint: disable=too-few-public-methods image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() @@ -258,10 +243,12 @@ class MyAddress(Screen): def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" + # pylint: disable=unnecessary-lambda, deprecated-lambda addresses_list = state.kivyapp.variable_1 if state.searcing_text: - filtered_list = filter(lambda addr: self.filter_address( - addr), BMConfigParser().addresses()) + filtered_list = filter( + lambda addr: self.filter_address( + addr), BMConfigParser().addresses()) addresses_list = filtered_list if addresses_list: data = [] @@ -324,6 +311,7 @@ class MyAddress(Screen): @staticmethod def filter_address(address): """Method will filter the my address list data.""" + # pylint: disable=deprecated-lambda if filter(lambda x: (state.searcing_text).lower() in x, [ BMConfigParser().get( address, 'label').lower(), address.lower()]): @@ -416,7 +404,6 @@ class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout): """Adds selection and focus behaviour to the view.""" - # pylint: disable=too-few-public-methods pass @@ -453,8 +440,7 @@ class SelectableLabel(RecycleDataViewBehavior, Label): class RV(RecycleView): """Recycling View.""" - # pylint: disable=too-few-public-methods - def __init__(self, **kwargs): + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """Recycling Method.""" super(RV, self).__init__(**kwargs) @@ -465,7 +451,7 @@ class DropDownWidget(BoxLayout): txt_input = ObjectProperty() rv = ObjectProperty() - def send(self, navApp): + def send(self, navApp): # pylint: disable=too-many-statements, inconsistent-return-statements """Send message from one address to another.""" # pylint: disable=too-many-locals fromAddress = str(self.ids.ti.text) @@ -604,7 +590,7 @@ class MyTextInput(TextInput): starting_no = NumericProperty(3) suggestion_text = '' - def __init__(self, **kwargs): + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation """Getting Text Input.""" super(MyTextInput, self).__init__(**kwargs) @@ -635,21 +621,18 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" - # pylint: disable=too-few-public-methods pass class Login(Screen): """Login Screeen.""" - # pylint: disable=too-few-public-methods pass class NetworkStat(Screen): """Method used to show network stat.""" - # pylint: disable=too-few-public-methods text_variable_1 = StringProperty( '{0}::{1}'.format('Total Connections', '0')) text_variable_2 = StringProperty( @@ -685,14 +668,12 @@ class NetworkStat(Screen): class ContentNavigationDrawer(Navigatorss): """Navigate Content Drawer.""" - # pylint: disable=too-few-public-methods pass class Random(Screen): """Generates Random Address.""" - # pylint: disable=too-few-public-methods is_active = BooleanProperty(False) checked = StringProperty("") @@ -723,7 +704,6 @@ class Random(Screen): class AddressSuccessful(Screen): """Getting Address Detail.""" - # pylint: disable=too-few-public-methods pass @@ -883,8 +863,6 @@ class Sent(Screen): class Trash(Screen): """Trash Screen uses screen to show widgets of screens.""" - # pylint: disable=too-few-public-methods - def __init__(self, *args, **kwargs): """Trash method, delete sent message and add in Trash.""" super(Trash, self).__init__(*args, **kwargs) @@ -956,15 +934,12 @@ class Trash(Screen): class Page(Screen): """Page Screen show widgets of page.""" - # pylint: disable=too-few-public-methods pass class Create(Screen): """Creates the screen widgets.""" - # pylint: disable=too-few-public-methods - def __init__(self, **kwargs): """Getting Labels and address from addressbook.""" super(Create, self).__init__(**kwargs) @@ -979,11 +954,10 @@ class Create(Screen): class Setting(Screen): """Setting the Screen components.""" - # pylint: disable=too-few-public-methods pass -class NavigateApp(App): +class NavigateApp(App): # pylint: disable=too-many-public-methods """Navigation Layout of class.""" theme_cls = ThemeManager() @@ -1111,15 +1085,18 @@ class NavigateApp(App): return BMConfigParser().addresses()[0] return 'Select Address' - def createFolder(self, directory): + @staticmethod + def createFolder(directory): """This method is used to create the directory when app starts""" try: if not os.path.exists(directory): os.makedirs(directory) except OSError: - print('Error: Creating directory. ' + directory) + print 'Error: Creating directory. ' + directory - def get_default_image(self): + @staticmethod + def get_default_image(): + """Getting default image on address""" if BMConfigParser().addresses(): # BMConfigParser().addresses()[0] return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) @@ -1316,7 +1293,9 @@ class NavigateApp(App): img.x = 5 self.root.children[2].children[0].ids.btn.add_widget(img) - def address_identicon(self): + @staticmethod + def address_identicon(): + """Address identicon""" return './images/drawer_logo1.png' @@ -1381,6 +1360,7 @@ class GrashofPopup(Popup): toast('Canceled') def checkAddress_valid(self, instance): + """Checking is address is valid or not""" my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values add_book = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] @@ -1408,21 +1388,18 @@ class GrashofPopup(Popup): class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" - # pylint: disable=too-few-public-methods pass class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): """Left icon sample widget.""" - # pylint: disable=too-few-public-methods pass class IconRightSampleWidget(IRightBodyTouch, MDCheckbox): """Right icon sample widget.""" - # pylint: disable=too-few-public-methods pass @@ -1560,7 +1537,8 @@ class MailDetail(Screen): self.parent.parent.current = 'create' navApp.set_navbar_for_composer() - def copy_composer_text(self, instance, *args): + @staticmethod + def copy_composer_text(instance, *args): """This method is used for copying the data from mail detail page""" if len(instance.parent.text.split(':')) > 1: cpy_text = instance.parent.text.split(':')[1].strip() @@ -1659,8 +1637,6 @@ class AddbookDetailPopup(Popup): class ShowQRCode(Screen): """ShowQRCode Screen uses to show the detail of mails.""" - # pylint: disable=too-few-public-methods - def qrdisplay(self): """Method used for showing QR Code.""" self.manager.parent.parent.parent.ids.search_bar.clear_widgets() @@ -1844,8 +1820,6 @@ class Draft(Screen): class CustomSpinner(Spinner): """This class is used for setting spinner size.""" - # pylint: disable=too-few-public-methods - def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) From 2c71612a4b1cfc971a1fbeb429d7c7d5458f0abd Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 4 Sep 2019 13:04:53 +0530 Subject: [PATCH 067/306] http pylint fixes --- src/network/http.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/network/http.py b/src/network/http.py index 8bab0c92..8bba38ac 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -12,7 +12,7 @@ class HttpError(ProxyError): class HttpConnection(AdvancedDispatcher): - def __init__(self, host, path="/"): + def __init__(self, host, path="/"): # pylint: disable=redefined-outer-name AdvancedDispatcher.__init__(self) self.path = path self.destination = (host, 80) @@ -29,7 +29,7 @@ class HttpConnection(AdvancedDispatcher): return False def state_http_request_sent(self): - if len(self.read_buf) > 0: + if self.read_buf: print "Received %ib" % (len(self.read_buf)) self.read_buf = b"" if not self.connected: @@ -38,7 +38,7 @@ class HttpConnection(AdvancedDispatcher): class Socks5HttpConnection(Socks5Connection, HttpConnection): - def __init__(self, host, path="/"): + def __init__(self, host, path="/"): # pylint: disable=super-init-not-called, redefined-outer-name self.path = path Socks5Connection.__init__(self, address=(host, 80)) @@ -48,7 +48,7 @@ class Socks5HttpConnection(Socks5Connection, HttpConnection): class Socks4aHttpConnection(Socks4aConnection, HttpConnection): - def __init__(self, host, path="/"): + def __init__(self, host, path="/"): # pylint: disable=super-init-not-called, redefined-outer-name Socks4aConnection.__init__(self, address=(host, 80)) self.path = path @@ -59,32 +59,31 @@ class Socks4aHttpConnection(Socks4aConnection, HttpConnection): if __name__ == "__main__": # initial fill - for host in ("bootstrap8080.bitmessage.org", "bootstrap8444.bitmessage.org"): proxy = Socks5Resolver(host=host) - while len(asyncore.socket_map) > 0: + while asyncore.socket_map: print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) asyncore.loop(timeout=1, count=1) proxy.resolved() proxy = Socks4aResolver(host=host) - while len(asyncore.socket_map) > 0: + while asyncore.socket_map: print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) asyncore.loop(timeout=1, count=1) proxy.resolved() for host in ("bitmessage.org",): direct = HttpConnection(host) - while len(asyncore.socket_map) > 0: + while asyncore.socket_map: # print "loop, state = %s" % (direct.state) asyncore.loop(timeout=1, count=1) proxy = Socks5HttpConnection(host) - while len(asyncore.socket_map) > 0: + while asyncore.socket_map: # print "loop, state = %s" % (proxy.state) asyncore.loop(timeout=1, count=1) proxy = Socks4aHttpConnection(host) - while len(asyncore.socket_map) > 0: + while asyncore.socket_map: # print "loop, state = %s" % (proxy.state) asyncore.loop(timeout=1, count=1) From 28e954902d4df6bf5562c7c0646277152bba4da3 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 4 Sep 2019 17:40:28 +0530 Subject: [PATCH 068/306] httpd flake8 fixes --- src/network/httpd.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/network/httpd.py b/src/network/httpd.py index b8b6ba21..ba53c7fc 100644 --- a/src/network/httpd.py +++ b/src/network/httpd.py @@ -3,6 +3,7 @@ import socket from tls import TLSHandshake + class HTTPRequestHandler(asyncore.dispatcher): response = """HTTP/1.0 200 OK\r Date: Sun, 23 Oct 2016 18:02:00 GMT\r @@ -66,7 +67,12 @@ class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): if not hasattr(self, '_map'): asyncore.dispatcher.__init__(self, sock) # self.tlsDone = False - TLSHandshake.__init__(self, sock=sock, certfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/cert.pem', keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', server_side=True) + TLSHandshake.__init__( + self, + sock=sock, + certfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/cert.pem', + keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', + server_side=True) HTTPRequestHandler.__init__(self, sock) def handle_connect(self): @@ -143,6 +149,7 @@ class HTTPSServer(HTTPServer): # print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) HTTPSRequestHandler(sock) + if __name__ == "__main__": client = HTTPSServer() asyncore.loop() From 97cbe43294c0360f7b35d1774b095d93e8f1a385 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 4 Sep 2019 19:54:27 +0530 Subject: [PATCH 069/306] invthread flake8 fixes --- src/network/invthread.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index e79172ba..d0dbb387 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -37,11 +37,11 @@ class InvThread(StoppableThread): def handleLocallyGenerated(self, stream, hashId): Dandelion().addHash(hashId, stream=stream) for connection in \ - BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): - if state.dandelion and connection != Dandelion().objectChildStem(hashId): - continue - connection.objectsNewToThem[hashId] = time() + if state.dandelion and connection != Dandelion().objectChildStem(hashId): + continue + connection.objectsNewToThem[hashId] = time() def run(self): while not state.shutdown: From ef77a9816ef9f50aa89c03d867c0b1012ccf3f29 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 5 Sep 2019 14:36:44 +0530 Subject: [PATCH 070/306] invthread pylint fixes --- src/network/invthread.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index d0dbb387..cf202012 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,3 +1,7 @@ +""" +src/network/invthread.py +======================== +""" import Queue import random from time import time @@ -32,9 +36,13 @@ def handleExpiredDandelion(expired): class InvThread(StoppableThread): + """A thread to manage inventory""" + name = "InvBroadcaster" - def handleLocallyGenerated(self, stream, hashId): + @staticmethod + def handleLocallyGenerated(stream, hashId): + """Locally generated inventory items require special handling""" Dandelion().addHash(hashId, stream=stream) for connection in \ BMConnectionPool().inboundConnections.values() + \ @@ -43,8 +51,8 @@ class InvThread(StoppableThread): continue connection.objectsNewToThem[hashId] = time() - def run(self): - while not state.shutdown: + def run(self): # pylint: disable=too-many-branches + while not state.shutdown: # pylint: disable=too-many-nested-blocks chunk = [] while True: # Dandelion fluff trigger by expiration From 77651eebe3536023e98e47e1c42498b204c29af4 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 5 Sep 2019 20:09:11 +0530 Subject: [PATCH 071/306] objecttracker flake8 fixes --- src/network/objectracker.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index f119b2d8..304cbc65 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -85,15 +85,15 @@ class ObjectTracker(object): self.objectsNewToMe[hashId] = True def handleReceivedObject(self, streamNumber, hashid): - for i in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): + for i in network.connectionpool.BMConnectionPool().inboundConnections.values( + ) + network.connectionpool.BMConnectionPool().outboundConnections.values(): if not i.fullyEstablished: continue try: del i.objectsNewToMe[hashid] except KeyError: - if streamNumber in i.streams and \ - (not Dandelion().hasHash(hashid) or \ - Dandelion().objectChildStem(hashid) == i): + if streamNumber in i.streams and ( + not Dandelion().hasHash(hashid) or Dandelion().objectChildStem(hashid) == i): with i.objectsNewToThemLock: i.objectsNewToThem[hashid] = time.time() # update stream number, which we didn't have when we just received the dinv @@ -116,16 +116,18 @@ class ObjectTracker(object): if haveBloom: self.addrBloom.add(hashid) -# addr sending -> per node upload queue, and flush every minute or so -# inv sending -> if not in bloom, inv immediately, otherwise put into a per node upload queue and flush every minute or so -# data sending -> a simple queue -# no bloom -# - if inv arrives -# - if we don't have it, add tracking and download queue -# - if we do have it, remove from tracking -# tracking downloads -# - per node hash of items the node has but we don't -# tracking inv -# - per node hash of items that neither the remote node nor we have -# +""" + addr sending -> per node upload queue, and flush every minute or so + inv sending -> if not in bloom, inv immediately, otherwise put into a per node upload queue + and flush every minute or so + data sending -> a simple queue + no bloom + - if inv arrives + - if we don't have it, add tracking and download queue + - if we do have it, remove from tracking + tracking downloads + - per node hash of items the node has but we don't + tracking inv + - per node hash of items that neither the remote node nor we have +""" From db1593f428df3a28b5f93c03cd95d5bf0efaaf80 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 6 Sep 2019 14:36:51 +0530 Subject: [PATCH 072/306] https flake8 fixes --- src/network/https.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/network/https.py b/src/network/https.py index 151efcb8..a7b8b57c 100644 --- a/src/network/https.py +++ b/src/network/https.py @@ -1,10 +1,18 @@ import asyncore from http import HTTPClient -import paths from tls import TLSHandshake -# self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') +""" +self.sslSock = ssl.wrap_socket( + self.sock, + keyfile=os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), + certfile=os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), + server_side=not self.initiatedConnection, + ssl_version=ssl.PROTOCOL_TLSv1, + do_handshake_on_connect=False, + ciphers='AECDH-AES256-SHA') +""" class HTTPSClient(HTTPClient, TLSHandshake): @@ -12,7 +20,15 @@ class HTTPSClient(HTTPClient, TLSHandshake): if not hasattr(self, '_map'): asyncore.dispatcher.__init__(self) self.tlsDone = False -# TLSHandshake.__init__(self, address=(host, 443), certfile='/home/shurdeek/src/PyBitmessage/sslsrc/keys/cert.pem', keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', server_side=False, ciphers='AECDH-AES256-SHA') + """ + TLSHandshake.__init__( + self, + address=(host, 443), + certfile='/home/shurdeek/src/PyBitmessage/sslsrc/keys/cert.pem', + keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', + server_side=False, + ciphers='AECDH-AES256-SHA') + """ HTTPClient.__init__(self, host, path, connect=False) TLSHandshake.__init__(self, address=(host, 443), server_side=False) @@ -49,6 +65,7 @@ class HTTPSClient(HTTPClient, TLSHandshake): else: TLSHandshake.handle_write(self) + if __name__ == "__main__": client = HTTPSClient('anarchy.economicsofbitcoin.com', '/') asyncore.loop() From fa6ef4f933e1c23e03c996ec66b259795b49d17f Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 6 Sep 2019 15:58:06 +0530 Subject: [PATCH 073/306] objectracker pylint fixes --- src/network/objectracker.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 304cbc65..a8e3292a 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -1,3 +1,7 @@ +""" +src/network/objectracker.py +=========================== +""" import time from threading import RLock @@ -27,6 +31,7 @@ missingObjects = {} class ObjectTracker(object): + """Object tracker mixin""" invCleanPeriod = 300 invInitialCapacity = 50000 invErrorRate = 0.03 @@ -42,21 +47,24 @@ class ObjectTracker(object): self.lastCleaned = time.time() def initInvBloom(self): + """Init bloom filter for tracking. WIP.""" if haveBloom: # lock? self.invBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, error_rate=ObjectTracker.invErrorRate) def initAddrBloom(self): + """Init bloom filter for tracking addrs, WIP. This either needs to be moved to addrthread.py or removed.""" if haveBloom: # lock? self.addrBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, error_rate=ObjectTracker.invErrorRate) def clean(self): + """Clean up tracking to prevent memory bloat""" if self.lastCleaned < time.time() - ObjectTracker.invCleanPeriod: if haveBloom: - if len(missingObjects) == 0: + if missingObjects == 0: self.initInvBloom() self.initAddrBloom() else: @@ -67,12 +75,13 @@ class ObjectTracker(object): self.lastCleaned = time.time() def hasObj(self, hashid): + """Do we already have object?""" if haveBloom: return hashid in self.invBloom - else: - return hashid in self.objectsNewToMe + return hashid in self.objectsNewToMe def handleReceivedInventory(self, hashId): + """Handling received inventory""" if haveBloom: self.invBloom.add(hashId) try: @@ -85,6 +94,7 @@ class ObjectTracker(object): self.objectsNewToMe[hashId] = True def handleReceivedObject(self, streamNumber, hashid): + """Handling received object""" for i in network.connectionpool.BMConnectionPool().inboundConnections.values( ) + network.connectionpool.BMConnectionPool().outboundConnections.values(): if not i.fullyEstablished: @@ -109,25 +119,12 @@ class ObjectTracker(object): self.objectsNewToMe.setLastObject() def hasAddr(self, addr): + """WIP, should be moved to addrthread.py or removed""" if haveBloom: return addr in self.invBloom + return None def addAddr(self, hashid): + """WIP, should be moved to addrthread.py or removed""" if haveBloom: self.addrBloom.add(hashid) - - -""" - addr sending -> per node upload queue, and flush every minute or so - inv sending -> if not in bloom, inv immediately, otherwise put into a per node upload queue - and flush every minute or so - data sending -> a simple queue - no bloom - - if inv arrives - - if we don't have it, add tracking and download queue - - if we do have it, remove from tracking - tracking downloads - - per node hash of items the node has but we don't - tracking inv - - per node hash of items that neither the remote node nor we have -""" From 253cec15c4ab0c771120b9e056a6d51e1fc079fb Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 6 Sep 2019 19:04:52 +0530 Subject: [PATCH 074/306] proxy flake8 fixes --- src/network/httpd.py | 66 ++++++++++++++++++++++------------------ src/network/invthread.py | 2 +- src/network/proxy.py | 12 ++++++-- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/network/httpd.py b/src/network/httpd.py index ba53c7fc..b69ffa99 100644 --- a/src/network/httpd.py +++ b/src/network/httpd.py @@ -1,3 +1,7 @@ +""" +src/network/httpd.py +======================= +""" import asyncore import socket @@ -5,25 +9,26 @@ from tls import TLSHandshake class HTTPRequestHandler(asyncore.dispatcher): + """Handling HTTP request""" response = """HTTP/1.0 200 OK\r -Date: Sun, 23 Oct 2016 18:02:00 GMT\r -Content-Type: text/html; charset=UTF-8\r -Content-Encoding: UTF-8\r -Content-Length: 136\r -Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\r -Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)\r -ETag: "3f80f-1b6-3e1cb03b"\r -Accept-Ranges: bytes\r -Connection: close\r -\r - - - An Example Page - - - Hello World, this is a very simple HTML document. - -""" + Date: Sun, 23 Oct 2016 18:02:00 GMT\r + Content-Type: text/html; charset=UTF-8\r + Content-Encoding: UTF-8\r + Content-Length: 136\r + Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\r + Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)\r + ETag: "3f80f-1b6-3e1cb03b"\r + Accept-Ranges: bytes\r + Connection: close\r + \r + + + An Example Page + + + Hello World, this is a very simple HTML document. + + """ def __init__(self, sock): if not hasattr(self, '_map'): @@ -63,10 +68,11 @@ Connection: close\r class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): + """Handling HTTPS request""" def __init__(self, sock): if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self, sock) -# self.tlsDone = False + asyncore.dispatcher.__init__(self, sock) # pylint: disable=non-parent-init-called + # self.tlsDone = False TLSHandshake.__init__( self, sock=sock, @@ -87,8 +93,7 @@ class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): def readable(self): if self.tlsDone: return HTTPRequestHandler.readable(self) - else: - return TLSHandshake.readable(self) + return TLSHandshake.readable(self) def handle_read(self): if self.tlsDone: @@ -99,8 +104,7 @@ class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): def writable(self): if self.tlsDone: return HTTPRequestHandler.writable(self) - else: - return TLSHandshake.writable(self) + return TLSHandshake.writable(self) def handle_write(self): if self.tlsDone: @@ -110,6 +114,7 @@ class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): class HTTPServer(asyncore.dispatcher): + """Handling HTTP Server""" port = 12345 def __init__(self): @@ -125,14 +130,15 @@ class HTTPServer(asyncore.dispatcher): pair = self.accept() if pair is not None: sock, addr = pair -# print 'Incoming connection from %s' % repr(addr) + # print 'Incoming connection from %s' % repr(addr) self.connections += 1 -# if self.connections % 1000 == 0: -# print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) + # if self.connections % 1000 == 0: + # print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) HTTPRequestHandler(sock) class HTTPSServer(HTTPServer): + """Handling HTTPS Server""" port = 12345 def __init__(self): @@ -143,10 +149,10 @@ class HTTPSServer(HTTPServer): pair = self.accept() if pair is not None: sock, addr = pair -# print 'Incoming connection from %s' % repr(addr) + # print 'Incoming connection from %s' % repr(addr) self.connections += 1 -# if self.connections % 1000 == 0: -# print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) + # if self.connections % 1000 == 0: + # print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) HTTPSRequestHandler(sock) diff --git a/src/network/invthread.py b/src/network/invthread.py index cf202012..ad3a0764 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -36,7 +36,7 @@ def handleExpiredDandelion(expired): class InvThread(StoppableThread): - """A thread to manage inventory""" + """A thread to send inv annoucements.""" name = "InvBroadcaster" diff --git a/src/network/proxy.py b/src/network/proxy.py index 04f0ac13..6f6d256a 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -1,3 +1,8 @@ +""" +src/network/proxy.py +==================== +""" +# pylint: disable=protected-access import socket import time @@ -56,7 +61,7 @@ class Proxy(AdvancedDispatcher): def proxy(self, address): """Set proxy IP and port""" if (not isinstance(address, tuple) or len(address) < 2 or - not isinstance(address[0], str) or + not isinstance(address[0], str) or not isinstance(address[1], int)): raise ValueError self.__class__._proxy = address @@ -83,8 +88,8 @@ class Proxy(AdvancedDispatcher): def onion_proxy(self, address): """Set onion proxy address""" if address is not None and ( - not isinstance(address, tuple) or len(address) < 2 or - not isinstance(address[0], str) or + not isinstance(address, tuple) or len(address) < 2 or + not isinstance(address[0], str) or not isinstance(address[1], int)): raise ValueError self.__class__._onion_proxy = address @@ -106,6 +111,7 @@ class Proxy(AdvancedDispatcher): self.destination = address self.isOutbound = True self.fullyEstablished = False + self.connectedAt = 0 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) if BMConfigParser().safeGetBoolean( "bitmessagesettings", "socksauthentication"): From 63fd415ae7482bd40b1fc4fab43656121584c536 Mon Sep 17 00:00:00 2001 From: Navjot Date: Wed, 11 Sep 2019 20:33:51 +0530 Subject: [PATCH 075/306] worked on UI design --- src/bitmessagekivy/main.kv | 69 +++---------- src/bitmessagekivy/mpybit.py | 193 +++++++++++++++++++++-------------- src/state.py | 6 +- 3 files changed, 133 insertions(+), 135 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index e5b0340c..84cf21dd 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -63,7 +63,7 @@ id: btn pos_hint:{"x":0,"y":.25} option_cls: Factory.get("MySpinnerOption") - font_size: '12.5sp' + font_size: '11.9sp' text: app.getDefaultAccData() background_color: color_button if self.state == 'normal' else color_button_pressed background_down: 'atlas://data/images/defaulttheme/spinner' @@ -180,19 +180,7 @@ NavigationLayout: background_palette: 'Primary' background_hue: '500' left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]] - Button: - id: myButton - size_hint_y: 0.35 - size_hint_x: 0.2 - pos_hint: {'x': .1, 'y': 0.3} - color: 0,0,0,1 - background_color: (0,0,0,0) - on_press:app.addingtoaddressbook() - Image: - source: './images/addressbookadd.png' - center_x: self.parent.center_x - center_y: self.parent.center_y - size: 55, 55 + right_action_items: [['account-plus', lambda x: app.addingtoaddressbook()]] BoxLayout: id: search_bar size_hint_y: None @@ -350,7 +338,7 @@ NavigationLayout: id: txt_input size_hint_y: None font_size: '13sp' - height: 70 + height: 50 hint_text: 'type or search recipients address starting with BM-' RV: id: rv @@ -374,17 +362,6 @@ NavigationLayout: helper_text_mode: "on_error" BoxLayout: spacing:50 - AnchorLayout: - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.send(app) - MDLabel: - font_style: 'Title' - text: 'send' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' AnchorLayout: MDRaisedButton: size_hint: 1, None @@ -643,9 +620,11 @@ NavigationLayout: ScrollView: do_scroll_x: False BoxLayout: - orientation: 'horizontal' + orientation: 'vertical' padding: dp(20) spacing: 10 + size_hint_y: None + height: self.minimum_height + dp(app.window_size[1]) if app.window_size[1] > app.window_size[0] else dp(app.window_size[0]) BoxLayout: orientation: 'vertical' padding: dp(5) @@ -665,7 +644,7 @@ NavigationLayout: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' - text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + text: 'We provide subscriptions for proof of work calculation for first month. ' halign: 'center' MDLabel: font_style: 'Headline' @@ -677,7 +656,7 @@ NavigationLayout: height: dp(40) MDLabel: font_style: 'Title' - text: 'Select' + text: 'Get Credits' font_size: '13sp' color: (1,1,1,1) halign: 'center' @@ -700,7 +679,7 @@ NavigationLayout: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' - text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + text: 'We provide for proof of work calculation for six month. ' halign: 'center' MDLabel: font_style: 'Headline' @@ -712,7 +691,7 @@ NavigationLayout: height: dp(40) MDLabel: font_style: 'Title' - text: 'Select' + text: 'Get Credits' font_size: '13sp' color: (1,1,1,1) halign: 'center' @@ -735,7 +714,7 @@ NavigationLayout: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' - text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + text: 'We provide for proof of work calculation for 1years. ' halign: 'center' MDLabel: font_style: 'Headline' @@ -747,7 +726,7 @@ NavigationLayout: height: dp(40) MDLabel: font_style: 'Title' - text: 'Select' + text: 'Get Credits' font_size: '13sp' color: (1,1,1,1) halign: 'center' @@ -915,7 +894,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(400) + self.minimum_height + height: dp(500) + self.minimum_height padding: dp(32) MDLabel: font_style: 'Headline' @@ -952,28 +931,6 @@ NavigationLayout: orientation: 'vertical' size_hint_y: None height: dp(100) + self.minimum_height - BoxLayout: - spacing:20 - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.inbox_reply() if root.page_type == 'inbox' else root.write_msg(app) if root.page_type == 'draft' else root.copy_sent_mail() - MDLabel: - font_style: 'Title' - text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.delete_mail() - MDLabel: - font_style: 'Title' - text: 'Delete' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' : id: cpyButton diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 48ff4738..ebabdcc4 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -61,7 +61,8 @@ import state from uikivysignaler import UIkivySignaler -import identiconGeneration +if platform == 'linux': + import identiconGeneration import os @@ -540,6 +541,7 @@ class DropDownWidget(BoxLayout): queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" self.parent.parent.current = 'inbox' + state.in_composer = True navApp.back_press() toast('send') return None @@ -554,29 +556,15 @@ class DropDownWidget(BoxLayout): # pylint: disable=attribute-defined-outside-init def address_error_message(self, msg): """Show Error Message.""" - self.box = FloatLayout() - self.lab = (Label( + msg_dialog = MDDialog( text=msg, - font_size=25, - size_hint=(None, None), - pos_hint={'x': .25, 'y': .6})) - self.box.add_widget(self.lab) - self.but = (Button( - text="dismiss", - size_hint=(None, None), - width=200, - height=50, - pos_hint={'x': .3, 'y': 0})) - self.box.add_widget(self.but) - self.main_pop = Popup( - title="Error", - content=self.box, - size_hint=(None, None), - size=(550, 400), - auto_dismiss=False, - title_size=30) - self.but.bind(on_press=self.main_pop.dismiss) - self.main_pop.open() + title='', size_hint=(.8, .25), text_button_ok='Ok', + events_callback=self.callback_for_menu_items) + msg_dialog.open() + + def callback_for_menu_items(self, text_item): + """Method is used for getting the callback of alert box""" + toast(text_item) def reset_composer(self): """Method will reset composer.""" @@ -984,6 +972,7 @@ class NavigateApp(App): variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() state.screen_density = Window.size + window_size = state.screen_density title = "PyBitmessage" imgstatus = False count = 0 @@ -1037,21 +1026,22 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" - self.set_identicon(text) + if platform == 'linux': + self.set_identicon(text) address_label = self.current_address_label( BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label state.association = text self.root.ids.sc1.clear_widgets() - self.root.ids.sc4.clear_widgets() - self.root.ids.sc5.clear_widgets() - self.root.ids.sc16.clear_widgets() - self.root.ids.sc17.clear_widgets() self.root.ids.sc1.add_widget(Inbox()) - self.root.ids.sc4.add_widget(Sent()) - self.root.ids.sc5.add_widget(Trash()) - self.root.ids.sc16.add_widget(Draft()) - self.root.ids.sc17.add_widget(Allmails()) + # self.root.ids.sc4.clear_widgets() + # self.root.ids.sc5.clear_widgets() + # self.root.ids.sc16.clear_widgets() + # self.root.ids.sc17.clear_widgets() + # self.root.ids.sc4.add_widget(Sent()) + # self.root.ids.sc5.add_widget(Trash()) + # self.root.ids.sc16.add_widget(Draft()) + # self.root.ids.sc17.add_widget(Allmails()) self.root.ids.scr_mngr.current = 'inbox' msg_counter_objs = \ @@ -1097,9 +1087,10 @@ class NavigateApp(App): def getDefaultAccData(self): """Getting Default Account Data.""" if BMConfigParser().addresses(): - img = identiconGeneration.generate(BMConfigParser().addresses()[0]) - self.createFolder('./images/default_identicon/') - img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) + if platform == 'linux': + img = identiconGeneration.generate(BMConfigParser().addresses()[0]) + self.createFolder('./images/default_identicon/') + img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' @@ -1113,8 +1104,8 @@ class NavigateApp(App): def get_default_image(self): if BMConfigParser().addresses(): - # BMConfigParser().addresses()[0] - return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + if platform == 'linux': + return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) return '' @staticmethod @@ -1131,8 +1122,9 @@ class NavigateApp(App): self.root.ids.scr_mngr.current = 'sent'\ if state.detailPageType == 'sent' else 'inbox' \ if state.detailPageType == 'inbox' else 'draft' - if state.detailPageType in ['sent', 'inbox']: - self.add_search_bar() + # if state.detailPageType in ['sent', 'inbox']: + # self.add_search_bar() + self.back_press() elif self.root.ids.scr_mngr.current == "create": composer_objs = self.root from_addr = str(self.root.ids.sc3.children[0].ids.ti.text) @@ -1140,7 +1132,6 @@ class NavigateApp(App): if from_addr and to_addr and state.detailPageType != 'draft': Draft().draft_msg(composer_objs) self.root.ids.scr_mngr.current = 'inbox' - self.add_search_bar() self.back_press() elif self.root.ids.scr_mngr.current == "showqrcode": self.root.ids.scr_mngr.current = 'myaddress' @@ -1175,25 +1166,30 @@ class NavigateApp(App): composer_obj.txt_input.text = '' composer_obj.subject.text = '' composer_obj.body.text = '' + state.in_composer = True def set_navbar_for_composer(self): """This method is used for clearing toolbar data when composer open""" self.root.ids.toolbar.left_action_items = [ ['arrow-left', lambda x: self.back_press()]] - self.root.ids.myButton.opacity = 0 - self.root.ids.myButton.disabled = True + self.root.ids.toolbar.right_action_items = [ + ['send', lambda x: self.root.ids.sc3.children[0].send(self)]] def back_press(self): """Method used for going back from composer to previous page.""" - self.root.ids.myButton.opacity = 1 - self.root.ids.myButton.disabled = False + 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.scr_mngr.current = 'inbox' + self.root.ids.scr_mngr.current = 'inbox' if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType self.root.ids.scr_mngr.transition.direction = 'right' self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) - self.add_search_bar() + if state.is_allmail or state.detailPageType == 'draft': + state.is_allmail = False + else: + self.add_search_bar() state.detailPageType = '' + state.in_composer = False @staticmethod def on_stop(): @@ -1275,8 +1271,24 @@ class NavigateApp(App): self.root.ids.sc4.add_widget(Sent()) self.root.ids.scr_mngr.current = state.search_screen + def clearSreeen(self, text): + if text == 'Sent': + self.root.ids.sc4.clear_widgets() + self.root.ids.sc4.add_widget(Sent()) + elif text == 'Draft': + self.root.ids.sc16.clear_widgets() + self.root.ids.sc16.add_widget(Draft()) + elif text == 'Trash': + self.root.ids.sc5.clear_widgets() + self.root.ids.sc5.add_widget(Trash()) + elif text == 'All Mails': + self.root.ids.sc17.clear_widgets() + self.root.ids.sc17.add_widget(Allmails()) + def check_search_screen(self, instance): """Method show search button only on inbox or sent screen.""" + if instance.text in ['Sent', 'Draft', 'Trash', 'All Mails']: + self.clearSreeen(instance.text) if instance.text in ['Inbox', 'Sent', 'Address Book', 'My Addresses']: if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget( @@ -1311,6 +1323,19 @@ class NavigateApp(App): def address_identicon(self): return './images/drawer_logo1.png' + def set_mail_detail_header(self): + 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 + class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1470,11 +1495,13 @@ class MailDetail(Screen): state.status = self state.ackdata = data[0][5] self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() elif state.detailPageType == 'inbox': data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox \ where received = {};".format(state.sentMailTime)) self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() def assign_mail_details(self, data): """Assigning mail details.""" @@ -1485,19 +1512,22 @@ class MailDetail(Screen): self.message = data[0][3] if len(data[0]) == 6: self.status = data[0][4] + state.write_msg = {'to_addr': self.to_addr, + 'from_addr': self.from_addr, + 'subject': self.subject, + 'message': self.message} def delete_mail(self): """Method for mail delete.""" - msg_count_objs = \ - self.parent.parent.parent.parent.parent.children[2].children[0].ids + msg_count_objs = state.kivyapp.root.children[2].children[0].ids if state.detailPageType == 'sent': sqlExecute( "UPDATE sent SET folder = 'trash' WHERE \ lastactiontime = {};".format(state.sentMailTime)) msg_count_objs.send_cnt.badge_text = str(int(state.sent_count) - 1) state.sent_count = str(int(state.sent_count) - 1) - self.parent.parent.screens[3].clear_widgets() - self.parent.parent.screens[3].add_widget(Sent()) + self.parent.screens[3].clear_widgets() + self.parent.screens[3].add_widget(Sent()) elif state.detailPageType == 'inbox': sqlExecute( "UPDATE inbox SET folder = 'trash' WHERE \ @@ -1505,21 +1535,27 @@ class MailDetail(Screen): msg_count_objs.inbox_cnt.badge_text = str( int(state.inbox_count) - 1) state.inbox_count = str(int(state.inbox_count) - 1) - self.parent.parent.screens[0].clear_widgets() - self.parent.parent.screens[0].add_widget(Inbox()) - if state.is_allmail: - self.parent.parent.current = 'allmails' - state.is_allmail = False - else: - self.parent.parent.current = state.detailPageType - msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) - msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) - state.all_count = str(int(state.all_count) - 1) - self.parent.parent.screens[4].clear_widgets() - self.parent.parent.screens[4].add_widget(Trash()) - self.parent.parent.screens[16].clear_widgets() - self.parent.parent.screens[16].add_widget(Allmails()) + self.parent.screens[0].clear_widgets() + self.parent.screens[0].add_widget(Inbox()) + elif state.detailPageType == 'draft': + sqlExecute("DELETE FROM sent WHERE lastactiontime = '{}';".format( + state.sentMailTime)) + msg_count_objs.draft_cnt.badge_text = str(int(state.draft_count) - 1) + state.draft_count = str(int(state.draft_count) - 1) + self.parent.screens[15].clear_widgets() + self.parent.screens[15].add_widget(Draft()) + + self.parent.current = 'allmails' if state.is_allmail else state.detailPageType + if state.detailPageType != 'draft': + msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + self.parent.screens[16].clear_widgets() + self.parent.screens[16].add_widget(Allmails()) + state.kivyapp.back_press() toast('Deleted') def inbox_reply(self): @@ -1527,12 +1563,14 @@ class MailDetail(Screen): data = sqlQuery( "select toaddress, fromaddress, subject, message from inbox where \ received = {};".format(state.sentMailTime)) - composer_obj = self.parent.parent.screens[2].children[0].ids - composer_obj.ti.text = data[0][1] - composer_obj.btn.text = data[0][1] - composer_obj.txt_input.text = data[0][0] + composer_obj = self.parent.screens[2].children[0].ids + composer_obj.ti.text = data[0][0] + composer_obj.btn.text = data[0][0] + composer_obj.txt_input.text = data[0][1] composer_obj.subject.text = data[0][2] - self.parent.parent.current = 'create' + state.kivyapp.root.ids.sc3.children[0].ids.rv.data = '' + self.parent.current = 'create' + state.kivyapp.set_navbar_for_composer() def copy_sent_mail(self): """Method used for copying sent mail to the composer.""" @@ -1542,14 +1580,13 @@ class MailDetail(Screen): """Method used to write on draft mail.""" state.send_draft_mail = state.sentMailTime composer_ids = \ - self.parent.parent.parent.parent.parent.ids.sc3.children[0].ids - composer_ids.ti.text = self.from_addr - composer_ids.btn.text = self.from_addr - composer_ids.txt_input.text = self.to_addr - composer_ids.subject.text = '' \ - if self.subject == '(no subject)' else self.subject.lower() - composer_ids.body.text = self.message - self.parent.parent.current = 'create' + self.parent.parent.parent.parent.ids.sc3.children[0].ids + composer_ids.ti.text = state.write_msg['from_addr'] + composer_ids.btn.text = state.write_msg['from_addr'] + composer_ids.txt_input.text = state.write_msg['to_addr'] + composer_ids.subject.text = state.write_msg['subject'] + composer_ids.body.text = state.write_msg['message'] + self.parent.current = 'create' navApp.set_navbar_for_composer() def copy_composer_text(self, instance, *args): diff --git a/src/state.py b/src/state.py index c3e71382..fb8351d7 100644 --- a/src/state.py +++ b/src/state.py @@ -106,4 +106,8 @@ search_screen = '' send_draft_mail = None -is_allmail = False \ No newline at end of file +is_allmail = False + +in_composer = False + +write_msg = {} \ No newline at end of file From 236beaedf6894994f3e26454cc12b46d6c99ad82 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 12 Sep 2019 14:41:33 +0530 Subject: [PATCH 076/306] mpybit flake8 fixes --- src/bitmessagekivy/mpybit.py | 12 ++++++------ .../BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png | Bin 0 -> 461 bytes 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 740c0bb2..0a6eb023 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,10 +1,12 @@ """Coding: utf-8.""" +import os import time from functools import partial from bmconfigparser import BMConfigParser from helper_sql import sqlExecute, sqlQuery from kivy.app import App 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 @@ -18,7 +20,6 @@ from kivy.uix.behaviors import FocusBehavior from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.carousel import Carousel -from kivy.uix.floatlayout import FloatLayout from kivy.uix.image import Image from kivy.uix.label import Label from kivy.uix.popup import Popup @@ -51,13 +52,11 @@ import queues from semaphores import kivyuisignaler import state from uikivysignaler import UIkivySignaler +# pylint: disable=unused-argument, too-few-public-methods + if platform == 'linux': import identiconGeneration - -import os -from kivy.core.clipboard import Clipboard -# pylint: disable=unused-argument, too-few-public-methods def toast(text): @@ -1168,7 +1167,8 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods [['account-plus', lambda x: self.addingtoaddressbook()]] self.root.ids.toolbar.left_action_items = \ [['menu', lambda x: self.root.toggle_nav_drawer()]] - self.root.ids.scr_mngr.current = 'inbox' if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType + self.root.ids.scr_mngr.current = 'inbox' \ + if state.in_composer else 'allmails' if state.is_allmail else state.detailPageType 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': diff --git a/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png b/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png new file mode 100644 index 0000000000000000000000000000000000000000..22def0cd17aa71234a0ab0ad8237d8795055e7e1 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV4ULV;uumf=k1-1yiATf3Z%_+g}Yo_3`3Vh(#~4LV0gIt_b?d2K{=@9ASpvIdCKIWUk%% zP43a<{r?Wk{I$^JBpV@*Ky^y*7BuFk|yI+#2Mtc{jm*(GOW^ fqJoW6;T`WBd$}JI#g{z=MiYaltDnm{r-UW|*9?{7 literal 0 HcmV?d00001 From 3686acf4d206f0dfc3e51b1aef2353fbefe80108 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 12 Sep 2019 15:13:11 +0530 Subject: [PATCH 077/306] mpybit pylint fixes --- src/bitmessagekivy/mpybit.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 0a6eb023..d5bda558 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,4 +1,5 @@ """Coding: utf-8.""" +# pylint: disable=relative-import, too-many-lines import os import time from functools import partial @@ -62,7 +63,7 @@ if platform == 'linux': def toast(text): """Method will display the toast message.""" if platform == 'linux': - from kivymd.toast.kivytoast import toast + from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name toast(text) return @@ -552,7 +553,8 @@ class DropDownWidget(BoxLayout): events_callback=self.callback_for_menu_items) msg_dialog.open() - def callback_for_menu_items(self, text_item): + @staticmethod + def callback_for_menu_items(text_item): """Method is used for getting the callback of alert box""" toast(text_item) @@ -1259,6 +1261,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods self.root.ids.scr_mngr.current = state.search_screen def clearSreeen(self, text): + """Method is used for clear screen""" if text == 'Sent': self.root.ids.sc4.clear_widgets() self.root.ids.sc4.add_widget(Sent()) @@ -1291,7 +1294,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods return def add_search_bar(self): - """Method used for adding search function on screen.""" + """Method used for adding search function on screen""" if not self.root.ids.search_bar.children: self.root.ids.search_bar.add_widget(MDIconButton(icon='magnify')) text_field = MDTextField( @@ -1313,6 +1316,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods return './images/drawer_logo1.png' def set_mail_detail_header(self): + """Method is used for setting the details of the page""" 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()] From a1bd95fedb4dfa24ccc1492fbf757a54ae2c66d8 Mon Sep 17 00:00:00 2001 From: Navjot Date: Mon, 16 Sep 2019 15:51:05 +0530 Subject: [PATCH 078/306] wokred on implementing free credit functionality in subscription package --- src/bitmessagekivy/main.kv | 80 +++++++++++++++++++++++++++++++----- src/bitmessagekivy/mpybit.py | 15 ++++++- src/state.py | 4 +- 3 files changed, 86 insertions(+), 13 deletions(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 84cf21dd..78b52d97 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -146,6 +146,11 @@ icon:'wallet' on_release: app.root.ids.scr_mngr.current = 'payment' on_press: app.check_search_screen(self) + NavigationDrawerIconButton: + text: "Credits" + icon:'wallet' + on_release: app.root.ids.scr_mngr.current = 'credits' + on_press: app.check_search_screen(self) NavigationDrawerIconButton: text: "new address" icon:'account-plus' @@ -230,6 +235,8 @@ NavigationLayout: id:sc16 Allmails: id:sc17 + Credits: + id:sc18 : @@ -293,6 +300,28 @@ NavigationLayout: : name: 'create' +: + name: 'credits' + ScrollView: + do_scroll_x: False + MDList: + id: ml + size_hint_y: None + height: dp(200) + OneLineListItem: + text: "Available Credits" + BoxLayout: + AnchorLayout: + MDRaisedButton: + size_hint: .6, .35 + height: dp(40) + MDLabel: + font_style: 'Title' + text: root.available_credits + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + : ScrollView: BoxLayout: @@ -621,8 +650,8 @@ NavigationLayout: do_scroll_x: False BoxLayout: orientation: 'vertical' - padding: dp(20) - spacing: 10 + padding: [dp(app.window_size[0]/4*1.1), dp(10)] + spacing: 12 size_hint_y: None height: self.minimum_height + dp(app.window_size[1]) if app.window_size[1] > app.window_size[0] else dp(app.window_size[0]) BoxLayout: @@ -630,7 +659,7 @@ NavigationLayout: padding: dp(5) canvas.before: Color: - rgba: 0.957, 0.890, 0.843, 1 + rgba: app.theme_cls.primary_dark Rectangle: # self here refers to the widget i.e FloatLayout pos: self.pos @@ -641,31 +670,42 @@ NavigationLayout: theme_text_color: 'Primary' text: 'Platinum' halign: 'center' + color: 1,1,1,1 MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: 'We provide subscriptions for proof of work calculation for first month. ' halign: 'center' + color: 1,1,1,1 MDLabel: + id: free_pak font_style: 'Headline' theme_text_color: 'Primary' text: '€ 50.0' halign: 'center' + color: 1,1,1,1 MDRaisedButton: + canvas: + Color: + rgb: (0.93, 0.93, 0.93) + Rectangle: + pos: self.pos + size: self.size size_hint: 1, None height: dp(40) + on_press: root.get_available_credits(self) MDLabel: font_style: 'Title' - text: 'Get Credits' + text: 'Get Free Credits' font_size: '13sp' - color: (1,1,1,1) + color: (0,0,0,1) halign: 'center' BoxLayout: orientation: 'vertical' padding: dp(5) canvas.before: Color: - rgba: 0.957, 0.890, 0.843, 1 + rgba: app.theme_cls.primary_dark Rectangle: # self here refers to the widget i.e FloatLayout pos: self.pos @@ -676,31 +716,40 @@ NavigationLayout: theme_text_color: 'Primary' text: 'Silver' halign: 'center' + color: 1,1,1,1 MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: 'We provide for proof of work calculation for six month. ' halign: 'center' + color: 1,1,1,1 MDLabel: font_style: 'Headline' theme_text_color: 'Primary' text: '€ 100.0' halign: 'center' + color: 1,1,1,1 MDRaisedButton: + canvas: + Color: + rgb: (0.93, 0.93, 0.93) + Rectangle: + pos: self.pos + size: self.size size_hint: 1, None height: dp(40) MDLabel: font_style: 'Title' - text: 'Get Credits' + text: 'Get Monthly Credits' font_size: '13sp' - color: (1,1,1,1) + color: (0,0,0,1) halign: 'center' BoxLayout: orientation: 'vertical' padding: dp(5) canvas.before: Color: - rgba: 0.957, 0.890, 0.843, 1 + rgba: app.theme_cls.primary_dark Rectangle: # self here refers to the widget i.e FloatLayout pos: self.pos @@ -711,24 +760,33 @@ NavigationLayout: theme_text_color: 'Primary' text: 'Gold' halign: 'center' + color: 1,1,1,1 MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: 'We provide for proof of work calculation for 1years. ' halign: 'center' + color: 1,1,1,1 MDLabel: font_style: 'Headline' theme_text_color: 'Primary' text: '€ 500.0' halign: 'center' + color: 1,1,1,1 MDRaisedButton: + canvas: + Color: + rgb: (0.93, 0.93, 0.93) + Rectangle: + pos: self.pos + size: self.size size_hint: 1, None height: dp(40) MDLabel: font_style: 'Title' - text: 'Get Credits' + text: 'Get Yearly Credits' font_size: '13sp' - color: (1,1,1,1) + color: (0,0,0,1) halign: 'center' diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 740c0bb2..1db89ddc 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -611,7 +611,20 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" - pass + def get_available_credits(self, instance): + state.availabe_credit = instance.parent.children[1].text + existing_credits = state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text + if len(existing_credits.split(' ')) > 1: + toast('We already have added free coins for the subscription to your account!') + else: + toast('Coins added to your account!') + state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text = '{0}'.format(state.availabe_credit) + + +class Credits(Screen): + """Credits Method""" + available_credits = StringProperty( + '{0}'.format('0')) class Login(Screen): diff --git a/src/state.py b/src/state.py index fb8351d7..fbb09390 100644 --- a/src/state.py +++ b/src/state.py @@ -110,4 +110,6 @@ is_allmail = False in_composer = False -write_msg = {} \ No newline at end of file +write_msg = {} + +availabe_credit = 0 \ No newline at end of file From 425a49edaf68b71e5302834d9f4ece186073ca5c Mon Sep 17 00:00:00 2001 From: ekta-v Date: Mon, 16 Sep 2019 16:20:40 +0530 Subject: [PATCH 079/306] update spec file for build script cross compile exe --- packages/pyinstaller/bitmessagemain.spec | 67 +++++++++++++++++------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index 06cf6e76..7f30cedf 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -1,22 +1,42 @@ import ctypes import os import time +import sys + +if ctypes.sizeof(ctypes.c_voidp) == 4: + arch=32 +else: + arch=64 + +sslName = 'OpenSSL-Win%s' % ("32" if arch == 32 else "64") +site_root = os.path.abspath(HOMEPATH) +spec_root = os.path.abspath(SPECPATH) +cdrivePath= site_root[0:3] +srcPath = spec_root[:-20]+"src\\" +qtPath = site_root+"\\PyQt4\\" +openSSLPath = cdrivePath+sslName+"\\" +msvcrDllPath = cdrivePath+"windows\\system32\\" +pythonDllPath = cdrivePath+"Python27\\" +outPath = spec_root+"\\bitmessagemain" + +importPath = srcPath +sys.path.insert(0,importPath) +os.chdir(sys.path[0]) +from version import softwareVersion -srcPath = "C:\\src\\PyBitmessage\\src\\" -qtPath = "C:\\Qt-4.8.7\\" -openSSLPath = "C:\\OpenSSL-1.0.2j\\bin\\" -outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" today = time.strftime("%Y%m%d") snapshot = False os.rename(os.path.join(srcPath, '__init__.py'), os.path.join(srcPath, '__init__.py.backup')) # -*- mode: python -*- -a = Analysis([srcPath + 'bitmessagemain.py'], +a = Analysis( + [srcPath + 'bitmessagemain.py'], pathex=[outPath], - hiddenimports=[], + hiddenimports=['pyopencl','numpy', 'win32com' , 'setuptools.msvc' ,'_cffi_backend'], hookspath=None, - runtime_hooks=None) + runtime_hooks=None + ) os.rename(os.path.join(srcPath, '__init__.py.backup'), os.path.join(srcPath, '__init__.py')) @@ -46,20 +66,17 @@ def addUIs(): a.datas += addTranslations() a.datas += addUIs() -if ctypes.sizeof(ctypes.c_voidp) == 4: - arch=32 -else: - arch=64 + a.binaries += [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), - (os.path.join('bitmsghash', 'bitmsghash%i.dll' % (arch)), os.path.join(srcPath, 'bitmsghash', 'bitmsghash%i.dll' % (arch)), 'BINARY'), - (os.path.join('bitmsghash', 'bitmsghash.cl'), os.path.join(srcPath, 'bitmsghash', 'bitmsghash.cl'), 'BINARY'), - (os.path.join('sslkeys', 'cert.pem'), os.path.join(srcPath, 'sslkeys', 'cert.pem'), 'BINARY'), - (os.path.join('sslkeys', 'key.pem'), os.path.join(srcPath, 'sslkeys', 'key.pem'), 'BINARY') - ] + ('python27.dll', pythonDllPath + 'python27.dll', 'BINARY'), + ('msvcr120.dll', msvcrDllPath + 'msvcr120.dll','BINARY'), + (os.path.join('bitmsghash', 'bitmsghash%i.dll' % (arch)), os.path.join(srcPath, 'bitmsghash', 'bitmsghash%i.dll' % (arch)), 'BINARY'), + (os.path.join('bitmsghash', 'bitmsghash.cl'), os.path.join(srcPath, 'bitmsghash', 'bitmsghash.cl'), 'BINARY'), + (os.path.join('sslkeys', 'cert.pem'), os.path.join(srcPath, 'sslkeys', 'cert.pem'), 'BINARY'), + (os.path.join('sslkeys', 'key.pem'), os.path.join(srcPath, 'sslkeys', 'key.pem'), 'BINARY') + ] -with open(os.path.join(srcPath, 'version.py'), 'rt') as f: - softwareVersion = f.readline().split('\'')[1] fname = 'Bitmessage_%s_%s.exe' % ("x86" if arch == 32 else "x64", softwareVersion) if snapshot: @@ -72,8 +89,18 @@ exe = EXE(pyz, a.zipfiles, a.datas, a.binaries, + [], name=fname, debug=False, strip=None, - upx=False, - console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) + upx=True, + console=True, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) + +coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + name='main') + From 8f848609ef6ce6e4176da466e5b6178b7266e9d1 Mon Sep 17 00:00:00 2001 From: ekta-v Date: Mon, 16 Sep 2019 16:27:08 +0530 Subject: [PATCH 080/306] added builder.sh script --- buildscripts/builder.sh | 173 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100755 buildscripts/builder.sh diff --git a/buildscripts/builder.sh b/buildscripts/builder.sh new file mode 100755 index 00000000..07949fa4 --- /dev/null +++ b/buildscripts/builder.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +# INIT +MACHINE_TYPE=`uname -m` +BASE_DIR=$(pwd) +PYTHON_VERSION=2.7.15 +PYQT_VERSION=4-4.11.4-gpl-Py2.7-Qt4.8.7 +OPENSSL_VERSION=1_0_2t +DIRECTORY32BIT=SoftwareDownloads32bit +DIRECTORY64BIT=SoftwareDownloads64bit + +if [ ${MACHINE_TYPE} == 'x86_64' ]; then + if [ ! -d "$DIRECTORY64BIT" ]; then + mkdir SoftwareDownloads64bit + cd SoftwareDownloads64bit + else + echo "Directory already exists" + cd SoftwareDownloads64bit + fi +else + if [ ! -d "$DIRECTORY32BIT" ]; then + mkdir SoftwareDownloads32bit + cd SoftwareDownloads32bit + else + echo "Directory 32 bit alrready exists" + cd SoftwareDownloads32bit + fi +fi +#Functions +function install_wine { + + + wget -nc https://dl.winehq.org/wine-builds/Release.key --no-check-certificate + sudo apt-key add Release.key + sudo apt-add-repository 'https://dl.winehq.org/wine-builds/ubuntu/' + sudo apt-get -y update + sudo apt-get -y install wine1.8 winetricks + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + sudo apt-get -y install wine64-development + env WINEPREFIX=$HOME/.wine64 WINEARCH=win64 winecfg + WINE="env WINEPREFIX=$HOME/.wine64 wine" + export WINEPREFIX + + else + sudo apt-get -y install wine32-development + env WINEPREFIX=$HOME/.wine32 WINEARCH=win32 winecfg + WINE="env WINEPREFIX=$HOME/.wine32 wine" + export WINEPREFIX + + fi +} + +function install_python(){ + echo "Download Python2.7" + + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + # For 64 bit machine + wget -nc wget http://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.amd64.msi --no-check-certificate + echo "Install Python2.7 for 64 bit" + $WINE msiexec -i python-${PYTHON_VERSION}.amd64.msi /q /norestart + + wget -nc https://download.microsoft.com/download/d/2/4/d242c3fb-da5a-4542-ad66-f9661d0a8d19/vcredist_x64.exe --no-check-certificate + $WINE vcredist_x64.exe /q /norestart + echo "Installed vcredist for 64 bit" + $WINE pip install --upgrade pip + + else + # For 32 bit machine + wget -nc https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.msi --no-check-certificate + echo "Install Python2.7 for 32 bit" + $WINE msiexec -i python-${PYTHON_VERSION}.msi /q /norestart + + echo "Installing vc_redist for 32 bit " + wget -nc https://download.microsoft.com/download/1/1/1/1116b75a-9ec3-481a-a3c8-1777b5381140/vcredist_x86.exe --no-check-certificate + $WINE vcredist_x86.exe /q /norestart + #insatlled msvcr120.dll for 32 bit system + wget -nc http://www.dll-found.com/zip/m/msvcr120.dll.zip --no-check-certificate + unzip msvcr120.dll.zip + sudo cp msvcr120.dll $HOME/.wine32/drive_c/windows/system32/ + $WINE pip install --upgrade pip + + fi +} + +function install_pyqt(){ + + echo "Download PyQT" + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + # For 64 bit machine + wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe?raw=true --no-check-certificate + $WINE PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes + else + # For 32 bit machine + wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe?raw=true --no-check-certificate + $WINE PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes + fi +} + +function install_openssl(){ + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win64OpenSSL-${OPENSSL_VERSION}.exe?raw=true --no-check-certificate + $WINE Win64OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes + + else + wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/Win32OpenSSL-${OPENSSL_VERSION}.exe?raw=true --no-check-certificate + $WINE Win32OpenSSL-${OPENSSL_VERSION}.exe /q /norestart /silent /verysiling /sp- /suppressmsgboxes + echo "Install PyInstaller 32 bit" + fi +} + +function install_pyinstaller() +{ + $WINE pip install pyinstaller + echo "Install PyInstaller" + echo "Install Pyopencl" + + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + wget -nc https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win_amd64.whl --no-check-certificate + $WINE pip install pyopencl-2015.1-cp27-none-win_amd64.whl + $WINE pip install msgpack-python + + else + wget -nc --content-disposition https://github.com/Bitmessage/ThirdPartyLibraries/blob/master/pyopencl-2015.1-cp27-none-win_amd64one-win32.whl?raw=true --no-check-certificate + $WINE pip install msgpack-python + $WINE pip install pyopencl-2015.1-cp27-none-win32.whl + fi + echo "Install Message Pack" + +} + + +function build_dll(){ + cd $BASE_DIR + rm -rf master.zip + rm -rf PyBitmessage + git clone https://github.com/Bitmessage/PyBitmessage.git + cd PyBitmessage/src/bitmsghash + if [ ${MACHINE_TYPE} == 'x86_64' ]; then + # Do stuff for 64 bit machine + echo "Install MinGW" + sudo apt-get -y install mingw-w64 + echo "Create dll" + x86_64-w64-mingw32-g++ -D_WIN32 -Wall -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -I/usr/x86_64-w64-mingw32/include -L$HOME/.wine64/drive_c/OpenSSL-Win64/lib -c bitmsghash.cpp + x86_64-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine64/drive_c/OpenSSL-Win64/include -L$HOME/.wine64/drive_c/OpenSSL-Win64 -L/usr/lib/x86_64-linux-gnu/wine -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash64.dll -Wl,--out-implib,bitmsghash.a + echo "DLL generated successfully " + cd .. + cp -R bitmsghash ../../../src/ + cd ../../../ + cd packages/pyinstaller/ + env WINEPREFIX=$HOME/.wine64 wine pyinstaller bitmessagemain.spec + else + echo "Install MinGW for 32 bit" + sudo apt-get install mingw-w64 + echo "Create dll" + + + i686-w64-mingw32-g++ -D_WIN32 -Wall -m32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -I/usr/i686-w64-mingw32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib -c bitmsghash.cpp + i686-w64-mingw32-g++ -static-libgcc -shared bitmsghash.o -D_WIN32 -O3 -march=native -I$HOME/.wine32/drive_c/OpenSSL-Win32/include -L$HOME/.wine32/drive_c/OpenSSL-Win32/lib/MinGW -fPIC -shared -lcrypt32 -leay32 -lwsock32 -o bitmsghash32.dll -Wl,--out-implib,bitmsghash.a + cd .. + cp -R bitmsghash ../../../src/ + cd ../../../ + cd packages/pyinstaller/ + env WINEPREFIX=$HOME/.wine32 wine pyinstaller bitmessagemain.spec + fi +} + + +install_wine +install_python +install_pyqt +install_openssl +install_pyinstaller +build_dll From 3d80fe94c7c04d8982d4e63173a3abb6c0c9c410 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 16 Sep 2019 18:16:07 +0530 Subject: [PATCH 081/306] mpybit flake8 fixes --- src/bitmessagekivy/mpybit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 8e9d4e30..b3b78e95 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -619,7 +619,8 @@ class Payment(Screen): toast('We already have added free coins for the subscription to your account!') else: toast('Coins added to your account!') - state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text = '{0}'.format(state.availabe_credit) + state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[ + 0].children[0].text = '{0}'.format(state.availabe_credit) class Credits(Screen): From a25ce191bf026d9d3e74b5e08d01e924611f8f29 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Mon, 16 Sep 2019 18:19:07 +0530 Subject: [PATCH 082/306] mpybit pylint fixes --- src/bitmessagekivy/mpybit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b3b78e95..be4be868 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -612,7 +612,8 @@ class MyTextInput(TextInput): class Payment(Screen): """Payment Method.""" - def get_available_credits(self, instance): + def get_available_credits(self, instance): # pylint: disable=no-self-use + """Method helps to get the available credits""" state.availabe_credit = instance.parent.children[1].text existing_credits = state.kivyapp.root.ids.sc18.ids.ml.children[0].children[0].children[0].children[0].text if len(existing_credits.split(' ')) > 1: @@ -1470,7 +1471,7 @@ class NavigationDrawerTwoLineListItem( def _update_specific_text_color(self, instance, value): pass - def _set_active(self, active, list): + def _set_active(self, active, list): # pylint: disable=redefined-builtin pass From 79d1b1b9e281037aca05db78dc174a87c8af6c33 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 10 Sep 2019 14:51:02 +0530 Subject: [PATCH 083/306] socks4a pylint fixes --- src/network/socks4a.py | 8 +++++++- src/network/udp.py | 5 +---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/network/socks4a.py b/src/network/socks4a.py index bdf59944..f0b234f5 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -1,3 +1,8 @@ +""" +src/network/socks4a.py +================================= +""" +# pylint: disable=attribute-defined-outside-init import socket import struct @@ -82,7 +87,7 @@ class Socks4aConnection(Socks4a): self.append_write_buf(self.ipaddr) except socket.error: # Well it's not an IP number, so it's probably a DNS name. - if Proxy._remote_dns: + if self._remote_dns: # Resolve remotely rmtrslv = True self.ipaddr = None @@ -118,6 +123,7 @@ class Socks4aResolver(Socks4a): Socks4a.__init__(self, address=(self.host, self.port)) def state_auth_done(self): + """Request connection to be made""" # Now we can request the actual connection self.append_write_buf( struct.pack('>BBH', 0x04, 0xF0, self.destination[1])) diff --git a/src/network/udp.py b/src/network/udp.py index 225aabf3..33504289 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -124,10 +124,7 @@ class UDPSocket(BMProto): self.destination = state.Peer(*addr) encodedAddr = protocol.encodeHost(addr[0]) - if protocol.checkIPAddress(encodedAddr, True): - self.local = True - else: - self.local = False + self.local = bool(protocol.checkIPAddress(encodedAddr, True)) # overwrite the old buffer to avoid mixing data and so that # self.local works correctly self.read_buf[0:] = recdata From 8182e159df8d1df294381ae657d9914e10ca246a Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 10 Sep 2019 14:55:07 +0530 Subject: [PATCH 084/306] socks5 flake8 fixes --- src/network/socks5.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/network/socks5.py b/src/network/socks5.py index 2e0821da..86616f30 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -66,10 +66,9 @@ class Socks5(Proxy): elif ret[1] == 2: # username/password self.append_write_buf( - struct.pack('BB', 1, len(self._auth[0])) + - self._auth[0] + struct.pack('B', len(self._auth[1])) + - self._auth[1] - ) + struct.pack( + 'BB', 1, len(self._auth[0])) + self._auth[0] + struct.pack( + 'B', len(self._auth[1])) + self._auth[1]) self.set_state("auth_needed", length=2, expectBytes=2) else: if ret[1] == 0xff: @@ -178,11 +177,8 @@ class Socks5Connection(Socks5): if Proxy._remote_dns: # pylint: disable=protected-access # Resolve remotely self.ipaddr = None - self.append_write_buf( - chr(0x03).encode() + - chr(len(self.destination[0])).encode() + - self.destination[0] - ) + self.append_write_buf(chr(0x03).encode() + chr( + len(self.destination[0])).encode() + self.destination[0]) else: # Resolve locally self.ipaddr = socket.inet_aton( @@ -212,10 +208,8 @@ class Socks5Resolver(Socks5): """Perform resolving""" # Now we can request the actual connection self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00)) - self.append_write_buf( - chr(0x03).encode() + chr(len(self.host)).encode() + - str(self.host) - ) + self.append_write_buf(chr(0x03).encode() + chr( + len(self.host)).encode() + str(self.host)) self.append_write_buf(struct.pack(">H", self.port)) self.set_state("pre_connect", length=0, expectBytes=4) return True From 7d0bd1cf7a1932f053461d3bda366178566d5170 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 10 Sep 2019 19:44:44 +0530 Subject: [PATCH 085/306] stats flake8 fixes --- src/network/stats.py | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/network/stats.py b/src/network/stats.py index 5a0f8064..a1f66425 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -4,6 +4,7 @@ import asyncore_pollchoose as asyncore from network.connectionpool import BMConnectionPool from objectracker import missingObjects + lastReceivedTimestamp = time.time() lastReceivedBytes = 0 currentReceivedSpeed = 0 @@ -11,6 +12,7 @@ lastSentTimestamp = time.time() lastSentBytes = 0 currentSentSpeed = 0 + def connectedHostsList(): retval = [] for i in BMConnectionPool().inboundConnections.values() + \ @@ -23,9 +25,11 @@ def connectedHostsList(): pass return retval + def sentBytes(): return asyncore.sentBytes + def uploadSpeed(): global lastSentTimestamp, lastSentBytes, currentSentSpeed currentTimestamp = time.time() @@ -36,35 +40,39 @@ def uploadSpeed(): lastSentTimestamp = currentTimestamp return currentSentSpeed + def receivedBytes(): return asyncore.receivedBytes + def downloadSpeed(): global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed currentTimestamp = time.time() if int(lastReceivedTimestamp) < int(currentTimestamp): currentReceivedBytes = asyncore.receivedBytes - currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / - (currentTimestamp - lastReceivedTimestamp)) + currentReceivedSpeed = int( + (currentReceivedBytes - lastReceivedBytes) / (currentTimestamp - lastReceivedTimestamp)) lastReceivedBytes = currentReceivedBytes lastReceivedTimestamp = currentTimestamp return currentReceivedSpeed + def pendingDownload(): return len(missingObjects) - #tmp = {} - #for connection in BMConnectionPool().inboundConnections.values() + \ - # BMConnectionPool().outboundConnections.values(): - # for k in connection.objectsNewToMe.keys(): - # tmp[k] = True - #return len(tmp) + # tmp = {} + # for connection in BMConnectionPool().inboundConnections.values() + \ + # BMConnectionPool().outboundConnections.values(): + # for k in connection.objectsNewToMe.keys(): + # tmp[k] = True + # return len(tmp) + def pendingUpload(): - #tmp = {} - #for connection in BMConnectionPool().inboundConnections.values() + \ - # BMConnectionPool().outboundConnections.values(): - # for k in connection.objectsNewToThem.keys(): - # tmp[k] = True - #This probably isn't the correct logic so it's disabled - #return len(tmp) + # tmp = {} + # for connection in BMConnectionPool().inboundConnections.values() + \ + # BMConnectionPool().outboundConnections.values(): + # for k in connection.objectsNewToThem.keys(): + # tmp[k] = True + # This probably isn't the correct logic so it's disabled + # return len(tmp) return 0 From fcffb426296793f4a352029019ccac1aeb900dbf Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Tue, 10 Sep 2019 20:00:42 +0530 Subject: [PATCH 086/306] stats pylint fixes --- src/network/stats.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/network/stats.py b/src/network/stats.py index a1f66425..fedfbbc1 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -1,3 +1,7 @@ +""" +src/network/stats.py +==================== +""" import time import asyncore_pollchoose as asyncore @@ -14,6 +18,7 @@ currentSentSpeed = 0 def connectedHostsList(): + """List of all the connected hosts""" retval = [] for i in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): @@ -27,10 +32,13 @@ def connectedHostsList(): def sentBytes(): + """Sending Bytes""" return asyncore.sentBytes def uploadSpeed(): + """Getting upload speed""" + # pylint: disable=global-statement global lastSentTimestamp, lastSentBytes, currentSentSpeed currentTimestamp = time.time() if int(lastSentTimestamp) < int(currentTimestamp): @@ -42,10 +50,13 @@ def uploadSpeed(): def receivedBytes(): + """Receiving Bytes""" return asyncore.receivedBytes def downloadSpeed(): + """Getting download speed""" + # pylint: disable=global-statement global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed currentTimestamp = time.time() if int(lastReceivedTimestamp) < int(currentTimestamp): @@ -58,6 +69,7 @@ def downloadSpeed(): def pendingDownload(): + """Getting pending downloads""" return len(missingObjects) # tmp = {} # for connection in BMConnectionPool().inboundConnections.values() + \ @@ -68,6 +80,7 @@ def pendingDownload(): def pendingUpload(): + """Getting pending uploads""" # tmp = {} # for connection in BMConnectionPool().inboundConnections.values() + \ # BMConnectionPool().outboundConnections.values(): From dccb1dbb3c3fba74933425414264af6af7fb60d6 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 11 Sep 2019 14:31:17 +0530 Subject: [PATCH 087/306] tls flake8 fixes --- src/network/tls.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/network/tls.py b/src/network/tls.py index c643f46e..88c48e73 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -64,15 +64,18 @@ class TLSDispatcher(AdvancedDispatcher): self.tlsStarted = True # Once the connection has been established, it's safe to wrap the # socket. - if sys.version_info >= (2,7,9): - context = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH) + if sys.version_info >= (2, 7, 9): + context = ssl.create_default_context( + purpose=ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH) context.set_ciphers(self.ciphers) context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE # also exclude TLSv1 and TLSv1.1 in the future - context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE - self.sslSocket = context.wrap_socket(self.socket, server_side = self.server_side, do_handshake_on_connect=False) + context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\ + ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE + self.sslSocket = context.wrap_socket( + self.socket, server_side=self.server_side, do_handshake_on_connect=False) else: self.sslSocket = ssl.wrap_socket( self.socket, server_side=self.server_side, @@ -101,7 +104,7 @@ class TLSDispatcher(AdvancedDispatcher): try: # during TLS handshake, and after flushing write buffer, return status of last handshake attempt if self.tlsStarted and not self.tlsDone and not self.write_buf: - #print "tls readable, %r" % (self.want_read) + # print "tls readable, %r" % (self.want_read) return self.want_read # prior to TLS handshake, receiveDataThread should emulate synchronous behaviour elif not self.fullyEstablished and (self.expectBytes == 0 or not self.write_buf_empty()): @@ -114,10 +117,10 @@ class TLSDispatcher(AdvancedDispatcher): try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: - #logger.debug("%s:%i TLS handshaking (read)", self.destination.host, self.destination.port) + # logger.debug("%s:%i TLS handshaking (read)", self.destination.host, self.destination.port) self.tls_handshake() else: - #logger.debug("%s:%i Not TLS handshaking (read)", self.destination.host, self.destination.port) + # logger.debug("%s:%i Not TLS handshaking (read)", self.destination.host, self.destination.port) return AdvancedDispatcher.handle_read(self) except AttributeError: return AdvancedDispatcher.handle_read(self) @@ -135,10 +138,10 @@ class TLSDispatcher(AdvancedDispatcher): try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: - #logger.debug("%s:%i TLS handshaking (write)", self.destination.host, self.destination.port) + # logger.debug("%s:%i TLS handshaking (write)", self.destination.host, self.destination.port) self.tls_handshake() else: - #logger.debug("%s:%i Not TLS handshaking (write)", self.destination.host, self.destination.port) + # logger.debug("%s:%i Not TLS handshaking (write)", self.destination.host, self.destination.port) return AdvancedDispatcher.handle_write(self) except AttributeError: return AdvancedDispatcher.handle_write(self) @@ -158,16 +161,16 @@ class TLSDispatcher(AdvancedDispatcher): return False # Perform the handshake. try: - #print "handshaking (internal)" + # print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError as err: - #print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) + # print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) self.want_read = self.want_write = False if err.args[0] == ssl.SSL_ERROR_WANT_READ: - #print "want read" + # print "want read" self.want_read = True if err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - #print "want write" + # print "want write" self.want_write = True if not (self.want_write or self.want_read): raise @@ -180,7 +183,7 @@ class TLSDispatcher(AdvancedDispatcher): if sys.version_info >= (2, 7, 9): self.tlsVersion = self.sslSocket.version() logger.debug("%s:%i: TLS handshake success, TLS protocol version: %s", - self.destination.host, self.destination.port, self.sslSocket.version()) + self.destination.host, self.destination.port, self.sslSocket.version()) else: self.tlsVersion = "TLSv1" logger.debug("%s:%i: TLS handshake success", self.destination.host, self.destination.port) From 498232dbea361724011e619c89a88b23c2c20cea Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Wed, 11 Sep 2019 15:40:42 +0530 Subject: [PATCH 088/306] tls pylint fixes --- src/network/tls.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/network/tls.py b/src/network/tls.py index 88c48e73..17b1ee1f 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -38,10 +38,12 @@ else: sslProtocolCiphers = "AECDH-AES256-SHA" -class TLSDispatcher(AdvancedDispatcher): +class TLSDispatcher(AdvancedDispatcher): # pylint: disable=too-many-instance-attributes + """TLS functionality for classes derived from AdvancedDispatcher""" + # pylint: disable=too-many-arguments, super-init-not-called, unused-argument def __init__( - self, address=None, sock=None, certfile=None, keyfile=None, - server_side=False, ciphers=sslProtocolCiphers + self, address=None, sock=None, certfile=None, keyfile=None, + server_side=False, ciphers=sslProtocolCiphers ): self.want_read = self.want_write = True if certfile is None: @@ -60,6 +62,8 @@ class TLSDispatcher(AdvancedDispatcher): self.isSSL = False def state_tls_init(self): + """Prepare sockets for TLS handshake""" + # pylint: disable=attribute-defined-outside-init self.isSSL = True self.tlsStarted = True # Once the connection has been established, it's safe to wrap the @@ -89,10 +93,13 @@ class TLSDispatcher(AdvancedDispatcher): # if hasattr(self.socket, "context"): # self.socket.context.set_ecdh_curve("secp256k1") - def state_tls_handshake(self): + @staticmethod + def state_tls_handshake(): + """Do nothing while TLS handshake is pending, as during this phase we need to react to callbacks instead""" return False def writable(self): + """Handle writable checks for TLS-enabled sockets""" try: if self.tlsStarted and not self.tlsDone and not self.write_buf: return self.want_write @@ -101,6 +108,7 @@ class TLSDispatcher(AdvancedDispatcher): return AdvancedDispatcher.writable(self) def readable(self): + """Handle readable check for TLS-enabled sockets""" try: # during TLS handshake, and after flushing write buffer, return status of last handshake attempt if self.tlsStarted and not self.tlsDone and not self.write_buf: @@ -113,7 +121,11 @@ class TLSDispatcher(AdvancedDispatcher): except AttributeError: return AdvancedDispatcher.readable(self) - def handle_read(self): + def handle_read(self): # pylint: disable=inconsistent-return-statements + """ + Handle reads for sockets during TLS handshake. Requires special treatment as during the handshake, buffers must + remain empty and normal reads must be ignored + """ try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: @@ -134,7 +146,11 @@ class TLSDispatcher(AdvancedDispatcher): self.handle_close() return - def handle_write(self): + def handle_write(self): # pylint: disable=inconsistent-return-statements + """ + Handle writes for sockets during TLS handshake. Requires special treatment as during the handshake, buffers + must remain empty and normal writes must be ignored + """ try: # wait for write buffer flush if self.tlsStarted and not self.tlsDone and not self.write_buf: @@ -156,6 +172,7 @@ class TLSDispatcher(AdvancedDispatcher): return def tls_handshake(self): + """Perform TLS handshake and handle its stages""" # wait for flush if self.write_buf: return False @@ -175,7 +192,7 @@ class TLSDispatcher(AdvancedDispatcher): if not (self.want_write or self.want_read): raise except socket.error as err: - if err.errno in asyncore._DISCONNECTED: + if err.errno in asyncore._DISCONNECTED: # pylint: disable=protected-access self.handle_close() else: raise From e74affe6363f99be5ee185919adfa14c2f0bbb7a Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 12 Sep 2019 15:24:18 +0530 Subject: [PATCH 089/306] udp pylint fixes --- src/network/udp.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/network/udp.py b/src/network/udp.py index 33504289..01dc1f7b 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -1,3 +1,7 @@ +""" +src/network/udp.py +================== +""" import time import socket @@ -9,15 +13,16 @@ from objectracker import ObjectTracker from queues import receiveDataQueue -class UDPSocket(BMProto): +class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes + """Bitmessage protocol over UDP (class)""" port = 8444 announceInterval = 60 def __init__(self, host=None, sock=None, announcing=False): - super(BMProto, self).__init__(sock=sock) + super(BMProto, self).__init__(sock=sock) # pylint: disable=bad-super-call self.verackReceived = True self.verackSent = True - # TODO sort out streams + # .. todo:: sort out streams self.streams = [1] self.fullyEstablished = True self.connectedAt = 0 @@ -44,6 +49,7 @@ class UDPSocket(BMProto): self.set_state("bm_header", expectBytes=protocol.Header.size) def set_socket_reuse(self): + """Set socket reuse option""" self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: @@ -73,8 +79,7 @@ class UDPSocket(BMProto): decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue - if (seenTime < time.time() - self.maxTimeOffset or - seenTime > time.time() + self.maxTimeOffset): + if (seenTime < time.time() - self.maxTimeOffset or seenTime > time.time() + self.maxTimeOffset): continue if decodedIP is False: # if the address isn't local, interpret it as From 915bfb757d0137acf9113d8880acda102b472c85 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Thu, 12 Sep 2019 17:20:08 +0530 Subject: [PATCH 090/306] networkthread pylint fixes --- src/network/networkthread.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 433c771e..2a22367f 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -1,4 +1,7 @@ - +""" +src/network/networkthread.py +============================ +""" import network.asyncore_pollchoose as asyncore import state from debug import logger @@ -8,6 +11,7 @@ from queues import excQueue class BMNetworkThread(StoppableThread): + """A thread to handle network concerns""" def __init__(self): super(BMNetworkThread, self).__init__(name="Asyncore") logger.info("init asyncore thread") From 1e446b768c5a9bc263aa33a70ca927cfe21860ed Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 13 Sep 2019 13:03:40 +0530 Subject: [PATCH 091/306] node pylint fixes --- src/network/node.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/node.py b/src/network/node.py index ab9f5fbe..0bfda653 100644 --- a/src/network/node.py +++ b/src/network/node.py @@ -1,3 +1,7 @@ +""" +src/network/node.py +=================== +""" import collections Node = collections.namedtuple('Node', ['services', 'host', 'port']) From a961a4a2fb3f2435efb818e410cf0558a4ed8ff5 Mon Sep 17 00:00:00 2001 From: lakshyacis Date: Fri, 13 Sep 2019 14:11:21 +0530 Subject: [PATCH 092/306] proxy pylint fixes --- src/network/proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/proxy.py b/src/network/proxy.py index 6f6d256a..479663d3 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -144,5 +144,5 @@ class Proxy(AdvancedDispatcher): def state_proxy_handshake_done(self): """Handshake is complete at this point""" - self.connectedAt = time.time() + self.connectedAt = time.time() # pylint: disable=attribute-defined-outside-init return False From a8be2e764a3b8e54ea4e6f712d3c70995577d40a Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 15:42:41 +0530 Subject: [PATCH 093/306] Implement new feature for back button for screen tracking back with keyboard event attach --- src/bitmessagekivy/main.kv | 11 ++++++++++- src/bitmessagekivy/mpybit.py | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index ea8936c5..1d86c133 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -54,7 +54,16 @@ BoxLayout: size_hint_x: 0.1 pos_hint: {'x': 0.8, 'y':0.4} on_press: app.say_exit() - + ActionBar: + size_hint_y: 0.4 + size_hint_x: 0.1 + pos_hint: {'x': 0.99, 'y':0.35} + background_color: (0,0,0,0) + ActionView: + use_separator: True + ActionPrevious: + with_previous: True + on_release: app.set_previous_screen() ScreenManager: id: scr_mngr diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 3f9b198b..b8d0a724 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -19,6 +19,7 @@ from bmconfigparser import BMConfigParser from helper_ackPayload import genAckPayload from addresses import decodeAddress, addBMIfNotPresent from helper_sql import sqlExecute +from kivy.core.window import Window statusIconColor = 'red' @@ -38,8 +39,19 @@ class NavigateApp(App, TextInput): main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigator() + Window.bind(on_keyboard=self._key_handler) return main_widget + def _key_handler(self, instance, key, *args): + if key is 27: + self.set_previous_screen() + return True + + def set_previous_screen(self): + if self.root.ids.scr_mngr.current != 'inbox': + self.root.ids.scr_mngr.transition.direction = 'left' + self.root.ids.scr_mngr.current = self.root.ids.scr_mngr.previous() + def getCurrentAccountData(self, text): """Get Current Address Account Data.""" state.association = text From ccd383b72fceff0a5cb45b215e90bed82a7f1d16 Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 5 Sep 2018 17:03:01 +0530 Subject: [PATCH 094/306] Changes made for new feature for back button for screen tracking back with keyboard event attach --- src/bitmessagekivy/main.kv | 30 +++++++++++++++++++----------- src/bitmessagekivy/mpybit.py | 2 +- src/images/back-button.png | Bin 0 -> 52318 bytes 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 src/images/back-button.png diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 1d86c133..4b4316d4 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -54,16 +54,6 @@ BoxLayout: size_hint_x: 0.1 pos_hint: {'x': 0.8, 'y':0.4} on_press: app.say_exit() - ActionBar: - size_hint_y: 0.4 - size_hint_x: 0.1 - pos_hint: {'x': 0.99, 'y':0.35} - background_color: (0,0,0,0) - ActionView: - use_separator: True - ActionPrevious: - with_previous: True - on_release: app.set_previous_screen() ScreenManager: id: scr_mngr @@ -352,8 +342,26 @@ BoxLayout: : name: 'page' + ActionBar: + background_color:0,0,0,0 + pos_hint: {'top':0.98} + size_hint_y: 0.05 + size_hint_x: 0.07 + ActionView: + ActionPrevious: + with_previous: False + app_icon: 'images/back-button.png' + markup:True + font_size:"16dp" + on_release: app.set_previous_screen() Label: - text: 'I am on description of my email yooooo' + text:"Message sent on 5 september 2018 05:44" + color: 0,0,0,1 + size: self.texture_size + size_hint: (None, None) + + Label: + text: 'I am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description \nI am on description of my email yooooo am on description of my email yooooo description description \nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\nI am on description of my email yooooo I am on description of my email yooooo description description\n' color: 0,0,0,1 : diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index b8d0a724..a5241e0a 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -50,7 +50,7 @@ class NavigateApp(App, TextInput): def set_previous_screen(self): if self.root.ids.scr_mngr.current != 'inbox': self.root.ids.scr_mngr.transition.direction = 'left' - self.root.ids.scr_mngr.current = self.root.ids.scr_mngr.previous() + self.root.ids.scr_mngr.current = 'inbox' def getCurrentAccountData(self, text): """Get Current Address Account Data.""" diff --git a/src/images/back-button.png b/src/images/back-button.png new file mode 100644 index 0000000000000000000000000000000000000000..e260b08bd191ec7badbfa32baa1b1f10c1125251 GIT binary patch literal 52318 zcmZ^~1z4187d1RI2uKOi2q+*ajkF-3QX&Y_-Q7c%q=bregMdhPOLt2QA>AR&fOPoZ zqvx&f|Gsk_J=gKVnfuxI+Iz3H_I|=&D#_vBqPzuxK=7YGd-@6jL45;$X<}o7KXDb7 z_W=Jvcb0mth7JDl#x@B9|BvJFOw$-Q)4#?CV#8Oh;mkfI4i#d(ePW zoR1%&;dcmhCk*@ISyW#2u|8k@@F3d?-j? z6H2vqbadosvuIf5Km;IfxUOw}e_0vznF z)5QAn@|ZL*pdY;g342C`Ou$O(jHgT?kCBRX8v{~*V>;TzVH{|M9r$}W!l zS?(q9{MPUJUcpeOL)&z5t0x}eEMYxME;-=enRKrIdI*R2qT82=ieloezxc@maYwB) z-rtOa+^UZ_+!8?d_d|t~Li91D@Oh2 zAi}oDLw;cFkDIlEoT5N!{Jn@cq)y?_-ff~>q4~Fr~UqeEiNY~5XjG@9~!Um@nA<%w5t+9?A_dih$P$`)ZK!HM9gPbJ<*9&`% z!&ij-TQK0J5Wl%E8ZnziJsrj>9mrF1=I9jQ)AuVh-~Le0Ky;((OM8uhvNZSSBhPwd zn`iqqK8E(J{DFk7Wc@4c+e`Eido=hX|H*UKL%2h`kUtm7nKI<2L8Vk_9r?LS%g7kL z=v0`TLlH%7DbMd&X}#~?f(kc>n+J)HDSH<_Iuo4iEI#wR%$~Ft9Rnii~d<#PUJU0O6E=m(!t1_gH#r!cX zZIC}N_9_d~MP8RqI`pt5DfyPXT*w zT3QcqRWT33>uDwro|t^4MJr?1m!YKv0EFBi@6_HG%OfTi8(<{<4!9-($N>f%-CzFb z_3Co@eK>>vA{HDg%JVp`sS67Ibqm}PyC*o9A;eztQ?VzZBscQION>}w zB%*8hAeZ<>7emPA4JYZlv5{9qS&-x>{$^}X*|0bL>}yb~0uA;LAjRrJzr89arL5h^ zif1S?`EkdRF|>xZ%$E{Sj_E-TQ$cRNsFdpUYDb33X@RTdeh(f<8{&;VcJbBq@qnfl zOZ-c6&FJOwxHr{Sr0T`g9sT8|Z|c1%)Y<8}`b~4lwFM$y=XAW`e$_ecK*Sb`OHRdU z@cE6TccDPuSDN0XCK&GPS=aY_y&i`Y8eNKvBuHe(LoCC5f6FY_+e8T z&1kI-!%k$(5na8K9NGb{yHf@ov;5O#ZVv>C^a73xEoJ+LJ#FhjNqTnb|2A z4!vX$pYi6=vskq~&*~%ziCStIy_0AY@`2v^mV&~Nk@q30Qnd2Q*)~opjRY3A7zX#8 zfC0TI8M-3mH_@1IaXu2jhPVJEn5dvIDM2zY9Q=k~kr6~Zh%DB7XL~on5z+mw%yOQx zNSi+dpG~gJP7}vkjuA~JiqHkK&nDy}!c&ja+H`=6img~y?nb~2Ens{cMM)3a(TTM+ zJlrx>R3soaUn$4Km)gh*{M&B+t>Ik@8hi#6y11rbC^Qk&IXV3fs>1!uIvb4s6ak~l z4g6^py-?d-4a2!v?jrq?WR`x>fG_5}QVQzfyy_~cGMJGATHG5WpF`Q?cP6dzFdW>N zcy#mgq*AFfI{U^~g&cS8iEl7!qngH~TX#n(HqFfO-l~+g^ zTA+*6*tadv++D3GrgG5qz!!+b&lTWssxOHi&~iO;%;bgZ8k{!tK17;8?LF0m`IZV~hQ))Fr$26RVcE6ZacAme-j9vdHPLI~E_ zb4$4!ocK?4Drgc8SXL`IcFVjvZbjmghT$v>5q1u&l=W#H&oQ{YV(cho8+Xhd`*MQf z=)2*YoF8j}!OY<1iAmy8p|;)@^pUJMm#^?VNok5vz9 z^E~R(5xko2$8Ex3K_+t zo}##)Q@AIXyeYE7Z<1CNub!~L51-;L1-?zq2(aD_RVN>SPG*b`A za+&?Qe=k+2*O1h-7Z(gT6M1Dv657UA?kbY=+P25STqGE3@aI5 zts#1CqB0@{q;+Q#rGDv#wtWAh!F)uvT7CxlW=~+YP5~*3C<>^aHp7}qcGKmqymn1a z1SN|;+?;cDs9p6x(k>};P8PQn<*BdB!qQlIsRnH*vOeoocH40pDfeX9w5pF36hOG5 zYLQ==!#u(uf(S^T1LeR4^Qi-~MQNa~~a^nko{KwF-6`de6f41%ilXj$!LjDU^rGN<;#DKS; zLZuh9Jfn(J1ec?CIeUI4*mu=b52Pu+8(M9JUf*Lk%AcD!>iKQJFMP;+%*1~(&fu0* z*ijl213R*nZAnYRL0lyg*nKTCpSYC&$V6c}Z6H_Q>G7!3M z;tPh2q4g-0yq!baX-Ac+roqW7hZwY+3M5>r-c7sOenHIeN(scEjl(N-$f$+U3Rj1^ zGe8x!z%?Gnp z=JCKbjzCExw)+B<^hCcLzi}$+aS9oyc5I|OFZ!+8ypn?&y|T%z-o-I1kEY>`?>0A) zrf<7%OWd`eV``J{#6lI~nQ6y0&*9e|!X?30rjvypl7?+mwU$u4?S_iTZho2|j?=Xu@n5D0C$vgYy5@xO>=m^&# zc~Te*A0$F&){l0J(Qi5<_9qbBnUwaxMUdlx;2S;#`U2&QJi9A{%_)A|wdl<^JoiOU zj{TPXS2h{H?-;0=i=5Y$a$6(3_nst;pPumI(zaqpMYzsXv*U$-Nt#8Y;yw(!Dx;b zxP%~?`d5t2NqI$nmNiLaE z^g7-q>~GtiT!B75!qTNP8GlA&|8cP>RD!9wJbQIg=%k^1kC*%Ok}Z}))V(3RI~Zay z#2|zqZYRN_Pv(snmhsPrc$Wd{%VtkcdyV8s&jx+mm$=Z*So~iNJ2gZUp6sn* z{HYUju8b8fYw!^Wp+Z{lm&R`z@x@rcC1imn(M;QV z0GUp&jkn8s!(#9oWZ!YEez+Kw#)BOlX1Y^;*`GXu;|xb-KSd}d&uiTI{rCTY;ldu} zBr*kfpVWAsS$EhJ+3-8Xpz&I!UKUe8MpC0`=>(($99HhMcL!J$hIR!fpm={)DZN<) z2-xBRU(Oxllv{IaEFUeSS6jaJk+5*!<>{iooc(N66q_80Yf0>glzFjD6u5J7?W|3j z&oXkJIAitOZd@+iFZ^x(vW*M73$9!u;bs+*?XxEMgv+0>GyLdb9dZ-yz zL<%^$^|3Ie^%s02PwTAje547<=wx_fU2VE5Eb4Z^0i9fUr^5R6 zGNS?9a2|tR{4gQ;@vJB<S12q4)#Quld_mM4oEFfWr_dIyT4^j(^JG z)JM|wV{638rCmp1X&rf&QCnFz%Q^2?cU}$wO}4qd7t2%I)jp!K4qJRXE4F9#MRCt# zqT2Rq4+uVkX2MF^A~V$w^&!$ZtRI-dk_xXKC%MK$H>^@>dRta*5jhnLS(yBykuj_t zCMOQZv6sxV^fGSXx2GMOwly8X-NTMZjS;#fE0~r%WD;BRujj}yHn9l*Wxou_YFN+bpZ85 zQKoTlh_H9P;RMTv$SZYZ!N6?1mx4{TiKb=Yjp@pP(G=^5%-+e>RrNe^E3SDmblHX^ zK(fbz#tS8zzwj10bt)=67W8Zh!ZlY-@Sc z{pZ(K?O0b#xA9PN6THloyS4{Ykk6Wi&(yZtJL072ka#I6ERl3}yur#L(KUx3h0`5L zInHjhd47Bvd7na+BOqUy-w|3tN;*hUyfls5YCu&i0fDRfiiCC%*q4z#2K^%nazl;Q zaNWMu`)I-Yz!rL~*jR2Obh17$9Mqg*S>C5LqofY#0w;K?a2_eX!m$r6Ig^SxK6Hsg z8DcFnZ)OguJQ_1q#NB5uBv}v!tB-xJ#bTEp?2HV)Jsa!OOijbd3Cs*$+H%H@rbB=F zI_~soUAP^MUr41hX3tHco zDs)BQH=%YN3yN$s3NnZ0Y6oUoCaTL;S~gLy5BcNG!j@jH&f{e^x83IxK6J0z;Wyhw ztCaQfZAaHc9weo(in4xJkf!C?L>u`CVz<=x{Mae2#9o>nzEV$iy9#EG0=oLB=eiu> z=E&DEwtvGu~+_ zmRXhjpqNYFOW2*&-;&vLN%6cnqbmXu`}4wQ+1(z?r)h(h5w)u@DmGSey^&f=0d-5h zei#>x{eZoIIue(Py>0^j;~W8-!+ee=6-Tc{07J&UErHK1k}ELv`%EBPE(GfkoJS0t zCk&j2R<_DShrgS~Q3{kkr5uLbf*{-5T@6x%Sf1#7FqhGh0WDZy;8Z6D!8MPJbrU##Z#?_IXq-0Ynnce4_ix7n}# z43s_pVY-VpS>+$Kd3JoN5D1$H2}b$6ziPaRCOUo-Ee*+j9JJJ1iLLyNy(N2*9^y^g z$_4z|0Nu6&qBg1`6ggl*5-cfm8&HMnRTxt({D%AP%{3AGrxlc?dD~R*yELWHzn?Ss z(+h+w^aRnKA;vLPEmrR`Sg+4w;Wme*tr_fW34jB=lRdd`-Oy0PJ+7sZ@Eakl;H8kP zr&~c(X0;xDHU0UxG{~V3-wk;j`zcsoS1qL$qPpw|A3vKx`Ccifq0O+k_CeRK~`D=nTx9 z@R}7j7((iCJV)=A&snW0y!Yx339EgiUPF0lOXSs*-fTx56<4G1y-&AA?eb>}8ok4k z4Q{DIl`!`Z1v=Mn$a0eL*Xf%syllnieu99C?SpFC3IH1dnSglT11ES>X@I)Vt zM(xBh{uBiCvSJi?2Fj0wS~8J44yQL%h|YNp<4KFYf8$p)oNDpsi@YwkidS{6NQze3 zreF@42@mhXuBRLf*6U1{$%!iO@66z_Hs$dcmB95*=&LLa56*k4ibLQ2^H1$8o}YL))qiOx=3mtW6^k{G|TX9L`cHL?^ED z4x7zv6%L)}YN5mR)Ffn2A^7K-acprGD02ZnFbiR0kXe)BAIyc&T+N)ndW|QxPG^xL zY68J@K7GC;1-ja=}7*YP&=iUg+t#J#re>E>9ICu z9lZK#Sw3!@KgMruY7Lp$O;~3xk(0G&@z2>rqZWqE;Lu9lvuFwftxA&I0OCO1N(CYY z1EskQoJ$9vFeVohy3#vs|0QO`8C zj)tV)brCPzj20r|Q{1!F%Ba==M+!}&j*L|n9yglU1&YJ0*yh|a$THnq;fg&WryIZ? z*|HuhPpc)FOh+PKiJ;##XKgUlGKd5faZ}5;S*K^Q@~iBLxY>EQmu$}KQs#@r4@ci; z+3)q6(fDE#`m~JXL*PjBK?4Nn2{J&P_k3PC9BuH3pTswoyRVXqu=EVrFw=3S3y>n! zN4CT6ERew)ZAef044g&q+`*KlIR0;F{zb;CKB&aNn6!=AD<7%%L8Jem+ag-C-W-GK z!0u5nH|%Kde6>WOvR{EM@_sbQO>Z#|7Fd`!AcisKCp_kwfD*lJZ9|YL>4X)x z5z_~DjNG%Jey_DJe?zmpInU6J%g5%mXREih=2=B-cV6*vJNH~|h|dBtJk58n)H zTU> z#C~Dd8UC+6OL=2cpHzS5Zh#7H$(Q%%MA%Mg?7y=-t%BTiRdOf@ z7+aSGl4)^WLzcHYtU9iPF|(D)eHlTu1_#3c2lIj4a6#A(r?RCjP3|0c{?cn&P98dv z-`7<=QUUx^MNtN6{XN>LeniDs>#>w*Gvv1b>PvH^N+Ni#W5m!ZqFfX)3QeFy{G7Iv?-HTDyEQ9-EYSF*W7_s zOKiQHUiGH-du1;Wm0HfzHHX-Z0&WJUSuvUCE(T1HXDTmv<-x2$Y3W(>v(ACj@}vxM zW})W2MC1GqyorDZ-A=X6qUaV%9>>1zdl%TxuV4N)plqE3)#rCCI1C;*3@}=}MEoUC z9;Mcj5eK8vHk@)cZAQFkeB#%h+)8hZN3y@r|a8=dD zr!1Z)pvfs01>85AD^KUR1oX(CnJ;j`di} zKbEI2x3R&a^SMNuZaK<6=lSQ5*}5BM*mvv{=fMm>`I9Dmz}BLknjd7p&6SyPT!e(_ zRR3r0=7P+X*U}IHaEFV$IC^>boRzXxMv(**%0Seb_E1;Ko{ES0ig1&zz)hS+ijas$ zQ+~o{uJ-*#60(E_iW0#gS;d`YeD&LaKGLDU?ML&e!t7=mNHe@I=cjAT&?S@q#w`1~ z_AgW8IoPws^a9^gZMl+s`v{0~SwfPTQD=y9T zo%U=Sc8jgqm#gP}ku*&>%O$Y{J&XTwxp7EL zvU+TYe{HZ9%kEz&_5d0nB6g?cW;R}*3x+tg*`xe8#~+QuBjG6Ktc0A}^#1WV%{yO}Rp@K@7f7T(qBv|zA& zrr4WTz!MbD>?{-}@MhU38PRF=HyBz=B#gH=U9Z)HCgO&pyT zjZW25DXgR~|I#|zN*!C{L^vL6(G2GZ+dlg0f75CYs0wgLI$r@# z2p72R>gaHL6t%-CDMQ%4*x5|aiSc+u)*YmB&id;Vu>44F08^2Cmj*Lw3uMzP3li(; za+p31m;)^9r@|qLBiWTK0M@4w-5T+i_$brRXnntt`%pz&meV2wK%ep+bqBGmo*z@{ zUbcF4=xysL42B@1HhoR=1Q+lqY3Rlm);x)qSnw>cD{;DLA=V3sFbel+?vNk$QqR#; zcIL}g>;2gng8AmV9Wt)P&Ab22?-D%B55%W;nR$IdGt{zhSyQ&+w|4m%1Zby{(<3l9 zLpQ(6R{<;KZLtF7{^!{_5Cv&{kp64Q7#uZ`)$WKkV^?z-fO!7{kQ^o&&aXQlSI}Ji4j6mnAB4C0tO#KeXh>d!sTyo%$Pf ztupV=Zk|PXazuud;PabXjlLeCX=gAy`qB9m zk(W{ytMlBKbD?JFzCFO!r3!b~@YPqa>j4N&hV}D`SAgS5X>Zy+`b+Ubzm8jj&c+jk zweRzOqRz7D?bs`n9!~Tl)8H{~Jbhp0WG-0Ap02E;xW^hHlXMhsjjt{X@@ z7T8K!nHOECrXtBm)@L%-ZqpU@0YP8G>5EuY~lvLEw{@dKqFLQXVmsZYtdLU z0eKW8Pa73X-LY5t*okD{Eh^Kf6EOIlaZopahS?D2JO9+>_s`mud_Aw%M%<16gZclP zrjeB`If$3tfyQ2$iCu9MrP?%6_UH-5`*a@_#@b5RtB)I5vVMWxKhVsIau-bOJnr4D z-ne@K&7*5bss=raY!NTVRTIJW4%7dS*Ckp=t8fEP`QS#hVBm@alzIo`Vz&@GLZ)fC z%?rM-?LO$o90Lv&p|P;767(`K!%EdQsBm{<3fGs&O8`s*{zts1zv4d_A$Bc~J-kF#dwhwKf(oPhHegIoQ=XJ)+-J;CTaDQ%`C)cuRx+0A{496dJQ zYP$N}S}Mx<%ht@XR=QgOIh#RiuwBUY1&%bzQaI>`p&qytF3_MjA`lzEPIt8WwdJV> z)Qj7C77_RCepI0PU#@j1-R|yVPO}W}I8JN6G$@rYLyGkV{5?QnTu7`chI>lh@+fnc=cYdA&884J*t%ybm*^zfhxO**m=J5>xz`gZZw z5VAxANW{ny84oC>Y-pebbwF;EAsuZ)G-m$dU>zZlyz)II27B;sB_ z)K@Pjs?B9`YXQqMYWS)gP53dXk+-@h`*gC*Q7|(-sAVyu= zLeL+W^z7yjkLpZLX|D!qe*_#4$PdTHDAt5T#PokpiWkyZoM|LDG2I@n{;{;5psq90z3>^AS%R|F2$c&4R$J9 zh>DP`L{@2#Jq??Br%W&Eh3E6u5<&nN;qUa?_fNo5*hApQ*kQm=A?h2&xlv*oIswWO zZdB@ct~G{bN!|*vq+$kD13&Nr+Ka6hfzd$DrrU)7=X`Ed#&LgKkM2LQbC6|h8|Y5q zr$o*W-qM%-mGNDsQ_mDbyi$3abVQE@M@nHJXl?*=l439*v5Enzs(oA$A%qq* zSDfwRKGjhj_x&#cvlcugC!LU&xKlse z$rWQ9-k>z2Ccm^6EJ;a){zngmCydGo-CjBYdw}=s>4U%)C^ZPy6y%K6zYt6_yIlo; z`1>K?uHfQwUrk?)0`i#2 zdfkduVY72y?Iq&5G{ji6r?jPJ9X8;4C01zlsdUjqvg}SB!E?_u+Xkk32Y8m3t$7Z9J7lS?Y zRS(F^#8g?;CSAHMe&HjLXd)*~wmU+O^!`<^$$;Eo5W1kg!1fEZP*ewl*C7Aw$DPKv z`G0+=Z&)1`frn$oZoH`ajq^llW#S$Kam&_<3`6?b$Nn|PdR;E!Qlb}4gHI;=nrx$t zlnSB;Ith5vM|){WU|3@wec5B5s=s&59TnnFZyBB&!&XHB<8j&?PHXWwPAuWo1_O