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/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/identiconGeneration.py b/src/bitmessagekivy/identiconGeneration.py new file mode 100644 index 00000000..43e0dbc5 --- /dev/null +++ b/src/bitmessagekivy/identiconGeneration.py @@ -0,0 +1,92 @@ +""" +src/identiconGeneration.py +================================= +""" +import hashlib +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 """ + + +# constants +RESOLUTION = 128, 128 +V_RESOLUTION = 7, 7 +BACKGROUND_COLOR = 255, 255, 255, 255 +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) + 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): + """Generating hash""" + 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): + """Getting random color""" + # 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): + """Generating images""" + 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/bitmessagekivy/kivy_helper_search.py b/src/bitmessagekivy/kivy_helper_search.py index 73a8a1ff..e2e962c0 100644 --- a/src/bitmessagekivy/kivy_helper_search.py +++ b/src/bitmessagekivy/kivy_helper_search.py @@ -7,13 +7,16 @@ 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 ''' + 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,22 +27,33 @@ 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: - 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) + 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 562e9f98..1fdb29f0 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,9 @@ #: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 #:set color_button_pressed (0.659, 0.522, 0.431, 1) # darker brown @@ -49,66 +53,81 @@ color: color_font : - drawer_logo: './images/drawer_logo1.png' + drawer_logo: app.address_identicon() NavigationDrawerDivider: - + NavigationDrawerTwoLineListItem: text: "Accounts" NavigationDrawerIconButton: - Spinner: - pos_hint:{"x":0,"y":.25} + CustomSpinner: 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' color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - on_press: app.limit_spinner() + 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 + 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 = 'inbox' - badge_text: "99+" + on_release: app.root.ids.scr_mngr.current = 'draft' + 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) - NavigationDrawerIconButton: + 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 = 'inbox' - badge_text: "999+" + on_release: app.root.ids.scr_mngr.current = 'allmails' + badge_text: "0" + on_press: app.check_search_screen(self) NavigationDrawerDivider: NavigationDrawerSubheader: text: "All labels" @@ -116,26 +135,37 @@ 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: "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' 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 @@ -144,27 +174,31 @@ NavigationLayout: 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()]] - 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 + 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 Inbox: @@ -197,14 +231,28 @@ NavigationLayout: id:sc14 ShowQRCode: id:sc15 + Draft: + id:sc16 + Allmails: + id:sc17 + Credits: + id:sc18 + Starred: + id:sc19 + Archieve: + id:sc20 + Spam: + id:sc21 : name: 'inbox' - 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: : @@ -225,9 +273,47 @@ 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: '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: + MDScrollViewRefreshLayout: + id: refresh_layout + refresh_callback: root.refresh_callback + root_layout: root + MDList: + id: ml + ComposerButton: + : name: 'test' Label: @@ -243,12 +329,34 @@ 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: orientation: 'vertical' size_hint_y: None - height: dp(600) + height: self.minimum_height + 2 * self.parent.height/4 padding: dp(32) spacing: 15 BoxLayout: @@ -258,6 +366,7 @@ NavigationLayout: hint_text: 'type or select sender address' size_hint_y: None height: 100 + font_size: '13sp' multiline: False required: True helper_text_mode: "on_error" @@ -265,13 +374,17 @@ NavigationLayout: BoxLayout: size_hint_y: None height: dp(40) - Spinner: + CustomSpinner: background_color: app.theme_cls.primary_dark id: btn values: app.variable_1 - on_text: ti.text = self.text + 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' + color: color_font font_size: '12.5sp' + ArrowImg: BoxLayout: orientation: 'vertical' @@ -282,7 +395,8 @@ NavigationLayout: MyTextInput: id: txt_input size_hint_y: None - height: 100 + font_size: '13sp' + height: self.parent.height/2 hint_text: 'type or search recipients address starting with BM-' RV: id: rv @@ -291,6 +405,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 +415,7 @@ NavigationLayout: multiline: True hint_text: 'body' size_hint_y: None + font_size: '13sp' required: True helper_text_mode: "on_error" BoxLayout: @@ -308,14 +424,13 @@ NavigationLayout: MDRaisedButton: size_hint: 1, None height: dp(40) - text: 'send' - on_press: root.send() - AnchorLayout: - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'reset' - on_press: app.root.ids.scr_mngr.current = 'random' + on_press: root.reset_composer() + MDLabel: + font_style: 'Title' + text: 'reset' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : readonly: False @@ -357,7 +472,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 +520,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 +537,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 +561,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(app) + opposite_colors: True + MDLabel: + font_style: 'Title' + text: 'next' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' : name: 'add_sucess' @@ -466,25 +594,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: @@ -511,10 +654,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: : @@ -529,7 +675,149 @@ NavigationLayout: : name: 'payment' - + ScrollView: + 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)] + 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: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: app.theme_cls.primary_dark + 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' + 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 Free Credits' + font_size: '13sp' + color: (0,0,0,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: app.theme_cls.primary_dark + 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' + 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 Monthly Credits' + font_size: '13sp' + color: (0,0,0,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: app.theme_cls.primary_dark + 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' + 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 Yearly Credits' + font_size: '13sp' + color: (0,0,0,1) + halign: 'center' + : id: popup @@ -549,7 +837,7 @@ NavigationLayout: orientation: 'vertical' MDTextField: id: label - multiline: True + multiline: False hint_text: "Label" required: True helper_text_mode: "on_error" @@ -558,10 +846,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: @@ -576,6 +866,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' @@ -592,6 +883,7 @@ NavigationLayout: color: (1,1,1,1) halign: 'center' + : name: 'networkstat' MDTabbedPanel: @@ -612,8 +904,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 +926,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' @@ -660,23 +981,27 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(400) + height: dp(500) + 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' @@ -688,18 +1013,24 @@ NavigationLayout: text: root.message halign: 'left' bold: True + CopyTextBtn: BoxLayout: - spacing:50 - 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() - MDRaisedButton: - size_hint: 1, None - height: dp(40) - text: 'Delete' - on_press: root.delete_mail() + orientation: 'vertical' + size_hint_y: None + height: dp(100) + self.minimum_height + +: + 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 @@ -715,7 +1046,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 @@ -784,6 +1115,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' @@ -860,6 +1192,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' @@ -871,4 +1204,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..ae69a133 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,57 +1,79 @@ -# -*- coding: utf-8 -*- +""" +src/bitmessagekivy/mpybit.py +================================= +""" +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 -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.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 kivymd.bottomsheet import MDListBottomSheet, MDGridBottomSheet +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.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.list import ( + ILeftBody, + ILeftBodyTouch, + IRightBodyTouch, + ThreeLineAvatarIconListItem, + TwoLineAvatarIconListItem, + TwoLineListItem) +from kivymd.navigationdrawer import ( + MDNavigationDrawer, + NavigationDrawerHeaderBase) from kivymd.selectioncontrols import MDCheckbox -from kivymd.snackbar import Snackbar +from kivymd.textfields import MDTextField 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 -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 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 functools import partial -from kivy.uix.carousel import Carousel -from kivy.garden.qrcode import QRCodeWidget -from kivy.utils import platform +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.""" + if platform == 'linux': + from kivymd.toast.kivytoast import toast # pylint: disable=redefined-outer-name + toast(text) + return class Navigatorss(MDNavigationDrawer): + """Navigators class contains image, title and logo.""" + image_source = StringProperty('images/qidenticon_two.png') title = StringProperty('Navigation') drawer_logo = StringProperty() @@ -59,9 +81,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(): @@ -71,7 +95,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.""" @@ -80,49 +104,74 @@ class Inbox(Screen): def loadMessagelist(self, account, where="", what=""): """Load Inbox list for Inbox messages.""" + # pylint: disable=too-many-locals + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text xAddress = 'toaddress' data = [] 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', ' ') - # ('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] }) + 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] + '........', + '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.bind(on_press = partial(self.inbox_detail, item['receivedTime'])) + 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['receivedTime'])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 + 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_color = (1, 0, 0, .5) - del_btn.bind(on_press=partial(self.delete, item['receivedTime'])) + 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) 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.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', - 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="No message found!" if state.searcing_text + else "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): - """Load inbox page details""" + """Load inbox page details.""" + remove_search_bar(self) state.detailPageType = 'inbox' state.sentMailTime = receivedTime if self.manager: @@ -134,205 +183,361 @@ class Inbox(Screen): src_mng_obj.current = 'mailDetail' 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) + """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.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.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') 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)) + """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()) - except Exception as e: + except Exception: 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.""" + def refresh_callback(interval): + """Method 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: + 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): """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) def init_ui(self, dt=0): """Clock Schdule for method inbox accounts.""" - if BMConfigParser().addresses() or state.kivyapp.variable_1: + # 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()) + addresses_list = filtered_list + if addresses_list: data = [] - for address in state.kivyapp.variable_1: - data.append({'text': BMConfigParser().get(address, 'label'), 'secondary_text': address}) + 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(item['text'][0].upper()))) - meny.bind(on_press=partial(self.myadd_detail, item['secondary_text'], item['text'])) + 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) 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="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') 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: + except Exception: pass - def myadd_detail(self, fromaddress, label, *args): + @staticmethod + def myadd_detail(fromaddress, label, *args): + """Myaddress Details.""" p = MyaddDetailPopup() 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.""" + def refresh_callback(interval): + """Method 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: + 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) + + @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()]): + return True + return False + 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) 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: - 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) + """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], + 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) 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') + content = MDLabel( + 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') self.ids.ml.add_widget(content) - def refreshs(self, *args): + @staticmethod + def refreshs(*args): + """Refresh the Widget.""" state.navinstance.ids.sc11.clear_widgets() state.navinstance.ids.sc11.add_widget(AddressBook()) - def addBook_detail(self, address, label, *args): + @staticmethod + def addBook_detail(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.""" + 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) + # 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])) - rv.parent.txt_input.text = rv.parent.txt_input.text.replace(rv.parent.txt_input.text, rv.data[index]['text']) + 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): + """Recycling View.""" + + def __init__(self, **kwargs): # pylint: disable=useless-super-delegation + """Recycling Method.""" super(RV, self).__init__(**kwargs) class DropDownWidget(BoxLayout): + """Adding Dropdown Widget.""" + txt_input = ObjectProperty() rv = ObjectProperty() - def send(self): + 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) 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) + print "message: ", self.ids.body.text sendMessageToPeople = True 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 * - 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 = '' + state.send_draft_mail = None + 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 - # 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()) + 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 = '' - self.ids.ti.text = '' - self.ids.subject.text = '' - self.ids.txt_input.text = '' - self.parent.parent.current = 'sent' - self.ids.btn.text = 'select' - self.ids.ti.text = '' + queues.workerQueue.put(('sendmessage', toAddress)) + print "sqlExecute successfully #######################" + self.parent.parent.current = 'inbox' + state.in_composer = True + navApp.back_press() + toast('send') return None else: msg = 'Enter a valid recipients address' @@ -342,70 +547,113 @@ 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): - 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.background = './images/popup.jpeg' - self.main_pop.open() + """Show Error Message.""" + msg_dialog = MDDialog( + text=msg, + title='', size_hint=(.8, .25), text_button_ok='Ok', + events_callback=self.callback_for_menu_items) + msg_dialog.open() + + @staticmethod + def callback_for_menu_items(text_item): + """Method is used for getting the callback of alert box""" + toast(text_item) + + def reset_composer(self): + """Method will reset composer.""" + self.ids.ti.text = '' + self.ids.btn.text = 'Select' + self.ids.txt_input.text = '' + self.ids.subject.text = '' + self.ids.body.text = '' + + 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 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): + 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[i][:self.starting_no] == value[:self.starting_no]] - # display the data in the recycleview + matches = [self.word_list[i] for i in range( + len(self.word_list)) if self.word_list[ + i][:self.starting_no] == value[:self.starting_no]] display_data = [] for i in matches: display_data.append({'text': i}) self.parent.parent.parent.parent.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): + """Key Down.""" if self.suggestion_text and keycode[1] == 'tab': self.insert_text(self.suggestion_text + ' ') return True - return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers) + return super(MyTextInput, self).keyboard_on_key_down( + window, keycode, text, modifiers) class Payment(Screen): - pass + """Payment Method.""" + + 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: + 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): + """Login Screeen.""" + 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')) + """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_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.""" super(NetworkStat, self).__init__(*args, **kwargs) Clock.schedule_interval(self.init_ui, 1) @@ -414,62 +662,67 @@ 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): + """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): - import queues - # queues.apiAddressGeneratorReturnQueue.queue.clear() + def generateaddress(self, navApp): + """Method for Address Generator.""" streamNumberForAddress = 1 label = self.ids.label.text eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - if self.ids.label.text: + if str(self.ids.label.text).strip(): queues.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, - payloadLengthExtraBytes) - ) - # self.manager.current = 'add_sucess' + 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 - - # 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()) + navApp.add_search_bar() + toast('New address created') class AddressSuccessful(Screen): - pass + """Getting Address Detail.""" - -class NavigationLayout(): 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(): @@ -479,7 +732,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.""" @@ -488,54 +741,77 @@ 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) - state.totalSentMail = len(queryreturn) - 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) + 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: - 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][: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(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.bind(on_press = partial(self.sent_detail, item['lastactiontime'])) + 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['lastactiontime'])) carousel = Carousel(direction='right') - if platform == 'android': - carousel.height = 150 + 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_color = (1, 0, 0, .5) - del_btn.bind(on_press=partial(self.delete, item['lastactiontime'])) + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + 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.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) - # self.ids.ml.add_widget(meny) 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="No message found!" if state.searcing_text + else "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): - """Load sent mail details""" + """Load sent mail details.""" + remove_search_bar(self) state.detailPageType = 'sent' state.sentMailTime = lastsenttime if self.manager: @@ -547,41 +823,57 @@ 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].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.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) + 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) - - sqlExecute("UPDATE sent SET folder = 'trash' WHERE lastactiontime = {};".format(data_index)) + state.all_count = str(int(state.all_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() + toast('Deleted') 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)) + """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()) - except Exception as e: + 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): """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) @@ -591,46 +883,101 @@ 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, 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 - 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()))) - self.ids.ml.add_widget(meny) + 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 = 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) + 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): + """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.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): +class NavigateApp(App): # pylint: disable=too-many-public-methods + """Navigation Layout of class.""" + theme_cls = ThemeManager() previous_date = ObjectProperty() obj_1 = ObjectProperty() variable_1 = ListProperty(BMConfigParser().addresses()) nav_drawer = ObjectProperty() - total_sentmail = str(state.totalSentMail) state.screen_density = Window.size + window_size = state.screen_density title = "PyBitmessage" + imgstatus = False count = 0 menu_items = [ {'viewclass': 'MDMenuItem', @@ -650,7 +997,7 @@ class NavigateApp(App): ] def build(self): - import os + """Method builds the widget.""" main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -662,141 +1009,307 @@ class NavigateApp(App): return main_widget def run(self): + """Running the widgets.""" kivyuisignaler.release() super(NavigateApp, self).run() - def show_address_success(self): - 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() - + # pylint: disable=inconsistent-return-statements @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(): + 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 [address[:16] + '..' + for address in BMConfigParser().addresses()] + return "valuesdemo" 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 state.association = text self.root.ids.sc1.clear_widgets() - self.root.ids.sc4.clear_widgets() - self.root.ids.sc5.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.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 = 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]) + 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 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 - - - 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)) + msg_counter_objs.draft_cnt.badge_text = state.draft_count + msg_counter_objs.allmail_cnt.badge_text = state.all_count @staticmethod def getCurrentAccount(): """It uses to get current account label.""" if state.association: return state.association - else: - return "Bitmessage Login" + return "Bitmessage Login" - def addingtoaddressbook(self): + @staticmethod + def addingtoaddressbook(): + """Adding to address Book.""" p = GrashofPopup() p.open() 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 addressexist(self): + @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 + + @staticmethod + def get_default_image(): + """Getting default image on address""" + if BMConfigParser().addresses(): + return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + return '' + + @staticmethod + def addressexist(): + """Checking address existence.""" if BMConfigParser().addresses(): 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): - 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": + """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.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) + 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' - return True + 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": + self.root.ids.scr_mngr.current = 'login' else: - return True + 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 - def status_dispatching(self, data): + 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.reset) + + @staticmethod + def status_dispatching(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.set_navbar_for_composer() + self.root.ids.search_bar.clear_widgets() 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 = '' + composer_obj.body.text = '' + state.in_composer = True - def on_stop(self): - """On stop methos is used for stoping the runing script""" - print("**************************EXITING FROM APPLICATION*****************************") + 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 = [ + ['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.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 + self.root.ids.scr_mngr.transition.direction = 'right' + self.root.ids.scr_mngr.transition.bind(on_complete=self.reset) + if state.is_allmail or state.detailPageType == 'draft': + state.is_allmail = False + else: + self.add_search_bar() + state.detailPageType = '' + state.in_composer = False + + @staticmethod + def on_stop(): + """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] + @staticmethod + def current_address_label(current_add_label=None, current_addr=None): + """Getting current address labels.""" + if BMConfigParser().addresses(): + if current_add_label: + first_name = current_add_label + addr = current_addr + else: + 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() + address = ' (' + addr + '...)' + return label + address + return '' + + def searchQuery(self, instance, *args): + """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()) + 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()) + self.root.ids.scr_mngr.current = state.search_screen + + def clearSreeen(self, text): + """Method is used for clear screen""" 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 + 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': - 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 + 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( + 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 = '' + 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) + 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 + 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.""" + 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 @@ -805,22 +1318,37 @@ class GrashofPopup(Popup): self.size_hint_x = 0.7 def savecontact(self): - label = self.ids.label.text - address = self.ids.address.text - if label and address: + """Method is used for Saving Contacts.""" + 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 + + 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') + # pylint: disable=attribute-defined-outside-init 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') + """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), @@ -831,113 +1359,220 @@ class GrashofPopup(Popup): action=lambda *x: self.dialog.dismiss()) self.dialog.open() + @staticmethod + def close_pop(): + """Pop is Canceled.""" + 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")] + 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.""" + 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): pass - def _set_active(self, active, list): + def _set_active(self, active, list): # pylint: disable=redefined-builtin pass 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) 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)) + if state.detailPageType == 'sent' or state.detailPageType == 'draft': + 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) + state.kivyapp.set_mail_detail_header() 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) + state.kivyapp.set_mail_detail_header() - 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() + 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] + 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 = state.kivyapp.root.children[2].children[0].ids 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' + 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.screens[3].clear_widgets() + self.parent.screens[3].add_widget(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()) + 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': + 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): - """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] + """Method used for replying inbox messages.""" + data = sqlQuery( + "select toaddress, fromaddress, subject, message from inbox where \ + received = {};".format(state.sentMailTime)) + 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): - """This method is used for copying sent mail to the composer""" + """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.sentMailTime + 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'] + 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() + + @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() + else: + cpy_text = instance.parent.text + Clipboard.copy(cpy_text) + toast('Copied') + 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 @@ -947,12 +1582,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 @@ -962,12 +1597,20 @@ class MyaddDetailPopup(Popup): window_obj.scr_mngr.current = 'create' self.dismiss() + @staticmethod + def close_pop(): + """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.""" super(AddbookDetailPopup, self).__init__(**kwargs) if state.screen_density[0] <= 720: self.size_hint_y = 0.35 @@ -977,20 +1620,22 @@ 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() + toast('Saved') 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 = '' @@ -1000,10 +1645,388 @@ class AddbookDetailPopup(Popup): window_obj.scr_mngr.current = 'create' self.dismiss() + @staticmethod + def close_pop(): + """Pop is Canceled.""" + 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() - self.ids.qr.add_widget(QRCodeWidget(data=self.manager.get_parent_window().children[0].address)) \ No newline at end of file + 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): + """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(): + 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)) + # 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)) + 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, + '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')) + meny.bind(on_press=partial( + self.draft_detail, item['lastactiontime'])) + 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['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 draft_detail(self, lastsenttime, *args): + """Method used to show draft Details.""" + 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( + data_index)) + try: + 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.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') + + # pylint: disable=unused-variable + @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[ + 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 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 + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '', + 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()) + toast('Save draft') + return + + +class CustomSpinner(Spinner): + """This class is used for setting spinner size.""" + + 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 + + +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.""" + + 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, received from\ + inbox WHERE folder = 'inbox' and toaddress = '{}';".format( + account)) + sent_and_draft = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from sent \ + WHERE folder = 'sent' and fromaddress = '{}';".format( + account)) + + 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 = 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) + 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 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.""" + 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: + 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) + + +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 + + +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 diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 6aafaeff..ee4b7eb9 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): + """Method helps us to connect with the stream""" state.streamsInWhichIAmParticipating.append(streamNumber) if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -109,6 +111,7 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): + """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") @@ -130,6 +133,7 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): + """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), @@ -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 + """Method starts the proxy config plugin""" + @staticmethod def start_proxyconfig(config): """Check socksproxytype and start any proxy configuration plugin""" @@ -207,7 +213,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 + """This method helps to start the daemon""" _fixSocket() config = BMConfigParser() @@ -268,11 +275,14 @@ 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: + pass 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() @@ -384,7 +394,6 @@ class Main: state.uploadThread.start() connectToStream(1) - if config.safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() @@ -396,7 +405,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() @@ -414,8 +423,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 @@ -429,7 +437,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: @@ -439,7 +449,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 @@ -460,7 +470,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 @@ -481,12 +491,15 @@ class Main: os.kill(parentPid, signal.SIGTERM) os.kill(grandfatherPid, signal.SIGTERM) - def setSignalHandler(self): + def setSignalHandler(self): # pylint: disable=no-self-use + """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): + @staticmethod + def usage(): + """After passing argument, method displays the usages""" print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' print ''' Options: @@ -498,13 +511,15 @@ Options: All parameters are optional. ''' - def stop(self): + def stop(self): # pylint: disable=no-self-use + """Method helps to stop the 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 + """This method returns the Api Addresses""" if not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'apienabled'): return None @@ -514,6 +529,7 @@ All parameters are optional. def main(): + """Start of the main thread""" mainprogram = Main() mainprogram.start() 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 cc91e880..444bf8ca 100644 --- a/src/buildozer.spec +++ b/src/buildozer.spec @@ -1,10 +1,10 @@ [app] # (str) Title of your application -title = bluewhale +title = bitapp # (str) Package name -package.name = bluewhale +package.name = bitapp # (str) Package domain (needed for android/ios packaging) package.domain = org.test @@ -35,21 +35,31 @@ 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, + Pillow, + msgpack # (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 +98,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 +156,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 +172,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 +209,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 +217,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 +286,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/class_singleCleaner.py b/src/class_singleCleaner.py index a5938716..eb67fcef 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -92,7 +92,7 @@ class singleCleaner(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 a7e19762..ca8c0b95 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -71,7 +71,7 @@ class singleWorker(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 @@ -514,7 +514,7 @@ class singleWorker(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 @@ -684,7 +684,7 @@ class singleWorker(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, \ @@ -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/images/copy_text.png b/src/images/copy_text.png new file mode 100644 index 00000000..dcc63611 Binary files /dev/null and b/src/images/copy_text.png differ diff --git a/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png b/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png new file mode 100644 index 00000000..22def0cd Binary files /dev/null and b/src/images/default_identicon/BM-2cXQpSjUCAf8fvAQCvsrLDVkLnDAkSjRGN.png differ diff --git a/src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png b/src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png new file mode 100644 index 00000000..c886f8fc Binary files /dev/null and b/src/images/default_identicon/BM-2cXewfSjCgGMPB5qYwUSCD2Q57bGLWgD3C.png differ diff --git a/src/images/down-arrow.png b/src/images/down-arrow.png new file mode 100644 index 00000000..bf3e864c Binary files /dev/null and b/src/images/down-arrow.png differ diff --git a/src/images/right-arrow.png b/src/images/right-arrow.png new file mode 100644 index 00000000..8f136a77 Binary files /dev/null and b/src/images/right-arrow.png differ diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 7319dfd5..01248197 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -5,7 +5,10 @@ src/messagetypes/__init__.py 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 @@ -39,8 +42,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/paths.py b/src/paths.py index 63e92704..c4c62950 100644 --- a/src/paths.py +++ b/src/paths.py @@ -42,8 +42,7 @@ def lookupAppdataFolder(): print stringToLog 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) + '/' 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 0aa30589..ae50116a 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -1,4 +1,14 @@ -#!/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 -*- """ src/pyelliptic/openssl.py @@ -10,11 +20,8 @@ src/pyelliptic/openssl.py # Software slightly changed by Jonathan Warren # pylint: disable=protected-access -import sys -import ctypes -OpenSSL = None -from kivy.utils import platform + class CipherName: """Class returns cipher name, pointer and blocksize""" @@ -31,7 +38,7 @@ class CipherName: " | Function pointer : " + str(self._pointer) def get_pointer(self): - """This method returns cipher pointer""" + """Method returns the pointer""" return self._pointer() def get_name(self): @@ -44,7 +51,7 @@ class CipherName: def get_version(library): - """This function return version, hexversion and cflages""" + """Method returns the version of the OpenSSL Library""" version = None hexversion = None cflags = None @@ -81,9 +88,7 @@ class _OpenSSL: """ # pylint: disable=too-many-statements, too-many-instance-attributes, old-style-class 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") @@ -649,8 +654,13 @@ 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 @@ -690,14 +700,18 @@ 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') 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: - 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: diff --git a/src/state.py b/src/state.py index 0311a342..63fa82e4 100644 --- a/src/state.py +++ b/src/state.py @@ -63,8 +63,6 @@ kivyapp = None navinstance = None -totalSentMail = 0 - sentMailTime = 0 myAddressObj = None @@ -85,4 +83,22 @@ sent_count = 0 inbox_count = 0 -trash_count = 0 \ No newline at end of file +trash_count = 0 + +draft_count = 0 + +all_count = 0 + +searcing_text = '' + +search_screen = '' + +send_draft_mail = None + +is_allmail = False + +in_composer = False + +write_msg = {} + +availabe_credit = 0 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: