From ebb350b81b53e5ded905a02c4428fb803e780b46 Mon Sep 17 00:00:00 2001 From: navjot Date: Tue, 23 Mar 2021 02:25:52 +0530 Subject: [PATCH] split mpybit module into multiple files and added working test with it --- src/bitmessagekivy/baseclass/addressbook.py | 191 ++ src/bitmessagekivy/baseclass/allmail.py | 209 ++ src/bitmessagekivy/baseclass/common.py | 129 + src/bitmessagekivy/baseclass/draft.py | 206 ++ src/bitmessagekivy/baseclass/inbox.py | 259 ++ src/bitmessagekivy/baseclass/login.py | 112 + src/bitmessagekivy/baseclass/maildetail.py | 236 ++ src/bitmessagekivy/baseclass/msg_composer.py | 307 ++ src/bitmessagekivy/baseclass/myaddress.py | 249 ++ src/bitmessagekivy/baseclass/network.py | 41 + src/bitmessagekivy/baseclass/payment.py | 67 + src/bitmessagekivy/baseclass/popup.py | 232 ++ src/bitmessagekivy/baseclass/qrcode.py | 23 + src/bitmessagekivy/baseclass/scan_screen.py | 113 + src/bitmessagekivy/baseclass/sent.py | 247 ++ src/bitmessagekivy/baseclass/settings.py | 91 + src/bitmessagekivy/baseclass/trash.py | 196 ++ src/bitmessagekivy/kv/maildetail.kv | 8 +- .../kv/{composer.kv => msg_composer.kv} | 6 + src/bitmessagekivy/kv/qrcode.kv | 33 + src/bitmessagekivy/kv/scan_screen.kv | 2 + src/bitmessagekivy/main.kv | 162 +- src/bitmessagekivy/mpybit.py | 2817 +---------------- src/bitmessagekivy/screens_data.json | 79 + src/bitmessagekivy/tests/test_addressbook.py | 105 - .../tests/test_allmail_message.py | 26 - .../tests/test_draft_message.py | 92 - .../tests/test_myaddress_screen.py | 55 - .../tests/test_network_screen.py | 18 - .../tests/test_payment_subscription.py | 25 - src/bitmessagekivy/tests/test_sent_message.py | 101 - .../tests/test_setting_screen.py | 16 - .../tests/test_trash_message.py | 22 - 33 files changed, 3168 insertions(+), 3307 deletions(-) create mode 100644 src/bitmessagekivy/baseclass/addressbook.py create mode 100644 src/bitmessagekivy/baseclass/allmail.py create mode 100644 src/bitmessagekivy/baseclass/common.py create mode 100644 src/bitmessagekivy/baseclass/draft.py create mode 100644 src/bitmessagekivy/baseclass/inbox.py create mode 100644 src/bitmessagekivy/baseclass/login.py create mode 100644 src/bitmessagekivy/baseclass/maildetail.py create mode 100644 src/bitmessagekivy/baseclass/msg_composer.py create mode 100644 src/bitmessagekivy/baseclass/myaddress.py create mode 100644 src/bitmessagekivy/baseclass/network.py create mode 100644 src/bitmessagekivy/baseclass/payment.py create mode 100644 src/bitmessagekivy/baseclass/popup.py create mode 100644 src/bitmessagekivy/baseclass/qrcode.py create mode 100644 src/bitmessagekivy/baseclass/scan_screen.py create mode 100644 src/bitmessagekivy/baseclass/sent.py create mode 100644 src/bitmessagekivy/baseclass/settings.py create mode 100644 src/bitmessagekivy/baseclass/trash.py rename src/bitmessagekivy/kv/{composer.kv => msg_composer.kv} (98%) create mode 100644 src/bitmessagekivy/kv/qrcode.kv create mode 100644 src/bitmessagekivy/kv/scan_screen.kv create mode 100644 src/bitmessagekivy/screens_data.json delete mode 100644 src/bitmessagekivy/tests/test_addressbook.py delete mode 100644 src/bitmessagekivy/tests/test_allmail_message.py delete mode 100644 src/bitmessagekivy/tests/test_draft_message.py delete mode 100644 src/bitmessagekivy/tests/test_myaddress_screen.py delete mode 100644 src/bitmessagekivy/tests/test_network_screen.py delete mode 100644 src/bitmessagekivy/tests/test_payment_subscription.py delete mode 100644 src/bitmessagekivy/tests/test_sent_message.py delete mode 100644 src/bitmessagekivy/tests/test_setting_screen.py delete mode 100644 src/bitmessagekivy/tests/test_trash_message.py diff --git a/src/bitmessagekivy/baseclass/addressbook.py b/src/bitmessagekivy/baseclass/addressbook.py new file mode 100644 index 00000000..3066390b --- /dev/null +++ b/src/bitmessagekivy/baseclass/addressbook.py @@ -0,0 +1,191 @@ +from bitmessagekivy.get_platform import platform +from bitmessagekivy import kivy_helper_search +from helper_sql import sqlExecute +from functools import partial +from kivy.clock import Clock +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.button import Button +from kivymd.uix.button import MDRaisedButton +from kivy.uix.carousel import Carousel +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem +from kivy.uix.screenmanager import Screen + +import state + +from bitmessagekivy.baseclass.common import ( + AvatarSampleWidget, avatarImageFirstLetter, toast, + ThemeClsColor, +) +from bitmessagekivy.baseclass.popup import AddbookDetailPopup + + +class AddressBook(Screen): + """AddressBook Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + address_label = StringProperty() + address = StringProperty() + + def __init__(self, *args, **kwargs): + """Getting AddressBook Details""" + super(AddressBook, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method AddressBook""" + self.loadAddresslist(None, 'All', '') + print(dt) + + def loadAddresslist(self, account, where="", what=""): + """Clock Schdule for method AddressBook""" + if state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 + where = ['label', 'address'] + what = state.searcing_text + xAddress = '' + self.ids.tag_label.text = '' + self.queryreturn = kivy_helper_search.search_sql( + xAddress, account, "addressbook", where, what, False) + self.queryreturn = [obj for obj in reversed(self.queryreturn)] + if self.queryreturn: + self.ids.tag_label.text = 'Address Book' + self.has_refreshed = True + self.set_mdList(0, 20) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No contact found!" if state.searcing_text + else "No contact found yet...... ", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def set_mdList(self, start_index, end_index): + """Creating the mdList""" + for item in self.queryreturn[start_index:end_index]: + meny = TwoLineAvatarIconListItem( + text=item[0], secondary_text=item[1], theme_text_color='Custom', + text_color=ThemeClsColor) + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(item[0].strip())))) + meny.bind(on_press=partial( + self.addBook_detail, item[1], item[0])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete_address, item[1])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + exist_addresses = len(self.ids.ml.children) + if exist_addresses != len(self.queryreturn): + self.update_addressBook_on_scroll(exist_addresses) + self.has_refreshed = ( + True if exist_addresses != len(self.queryreturn) else False + ) + + def update_addressBook_on_scroll(self, exist_addresses): + """Load more data on scroll down""" + self.set_mdList(exist_addresses, exist_addresses + 5) + + @staticmethod + def refreshs(*args): + """Refresh the Widget""" + # state.navinstance.ids.sc11.ids.ml.clear_widgets() + # state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') + + # @staticmethod + def addBook_detail(self, address, label, *args): + """Addressbook details""" + obj = AddbookDetailPopup() + self.address_label = obj.address_label = label + self.address = obj.address = address + width = .9 if platform == 'android' else .8 + self.addbook_popup = MDDialog( + type="custom", + size_hint=(width, .25), + content_cls=obj, + buttons=[ + MDRaisedButton( + text="Send message to", + on_release=self.send_message_to, + ), + MDRaisedButton( + text="Save", + on_release=self.update_addbook_label, + ), + MDRaisedButton( + text="Cancel", + on_release=self.close_pop, + ), + ], + ) + self.addbook_popup.set_normal_height() + self.addbook_popup.auto_dismiss = False + self.addbook_popup.open() + + def delete_address(self, address, instance, *args): + """Delete inbox mail from inbox listing""" + self.ids.ml.remove_widget(instance.parent.parent) + # if len(self.ids.ml.children) == 0: + if self.ids.ml.children is not None: + self.ids.tag_label.text = '' + sqlExecute( + "DELETE FROM addressbook WHERE address = '{}';".format(address)) + + def close_pop(self, instance): + """Pop is Canceled""" + self.addbook_popup.dismiss() + toast('Canceled') + + def update_addbook_label(self, instance): + """Updating the label of address book address""" + address_list = kivy_helper_search.search_sql(folder="addressbook") + stored_labels = [labels[0] for labels in address_list] + add_dict = dict(address_list) + label = str(self.addbook_popup.content_cls.ids.add_label.text) + if label in stored_labels and self.address == add_dict[label]: + stored_labels.remove(label) + if label and label not in stored_labels: + sqlExecute( + "UPDATE addressbook SET label = '{}' WHERE" + " address = '{}';".format( + label, self.addbook_popup.content_cls.address)) + state.kivyapp.root.ids.sc11.ids.ml.clear_widgets() + state.kivyapp.root.ids.sc11.loadAddresslist(None, 'All', '') + self.addbook_popup.dismiss() + toast('Saved') + + def send_message_to(self, instance): + """Method used to fill to_address of composer autofield""" + state.kivyapp.set_navbar_for_composer() + window_obj = state.kivyapp.root.ids + window_obj.sc3.children[1].ids.txt_input.text = self.address + window_obj.sc3.children[1].ids.ti.text = '' + window_obj.sc3.children[1].ids.btn.text = 'Select' + window_obj.sc3.children[1].ids.subject.text = '' + window_obj.sc3.children[1].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.addbook_popup.dismiss() \ No newline at end of file diff --git a/src/bitmessagekivy/baseclass/allmail.py b/src/bitmessagekivy/baseclass/allmail.py new file mode 100644 index 00000000..1da31af2 --- /dev/null +++ b/src/bitmessagekivy/baseclass/allmail.py @@ -0,0 +1,209 @@ +from bitmessagekivy import kivy_helper_search +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute, sqlQuery +from functools import partial +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.button import Button +from kivy.uix.carousel import Carousel +from kivy.uix.screenmanager import Screen +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem + +import state + +from bitmessagekivy.baseclass.common import ( + showLimitedCnt, toast, initailize_detail_page, ThemeClsColor, + chipTag, avatarImageFirstLetter, AddTimeWidget, AvatarSampleWidget +) +from bitmessagekivy.baseclass.trash import Trash + + +class Allmails(Screen): + """Allmails Screen for kivy Ui""" + + data = ListProperty() + has_refreshed = True + all_mails = ListProperty() + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Method Parsing the address""" + super(Allmails, self).__init__(*args, **kwargs) + if 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.loadMessagelist() + print(dt) + + def loadMessagelist(self): + """Load Inbox, Sent anf Draft list of messages""" + self.account = state.association + self.ids.tag_label.text = '' + self.allMessageQuery(0, 20) + if self.all_mails: + self.ids.tag_label.text = 'All Mails' + state.kivyapp.get_inbox_count() + state.kivyapp.get_sent_count() + state.all_count = str( + int(state.sent_count) + int(state.inbox_count)) + self.set_AllmailCnt(state.all_count) + self.set_mdlist() + # self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_AllmailCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def allMessageQuery(self, start_indx, end_indx): + """Retrieving data from inbox or sent both tables""" + self.all_mails = sqlQuery( + "SELECT toaddress, fromaddress, subject, message, folder, ackdata" + " As id, DATE(senttime) As actionTime, senttime as msgtime FROM sent WHERE" + " folder = 'sent' and fromaddress = '{0}'" + " UNION SELECT toaddress, fromaddress, subject, message, folder," + " msgid As id, DATE(received) As actionTime, received as msgtime FROM inbox" + " WHERE folder = 'inbox' and toaddress = '{0}'" + " ORDER BY actionTime DESC limit {1}, {2}".format( + self.account, start_indx, end_indx)) + + def set_AllmailCnt(self, Count): # pylint: disable=no-self-use + """This method is used to set allmails message count""" + allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt + allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdlist(self): + """This method is used to create mdList for allmaills""" + data_exist = len(self.ids.ml.children) + for item in self.all_mails: + body = item[3].decode() if isinstance(item[3], bytes) else item[3] + subject = item[2].decode() if isinstance(item[2], bytes) else item[2] + meny = TwoLineAvatarIconListItem( + text=item[1], + secondary_text=(subject[:50] + '........' if len( + subject) >= 50 else ( + subject + ',' + body)[0:50] + '........').replace('\t', '').replace(' ', ''), + theme_text_color='Custom', + text_color=ThemeClsColor) + meny._txt_right_pad = dp(70) + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(body.strip())))) + meny.bind(on_press=partial( + self.mail_detail, item[5], item[4])) + meny.add_widget(AddTimeWidget(item[7])) + meny.add_widget(chipTag(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) + updated_data = len(self.ids.ml.children) + self.has_refreshed = True if data_exist != updated_data else False + + def check_scroll_y(self, instance, somethingelse): + """Scroll fixed length""" + if self.ids.scroll_y.scroll_y <= -0.00 and self.has_refreshed: + self.ids.scroll_y.scroll_y = .06 + load_more = len(self.ids.ml.children) + self.updating_allmail(load_more) + + def updating_allmail(self, load_more): + """This method is used to update the all mail + listing value on the scroll of screen""" + self.allMessageQuery(load_more, 5) + self.set_mdlist() + + def mail_detail(self, unique_id, folder, *args): + """Load sent and inbox mail details""" + state.detailPageType = folder + state.is_allmail = True + state.mail_id = 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' + initailize_detail_page(src_mng_obj) + + def swipe_delete(self, unique_id, folder, instance, *args): + """Delete inbox mail from all mail listing""" + if folder == 'inbox': + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", + unique_id) + else: + sqlExecute( + "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", + unique_id) + self.ids.ml.remove_widget(instance.parent.parent) + try: + msg_count_objs = self.parent.parent.ids.content_drawer.ids + nav_lay_obj = self.parent.parent.ids + except Exception: + msg_count_objs = self.parent.parent.parent.ids.content_drawer.ids + nav_lay_obj = self.parent.parent.parent.ids + if folder == 'inbox': + msg_count_objs.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) + nav_lay_obj.sc1.ids.ml.clear_widgets() + nav_lay_obj.sc1.loadMessagelist(state.association) + else: + msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(state.sent_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) + nav_lay_obj.sc4.ids.ml.clear_widgets() + nav_lay_obj.sc4.loadSent(state.association) + if folder != 'inbox': + msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count) - 1) + state.all_count = str(int(state.all_count) - 1) + msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(state.trash_count) + 1) + state.trash_count = str(int(state.trash_count) + 1) + if int(state.all_count) <= 0: + self.ids.tag_label.text = '' + nav_lay_obj.sc5.clear_widgets() + nav_lay_obj.sc5.add_widget(Trash()) + nav_lay_obj.sc17.remove_widget(instance.parent.parent) + toast('Deleted') + + def refresh_callback(self, *args): + """Method updates the state of application, + While the spinner remains on the screen""" + def refresh_callback(interval): + """Load 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) diff --git a/src/bitmessagekivy/baseclass/common.py b/src/bitmessagekivy/baseclass/common.py new file mode 100644 index 00000000..ad156f83 --- /dev/null +++ b/src/bitmessagekivy/baseclass/common.py @@ -0,0 +1,129 @@ +import os +from datetime import datetime +from kivy.lang import Builder +from kivy.metrics import dp +from kivymd.uix.list import ( + ILeftBody, + IRightBodyTouch, + TwoLineAvatarIconListItem, + OneLineIconListItem, + OneLineAvatarIconListItem, + OneLineListItem +) +from kivy.uix.image import Image +from kivymd.uix.label import MDLabel +from bitmessagekivy.get_platform import platform +from kivymd.uix.chip import MDChip + + +ThemeClsColor = [0.12, 0.58, 0.95, 1] + + +data_screens = { + "MailDetail": { + "kv_string": "maildetail", + "Factory": "MailDetail()", + "name_screen": "mailDetail", + "object": 0, + "Import": "from bitmessagekivy.baseclass.maildetail import MailDetail", + } +,} + + +def chipTag(text): + """This method is used for showing chip tag""" + obj = MDChip() + # obj.size_hint = (None, None) + obj.size_hint = (0.16 if platform == "android" else 0.08, None) + obj.text = text + obj.icon = "" + obj.pos_hint = { + "center_x": 0.91 if platform == "android" else 0.94, + "center_y": 0.3 + } + obj.height = dp(18) + obj.text_color = (1,1,1,1) + obj.radius =[8] + return obj + + +def initailize_detail_page(manager): + if not manager.has_screen( + data_screens['MailDetail']["name_screen"] + ): + Builder.load_file( + os.path.join( + # os.environ["KITCHEN_SINK_ROOT"], + os.path.dirname(os.path.dirname(__file__)), + "kv", + "maildetail.kv", + ) + ) + if "Import" in data_screens['MailDetail']: + exec(data_screens['MailDetail']["Import"]) + screen_object = eval(data_screens['MailDetail']["Factory"]) + data_screens['MailDetail']["object"] = screen_object + manager.add_widget(screen_object) + manager.current = data_screens['MailDetail']["name_screen"] + +def toast(text): + """Method will display the toast message""" + # pylint: disable=redefined-outer-name + from kivymd.toast.kivytoast import toast + + toast(text) + return None + + +def showLimitedCnt(total_msg): + """This method set the total count limit in badge_text""" + return "99+" if total_msg > 99 else str(total_msg) + + +def avatarImageFirstLetter(letter_string): + """This function is used to the first letter for the avatar image""" + try: + if letter_string[0].upper() >= 'A' and letter_string[0].upper() <= 'Z': + img_latter = letter_string[0].upper() + elif int(letter_string[0]) >= 0 and int(letter_string[0]) <= 9: + img_latter = letter_string[0] + else: + img_latter = '!' + except ValueError: + img_latter = '!' + return img_latter if img_latter else '!' + + +def AddTimeWidget(time): # pylint: disable=redefined-outer-name + """This method is used to create TimeWidget""" + action_time = TimeTagRightSampleWidget( + text=str(ShowTimeHistoy(time)), + font_style="Caption", + size=[120, 140] if platform == "android" else [64, 80], + ) + action_time.font_size = "11sp" + return action_time + + +def ShowTimeHistoy(act_time): + """This method is used to return the message sent or receive time""" + action_time = datetime.fromtimestamp(int(act_time)) + crnt_date = datetime.now() + duration = crnt_date - action_time + display_data = ( + action_time.strftime("%d/%m/%Y") + if duration.days >= 365 + else action_time.strftime("%I:%M %p").lstrip("0") + if duration.days == 0 and crnt_date.strftime("%d/%m/%Y") == action_time.strftime("%d/%m/%Y") + else action_time.strftime("%d %b") + ) + return display_data + + +class AvatarSampleWidget(ILeftBody, Image): + """AvatarSampleWidget class for kivy Ui""" + + +class TimeTagRightSampleWidget(IRightBodyTouch, MDLabel): + """TimeTagRightSampleWidget class for Ui""" + diff --git a/src/bitmessagekivy/baseclass/draft.py b/src/bitmessagekivy/baseclass/draft.py new file mode 100644 index 00000000..db120900 --- /dev/null +++ b/src/bitmessagekivy/baseclass/draft.py @@ -0,0 +1,206 @@ +from bitmessagekivy import kivy_helper_search +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute +from functools import partial +from addresses import decodeAddress +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.button import Button +from kivy.uix.carousel import Carousel +from kivy.uix.screenmanager import Screen +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem + +import state + +from bitmessagekivy.baseclass.common import ( + showLimitedCnt, initailize_detail_page, toast, ThemeClsColor, + AddTimeWidget, AvatarSampleWidget +) + + +class Draft(Screen): + """Draft screen class for kivy Ui""" + + data = ListProperty() + account = StringProperty() + queryreturn = ListProperty() + has_refreshed = True + + def __init__(self, *args, **kwargs): + """Method used for storing draft messages""" + super(Draft, self).__init__(*args, **kwargs) + if 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""" + self.account = state.association + self.loadDraft() + + def loadDraft(self, where="", what=""): + """Load draft list for Draft messages""" + xAddress = 'fromaddress' + self.ids.tag_label.text = '' + self.draftDataQuery(xAddress, where, what) + # if state.msg_counter_objs: + # state.msg_counter_objs.draft_cnt.children[0].children[0].text = showLimitedCnt(len(self.queryreturn)) + if self.queryreturn: + self.ids.tag_label.text = 'Draft' + self.set_draftCnt(state.draft_count) + self.set_mdList() + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_draftCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def draftDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This methosd is for retrieving draft messages""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, self.account, "draft", where, what, + False, start_indx, end_indx) + + def set_draftCnt(self, Count): # pylint: disable=no-self-use + """This method set the count of draft mails""" + draftCnt_obj = state.kivyapp.root.ids.content_drawer.ids.draft_cnt + draftCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdList(self): + """This method is used to create mdlist""" + data = [] + total_draft_msg = len(self.ids.ml.children) + for mail in self.queryreturn: + third_text = mail[3].replace('\n', ' ') + data.append({ + 'text': mail[1].strip(), + 'secondary_text': mail[2][:10] + '...........' if len( + mail[2]) > 10 else mail[2] + '\n' + " " + ( + third_text[:25] + '...!') if len( + third_text) > 25 else third_text, + 'ackdata': mail[5], 'senttime': mail[6]}) + for item in data: + meny = TwoLineAvatarIconListItem( + text='Draft', secondary_text=item['text'], + theme_text_color='Custom', + text_color=ThemeClsColor) + meny._txt_right_pad = dp(70) + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + '/avatar.png')) + meny.bind(on_press=partial( + self.draft_detail, item['ackdata'])) + meny.add_widget(AddTimeWidget(item['senttime'])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete_draft, item['ackdata'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + updated_msg = len(self.ids.ml.children) + self.has_refreshed = True if total_draft_msg != updated_msg else False + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + total_draft_msg = len(self.ids.ml.children) + self.update_draft_screen_on_scroll(total_draft_msg) + + def update_draft_screen_on_scroll(self, total_draft_msg, where='', what=''): + """Load more data on scroll down""" + self.draftDataQuery('fromaddress', where, what, total_draft_msg, 5) + self.set_mdList() + + def draft_detail(self, ackdata, *args): + """Show draft Details""" + state.detailPageType = 'draft' + state.mail_id = ackdata + 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' + initailize_detail_page(src_mng_obj) + + def delete_draft(self, data_index, instance, *args): + """Delete draft message permanently""" + sqlExecute("DELETE FROM sent WHERE ackdata = ?;", data_index) + if int(state.draft_count) > 0: + state.draft_count = str(int(state.draft_count) - 1) + self.set_draftCnt(state.draft_count) + if int(state.draft_count) <= 0: + # self.ids.identi_tag.children[0].text = '' + self.ids.tag_label.text = '' + self.ids.ml.remove_widget(instance.parent.parent) + toast('Deleted') + + @staticmethod + def draft_msg(src_object): + """Save draft mails""" + composer_object = state.kivyapp.root.ids.sc3.children[1].ids + fromAddress = str(composer_object.ti.text) + toAddress = str(composer_object.txt_input.text) + subject = str(composer_object.subject.text) + message = str(composer_object.body.text) + encoding = 3 + sendMessageToPeople = True + if sendMessageToPeople: + streamNumber, ripe = decodeAddress(toAddress)[2:] + from addresses import addBMIfNotPresent + toAddress = addBMIfNotPresent(toAddress) + stealthLevel = BMConfigParser().safeGetInt( + 'bitmessagesettings', 'ackstealthlevel') + from helper_ackPayload import genAckPayload + ackdata = genAckPayload(streamNumber, stealthLevel) + sqlExecute( + '''INSERT INTO sent VALUES + (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), + int(time.time()), + 0, + 'msgqueued', + 0, + 'draft', + encoding, + BMConfigParser().safeGetInt('bitmessagesettings', 'ttl')) + state.msg_counter_objs = src_object.children[2].children[0].ids + state.draft_count = str(int(state.draft_count) + 1) \ + if state.association == fromAddress else state.draft_count + src_object.ids.sc16.clear_widgets() + src_object.ids.sc16.add_widget(Draft()) + toast('Save draft') + return diff --git a/src/bitmessagekivy/baseclass/inbox.py b/src/bitmessagekivy/baseclass/inbox.py new file mode 100644 index 00000000..e62544dd --- /dev/null +++ b/src/bitmessagekivy/baseclass/inbox.py @@ -0,0 +1,259 @@ +# from bitmessagekivy.get_platform import platform +# from bitmessagekivy import identiconGeneration +from bitmessagekivy import kivy_helper_search +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute +from functools import partial +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.button import Button +from kivy.uix.carousel import Carousel +from kivy.uix.screenmanager import Screen +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem + +import state + +from bitmessagekivy.baseclass.common import ( + showLimitedCnt, initailize_detail_page, avatarImageFirstLetter, + AddTimeWidget, ThemeClsColor, AvatarSampleWidget, toast +) + + +class Inbox(Screen): + """Inbox Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Method Parsing the address""" + super(Inbox, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + @staticmethod + def set_defaultAddress(): + """This method set's default address""" + if state.association == "": + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + + def init_ui(self, dt=0): + """Clock schdule for method inbox accounts""" + self.loadMessagelist() + + def loadMessagelist(self, where="", what=""): + """Load Inbox list for Inbox messages""" + self.set_defaultAddress() + self.account = state.association + if state.searcing_text: + # self.children[2].children[0].children[0].scroll_y = 1.0 + self.ids.scroll_y.scroll_y = 1.0 + where = ["subject", "message"] + what = state.searcing_text + xAddress = "toaddress" + data = [] + self.ids.tag_label.text = "" + self.inboxDataQuery(xAddress, where, what) + self.ids.tag_label.text = "" + if self.queryreturn: + self.ids.tag_label.text = "Inbox" + state.kivyapp.get_inbox_count() + self.set_inboxCount(state.inbox_count) + for mail in self.queryreturn: + # third_text = mail[3].replace('\n', ' ') + body = mail[3].decode() if isinstance(mail[3], bytes) else mail[3] + subject = mail[5].decode() if isinstance(mail[5], bytes) else mail[5] + data.append( + { + "text": mail[4].strip(), + "secondary_text": ( + subject[:50] + "........" + if len(subject) >= 50 + else (subject + "," + body)[0:50] + "........" + ) + .replace("\t", "") + .replace(" ", ""), + "msgid": mail[1], + "received": mail[6] + } + ) + + self.has_refreshed = True + self.set_mdList(data) + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_inboxCount("0") + content = MDLabel( + font_style="Caption", + theme_text_color="Primary", + text="No message found!" + if state.searcing_text + else "yet no message for this account!!!!!!!!!!!!!", + halign="center", + size_hint_y=None, + valign="top" + ) + self.ids.ml.add_widget(content) + + def set_inboxCount(self, msgCnt): # pylint: disable=no-self-use + """This method is used to sent inbox message count""" + src_mng_obj = state.kivyapp.root.ids.content_drawer.ids + src_mng_obj.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(msgCnt)) + state.kivyapp.get_sent_count() + state.all_count = str( + int(state.sent_count) + int(state.inbox_count)) + src_mng_obj.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count)) + + def inboxDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This method is used for retrieving inbox data""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, self.account, "inbox", where, what, False, start_indx, end_indx + ) + + def set_mdList(self, data): + """This method is used to create the mdList""" + total_message = len(self.ids.ml.children) + for item in data: + meny = TwoLineAvatarIconListItem( + text=item["text"], + secondary_text=item["secondary_text"], + theme_text_color="Custom", + text_color=ThemeClsColor + ) + meny._txt_right_pad = dp(70) + meny.add_widget( + AvatarSampleWidget( + source=state.imageDir + "/text_images/{}.png".format( + avatarImageFirstLetter(item["secondary_text"].strip()) + ) + ) + ) + meny.bind(on_press=partial(self.inbox_detail, item["msgid"])) + meny.add_widget(AddTimeWidget(item["received"])) + carousel = Carousel(direction="right") + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text="Delete") + del_btn.background_normal = "" + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete, item["msgid"])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + # ach_btn = Button(text='Achieve') + # ach_btn.background_color = (0, 1, 0, 1) + # ach_btn.bind(on_press=partial(self.archive, item['msgid'])) + # carousel.add_widget(ach_btn) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + update_message = len(self.ids.ml.children) + self.has_refreshed = True if total_message != update_message else False + + def check_scroll_y(self, instance, somethingelse): + """Loads data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + total_message = len(self.ids.ml.children) + self.update_inbox_screen_on_scroll(total_message) + + def update_inbox_screen_on_scroll(self, total_message, where="", what=""): + """This method is used to load more data on scroll down""" + data = [] + if state.searcing_text: + where = ["subject", "message"] + what = state.searcing_text + self.inboxDataQuery("toaddress", where, what, total_message, 5) + for mail in self.queryreturn: + # third_text = mail[3].replace('\n', ' ') + subject = mail[3].decode() if isinstance(mail[3], bytes) else mail[3] + body = mail[5].decode() if isinstance(mail[5], bytes) else mail[5] + data.append( + { + "text": mail[4].strip(), + "secondary_text": body[:50] + "........" + if len(body) >= 50 + else (body + "," + subject.replace("\n", ""))[0:50] + "........", + "msgid": mail[1], + "received": mail[6] + } + ) + self.set_mdList(data) + + def inbox_detail(self, msg_id, *args): + """Load inbox page details""" + state.detailPageType = "inbox" + state.mail_id = msg_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" + initailize_detail_page(src_mng_obj) + + def delete(self, data_index, instance, *args): + """Delete inbox mail from inbox listing""" + sqlExecute("UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", data_index) + msg_count_objs = self.parent.parent.ids.content_drawer.ids + if int(state.inbox_count) > 0: + msg_count_objs.inbox_cnt.ids.badge_txt.text = showLimitedCnt( + int(state.inbox_count) - 1 + ) + msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt( + int(state.trash_count) + 1 + ) + state.inbox_count = str(int(state.inbox_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + if int(state.all_count) > 0: + msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt( + int(state.all_count) - 1 + ) + state.all_count = str(int(state.all_count) - 1) + + if int(state.inbox_count) <= 0: + # self.ids.identi_tag.children[0].text = '' + self.ids.tag_label.text = '' + 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 msgid = ?;", data_index) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + except Exception: + self.parent.parent.screens[4].clear_widgets() + self.parent.parent.screens[4].add_widget(Trash()) + + 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""" + state.searcing_text = "" + self.children[2].children[1].ids.search_field.text = "" + self.ids.ml.clear_widgets() + self.loadMessagelist(state.association) + self.has_refreshed = True + self.ids.refresh_layout.refresh_done() + self.tick = 0 + + Clock.schedule_once(refresh_callback, 1) diff --git a/src/bitmessagekivy/baseclass/login.py b/src/bitmessagekivy/baseclass/login.py new file mode 100644 index 00000000..7d4a8cc7 --- /dev/null +++ b/src/bitmessagekivy/baseclass/login.py @@ -0,0 +1,112 @@ +import queues + +from bmconfigparser import BMConfigParser +from kivy.clock import Clock +from kivy.properties import StringProperty, BooleanProperty +from kivy.uix.boxlayout import BoxLayout +from kivymd.uix.behaviors.elevation import RectangularElevationBehavior +from kivy.uix.screenmanager import Screen + +import state + +from bitmessagekivy.baseclass.common import ( + toast, ThemeClsColor +) + + +class Login(Screen): + """Login Screeen class for kivy Ui""" + log_text1 = ( + 'You may generate addresses by using either random numbers' + ' or by using a passphrase If you use a passphrase, the address' + ' is called a deterministic; address The Random Number option is' + ' selected by default but deterministic addresses have several pros' + ' and cons:') + log_text2 = ('If talk about pros You can recreate your addresses on any computer' + ' from memory, You need-not worry about backing up your keys.dat file' + ' as long as you can remember your passphrase and aside talk about cons' + ' You must remember (or write down) your You must remember the address' + ' version number and the stream number along with your passphrase If you' + ' choose a weak passphrase and someone on the Internet can brute-force it,' + ' they can read your messages and send messages as you') + + +class Random(Screen): + """Random Screen class for Ui""" + + is_active = BooleanProperty(False) + checked = StringProperty("") + + def generateaddress(self, navApp): + """Method for Address Generator""" + # entered_label = str(self.ids.lab.text).strip() + entered_label = str(self.ids.add_random_bx.children[0].ids.lab.text).strip() + if not entered_label: + self.ids.add_random_bx.children[0].ids.lab.focus = True + streamNumberForAddress = 1 + eighteenByteRipe = False + nonceTrialsPerByte = 1000 + payloadLengthExtraBytes = 1000 + lables = [BMConfigParser().get(obj, 'label') + for obj in BMConfigParser().addresses()] + if entered_label and entered_label not in lables: + toast('Address Creating...') + queues.addressGeneratorQueue.put(( + 'createRandomAddress', 4, streamNumberForAddress, entered_label, 1, + "", eighteenByteRipe, nonceTrialsPerByte, + payloadLengthExtraBytes)) + self.parent.parent.ids.toolbar.opacity = 1 + self.parent.parent.ids.toolbar.disabled = False + state.kivyapp.loadMyAddressScreen(True) + self.manager.current = 'myaddress' + Clock.schedule_once(self.address_created_callback, 6) + + def address_created_callback(self, dt=0): + """New address created""" + state.kivyapp.loadMyAddressScreen(False) + state.kivyapp.root.ids.sc10.ids.ml.clear_widgets() + state.kivyapp.root.ids.sc10.is_add_created = True + state.kivyapp.root.ids.sc10.init_ui() + self.reset_address_spinner() + toast('New address created') + + def reset_address_spinner(self): + """reseting spinner address and UI""" + addresses = [addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true'] + self.manager.parent.ids.content_drawer.ids.btn.values = [] + self.manager.parent.ids.sc3.children[1].ids.btn.values = [] + self.manager.parent.ids.content_drawer.ids.btn.values = addresses + self.manager.parent.ids.sc3.children[1].ids.btn.values = addresses + + @staticmethod + def add_validation(instance): + """Checking validation at address creation time""" + entered_label = str(instance.text.strip()) + lables = [BMConfigParser().get(obj, 'label') + for obj in BMConfigParser().addresses()] + if entered_label in lables: + instance.error = True + instance.helper_text = 'it is already exist you'\ + ' can try this Ex. ( {0}_1, {0}_2 )'.format( + entered_label) + elif entered_label: + instance.error = False + else: + instance.error = False + instance.helper_text = 'This field is required' + + def reset_address_label(self, n): + """Resetting address labels""" + if not self.ids.add_random_bx.children: + self.ids.add_random_bx.add_widget(RandomBoxlayout()) + + +class InfoLayout(BoxLayout, RectangularElevationBehavior): + """InfoLayout class for kivy Ui""" + + +class RandomBoxlayout(BoxLayout): + """RandomBoxlayout class for BoxLayout behaviour""" + + diff --git a/src/bitmessagekivy/baseclass/maildetail.py b/src/bitmessagekivy/baseclass/maildetail.py new file mode 100644 index 00000000..14eaf190 --- /dev/null +++ b/src/bitmessagekivy/baseclass/maildetail.py @@ -0,0 +1,236 @@ +from bitmessagekivy.get_platform import platform +from helper_sql import sqlExecute, sqlQuery + +from kivy.core.clipboard import Clipboard +from kivy.clock import Clock +from kivy.properties import ( + StringProperty, + NumericProperty +) +from kivymd.uix.button import MDFlatButton, MDIconButton +from kivymd.uix.dialog import MDDialog +from kivymd.uix.list import ( + OneLineListItem, + IRightBodyTouch +) +from kivymd.uix.label import MDLabel +from kivy.uix.screenmanager import Screen + +import state + +from bitmessagekivy.baseclass.common import ( + toast, avatarImageFirstLetter, ShowTimeHistoy +) +from bitmessagekivy.baseclass.popup import SenderDetailPopup +from bitmessagekivy.baseclass.trash import Trash + + +class OneLineListTitle(OneLineListItem): + """OneLineListTitle class for kivy Ui""" + __events__ = ('on_long_press', ) + long_press_time = NumericProperty(1) + + def on_state(self, instance, value): + """On state""" + if value == 'down': + lpt = self.long_press_time + self._clockev = Clock.schedule_once(self._do_long_press, lpt) + else: + self._clockev.cancel() + + def _do_long_press(self, dt): + """Do long press""" + self.dispatch('on_long_press') + + def on_long_press(self, *largs): + """On long press""" + self.copymessageTitle(self.text) + + def copymessageTitle(self, title_text): + """this method is for displaying dialog box""" + self.title_text = title_text + width = .8 if platform == 'android' else .55 + self.dialog_box = MDDialog( + text=title_text, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Copy", on_release=self.callback_for_copy_title + ), + MDFlatButton( + text="Cancel", on_release=self.callback_for_copy_title, + ), + ],) + self.dialog_box.open() + + def callback_for_copy_title(self, instance): + """Callback of alert box""" + if instance.text == 'Copy': + Clipboard.copy(self.title_text) + self.dialog_box.dismiss() + toast(instance.text) + + +class IconRightSampleWidget(IRightBodyTouch, MDIconButton): + """IconRightSampleWidget class for kivy Ui""" + + +class MailDetail(Screen): # pylint: disable=too-many-instance-attributes + """MailDetail Screen class for kivy Ui""" + + to_addr = StringProperty() + from_addr = StringProperty() + subject = StringProperty() + message = StringProperty() + status = StringProperty() + page_type = StringProperty() + time_tag = StringProperty() + avatarImg = StringProperty() + + def __init__(self, *args, **kwargs): + """Mail Details method""" + super(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' or state.detailPageType == 'draft': + data = sqlQuery( + "select toaddress, fromaddress, subject, message, status," + " ackdata, senttime from sent where ackdata = ?;", state.mail_id) + state.status = self + state.ackdata = data[0][5] + self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() + elif state.detailPageType == 'inbox': + data = sqlQuery( + "select toaddress, fromaddress, subject, message, received from inbox" + " where msgid = ?;", state.mail_id) + self.assign_mail_details(data) + state.kivyapp.set_mail_detail_header() + + def assign_mail_details(self, data): + """Assigning mail details""" + subject = data[0][2].decode() if isinstance(data[0][2], bytes) else data[0][2] + body = data[0][3].decode() if isinstance(data[0][2], bytes) else data[0][3] + self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' ' + self.from_addr = data[0][1] + + self.subject = subject.capitalize( + ) if subject.capitalize() else '(no subject)' + self.message = body + if len(data[0]) == 7: + self.status = data[0][4] + self.time_tag = ShowTimeHistoy(data[0][4]) if state.detailPageType == 'inbox' else ShowTimeHistoy(data[0][6]) + self.avatarImg = state.imageDir + '/avatar.png' if state.detailPageType == 'draft' else ( + state.imageDir + '/text_images/{0}.png'.format(avatarImageFirstLetter(self.subject.strip()))) + self.timeinseconds = data[0][4] if state.detailPageType == 'inbox' else data[0][6] + + def delete_mail(self): + """Method for mail delete""" + msg_count_objs = state.kivyapp.root.ids.content_drawer.ids + state.searcing_text = '' + self.children[0].children[0].active = True + if state.detailPageType == 'sent': + state.kivyapp.root.ids.sc4.ids.sent_search.ids.search_field.text = '' + sqlExecute( + "UPDATE sent SET folder = 'trash' WHERE" + " ackdata = ?;", state.mail_id) + msg_count_objs.send_cnt.ids.badge_txt.text = str(int(state.sent_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) + self.parent.screens[3].ids.ml.clear_widgets() + self.parent.screens[3].loadSent(state.association) + elif state.detailPageType == 'inbox': + state.kivyapp.root.ids.sc1.ids.inbox_search.ids.search_field.text = '' + sqlExecute( + "UPDATE inbox SET folder = 'trash' WHERE" + " msgid = ?;", state.mail_id) + msg_count_objs.inbox_cnt.ids.badge_txt.text = str( + int(state.inbox_count) - 1) + state.inbox_count = str(int(state.inbox_count) - 1) + self.parent.screens[0].ids.ml.clear_widgets() + self.parent.screens[0].loadMessagelist(state.association) + + elif state.detailPageType == 'draft': + sqlExecute("DELETE FROM sent WHERE ackdata = ?;", state.mail_id) + msg_count_objs.draft_cnt.ids.badge_txt.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()) + + if state.detailPageType != 'draft': + msg_count_objs.trash_cnt.ids.badge_txt.text = str( + int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.ids.badge_txt.text = str( + int(state.all_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) if int(state.all_count) else '0' + 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()) + Clock.schedule_once(self.callback_for_delete, 4) + + def callback_for_delete(self, dt=0): + """Delete method from allmails""" + if state.detailPageType: + self.children[0].children[0].active = False + state.kivyapp.set_common_header() + self.parent.current = 'allmails' \ + if state.is_allmail else state.detailPageType + state.detailPageType = '' + toast('Deleted') + + def inbox_reply(self): + """Reply inbox messages""" + state.in_composer = True + data = sqlQuery( + "select toaddress, fromaddress, subject, message, received from inbox where" + " msgid = ?;", state.mail_id) + composer_obj = self.parent.screens[2].children[1].ids + composer_obj.ti.text = data[0][0] + composer_obj.btn.text = data[0][0] + composer_obj.txt_input.text = data[0][1] + split_subject = data[0][2].split('Re:', 1) + composer_obj.subject.text = 'Re: ' + (split_subject[1] if len(split_subject) > 1 else split_subject[0]) + time_obj = datetime.fromtimestamp(int(data[0][4])) + time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") + # sender_name = BMConfigParser().get(data[0][1], 'label') + sender_name = data[0][1] + composer_obj.body.text = ( + '\n\n --------------On ' + time_tag + ', ' + sender_name + ' wrote:--------------\n' + data[0][3]) + composer_obj.body.focus = True + composer_obj.body.cursor = (0, 0) + state.kivyapp.root.ids.sc3.children[1].ids.rv.data = '' + self.parent.current = 'create' + state.kivyapp.set_navbar_for_composer() + + def write_msg(self, navApp): + """Write on draft mail""" + state.send_draft_mail = state.mail_id + data = sqlQuery( + "select toaddress, fromaddress, subject, message from sent where" + " ackdata = ?;", state.mail_id) + composer_ids = ( + self.parent.parent.ids.sc3.children[1].ids) + composer_ids.ti.text = data[0][1] + composer_ids.btn.text = data[0][1] + composer_ids.txt_input.text = data[0][0] + composer_ids.subject.text = data[0][2] if data[0][2] != '(no subject)' else '' + composer_ids.body.text = data[0][3] + self.parent.current = 'create' + navApp.set_navbar_for_composer() + + def detailedPopup(self): + """Detailed popup""" + obj = SenderDetailPopup() + obj.open() + arg = (self.to_addr, self.from_addr, self.timeinseconds) + obj.assignDetail(*arg) + + @staticmethod + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + toast(text_item) diff --git a/src/bitmessagekivy/baseclass/msg_composer.py b/src/bitmessagekivy/baseclass/msg_composer.py new file mode 100644 index 00000000..979adc70 --- /dev/null +++ b/src/bitmessagekivy/baseclass/msg_composer.py @@ -0,0 +1,307 @@ +import time + +from bitmessagekivy.get_platform import platform +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute, sqlQuery +from kivy.clock import Clock +from kivy.core.window import Window +from kivy.properties import ( + BooleanProperty, + ListProperty, + NumericProperty, + ObjectProperty, +) +from kivy.uix.behaviors import FocusBehavior +from kivy.uix.boxlayout import BoxLayout +from kivymd.uix.button import MDFlatButton +from kivymd.uix.dialog import MDDialog +from kivy.uix.label import Label +from kivy.uix.recycleview import RecycleView +from kivy.uix.recycleboxlayout import RecycleBoxLayout +from kivy.uix.recycleview.layout import LayoutSelectionBehavior +from kivy.uix.recycleview.views import RecycleDataViewBehavior +from kivy.uix.screenmanager import Screen +from kivy.uix.textinput import TextInput + +import state +import queues + +from addresses import decodeAddress +from bitmessagekivy.baseclass.common import ( + toast, showLimitedCnt +) + + +class Create(Screen): + """Creates Screen class for kivy Ui""" + + def __init__(self, **kwargs): + """Getting Labels and address from addressbook""" + super(Create, self).__init__(**kwargs) + Window.softinput_mode = "below_target" + widget_1 = DropDownWidget() + widget_1.ids.txt_input.word_list = [ + addr[1] for addr in sqlQuery( + "SELECT label, address from addressbook")] + widget_1.ids.txt_input.starting_no = 2 + self.add_widget(widget_1) + self.children[0].ids.id_scroll.bind(scroll_y=self.check_scroll_y) + + def check_scroll_y(self, instance, somethingelse): + """show data on scroll down""" + if self.children[1].ids.btn.is_open: + self.children[1].ids.btn.is_open = False + + +class RV(RecycleView): + """Recycling View class for kivy Ui""" + + def __init__(self, **kwargs): + """Recycling Method""" + super(RV, self).__init__(**kwargs) + + +class SelectableRecycleBoxLayout( + FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout +): + """Adds selection and focus behaviour to the view""" + + # pylint: disable = duplicate-bases + + +class DropDownWidget(BoxLayout): + """DropDownWidget class for kivy Ui""" + + # pylint: disable=too-many-statements + + txt_input = ObjectProperty() + rv = ObjectProperty() + + def send(self, navApp): + """Send message from one address to another""" + fromAddress = self.ids.ti.text.strip() + toAddress = self.ids.txt_input.text.strip() + subject = self.ids.subject.text.strip() + message = self.ids.body.text.strip() + encoding = 3 + print("message: ", self.ids.body.text) + sendMessageToPeople = True + if sendMessageToPeople: + if toAddress != "" and subject and message: + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress + ) + if status == "success": + navApp.root.ids.sc3.children[0].active = True + if state.detailPageType == "draft" and state.send_draft_mail: + sqlExecute( + "UPDATE sent SET toaddress = ?" + ", fromaddress = ? , subject = ?" + ", message = ?, folder = 'sent'" + ", senttime = ?, lastactiontime = ?" + " WHERE ackdata = ?;", + toAddress, + fromAddress, + subject, + message, + int(time.time()), + int(time.time()), + 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().safeGetInt( + 'bitmessagesettings', 'ttl')) + state.check_sent_acc = fromAddress + # state.msg_counter_objs = self.parent.parent.parent.parent\ + # .parent.parent.children[2].children[0].ids + if state.detailPageType == 'draft' \ + and state.send_draft_mail: + state.draft_count = str(int(state.draft_count) - 1) + # state.msg_counter_objs.draft_cnt.badge_text = ( + # state.draft_count) + state.detailPageType = '' + state.send_draft_mail = None + self.parent.parent.parent.ids.sc4.update_sent_messagelist() + allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt + allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(state.all_count) + 1) + state.all_count = str(int(state.all_count) + 1) + Clock.schedule_once(self.callback_for_msgsend, 3) + queues.workerQueue.put(('sendmessage', toAddress)) + print("sqlExecute successfully #######################") + state.in_composer = True + return + else: + msg = 'Enter a valid recipients address' + elif not toAddress: + msg = 'Please fill the form completely' + else: + msg = 'Please fill the form completely' + self.address_error_message(msg) + + @staticmethod + def callback_for_msgsend(dt=0): + """Callback method for messagesend""" + state.kivyapp.root.ids.sc3.children[0].active = False + state.in_sent_method = True + state.kivyapp.back_press() + toast("sent") + + def address_error_message(self, msg): + """Generates error message""" + width = .8 if platform == 'android' else .55 + dialog_box = MDDialog( + text=msg, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ],) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + dialog_box.dismiss() + toast(text_item) + + def reset_composer(self): + """Method will reset composer""" + self.ids.ti.text = "" + self.ids.btn.text = "Select" + self.ids.txt_input.text = "" + self.ids.subject.text = "" + self.ids.body.text = "" + toast("Reset message") + + def auto_fill_fromaddr(self): + """Fill the text automatically From Address""" + self.ids.ti.text = self.ids.btn.text + self.ids.ti.focus = True + + def is_camara_attached(self): + self.parent.parent.parent.ids.sc23.check_camera() + is_available = self.parent.parent.parent.ids.sc23.camera_avaialbe + return is_available + + def camera_alert(self): + width = .8 if platform == 'android' else .55 + altet_txt = 'Currently this feature is not avaialbe!'if platform == 'android' else 'Camera is not available!' + dialog_box = MDDialog( + text=altet_txt, + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ], + ) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + dialog_box.dismiss() + toast(text_item) + + +class MyTextInput(TextInput): + """MyTextInput class for kivy Ui""" + + txt_input = ObjectProperty() + flt_list = ObjectProperty() + word_list = ListProperty() + starting_no = NumericProperty(3) + suggestion_text = '' + + def __init__(self, **kwargs): + """Getting Text Input.""" + super(MyTextInput, self).__init__(**kwargs) + self.__lineBreak__ = 0 + + def on_text(self, instance, value): + """Find all the occurrence of the word""" + self.parent.parent.parent.parent.parent.ids.rv.data = [] + matches = [self.word_list[i] for i in range( + len(self.word_list)) if self.word_list[ + i][:self.starting_no] == value[:self.starting_no]] + display_data = [] + for i in matches: + display_data.append({'text': i}) + self.parent.parent.parent.parent.parent.ids.rv.data = display_data + if len(matches) <= 10: + self.parent.height = (250 + (len(matches) * 20)) + else: + self.parent.height = 400 + + def keyboard_on_key_down(self, window, keycode, text, modifiers): + """Keyboard on key Down""" + if self.suggestion_text and keycode[1] == 'tab': + self.insert_text(self.suggestion_text + ' ') + return True + return super(MyTextInput, self).keyboard_on_key_down( + window, keycode, text, modifiers) + + +class SelectableLabel(RecycleDataViewBehavior, Label): + """Add selection support to the Label""" + + index = None + selected = BooleanProperty(False) + selectable = BooleanProperty(True) + + def refresh_view_attrs(self, rv, index, data): + """Catch and handle the view changes""" + self.index = index + return super(SelectableLabel, self).refresh_view_attrs(rv, index, data) + + def on_touch_down(self, touch): # pylint: disable=inconsistent-return-statements + """Add selection on touch down""" + if super(SelectableLabel, self).on_touch_down(touch): + return True + if self.collide_point(*touch.pos) and self.selectable: + return self.parent.select_with_touch(self.index, touch) + + def apply_selection(self, rv, index, is_selected): + """Respond to the selection of items in the view""" + self.selected = is_selected + if is_selected: + 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"] + ) diff --git a/src/bitmessagekivy/baseclass/myaddress.py b/src/bitmessagekivy/baseclass/myaddress.py new file mode 100644 index 00000000..65489390 --- /dev/null +++ b/src/bitmessagekivy/baseclass/myaddress.py @@ -0,0 +1,249 @@ +from bitmessagekivy.get_platform import platform +from functools import partial +from bmconfigparser import BMConfigParser +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.list import ( + IRightBodyTouch, + TwoLineAvatarIconListItem, +) +from kivymd.uix.selectioncontrol import MDSwitch +from kivy.uix.screenmanager import Screen + +import state + +from bitmessagekivy.baseclass.common import ( + avatarImageFirstLetter, AvatarSampleWidget,ThemeClsColor +) +from bitmessagekivy.baseclass.popup import MyaddDetailPopup + + +class ToggleBtn(IRightBodyTouch, MDSwitch): + """ToggleBtn class for kivy Ui""" + + +class CustomTwoLineAvatarIconListItem(TwoLineAvatarIconListItem): + """CustomTwoLineAvatarIconListItem class for kivy Ui""" + + +class BadgeText(IRightBodyTouch, MDLabel): + """BadgeText class for kivy Ui""" + + +class MyAddress(Screen): + """MyAddress screen class for kivy Ui""" + + address_label = StringProperty() + text_address = StringProperty() + addresses_list = ListProperty() + has_refreshed = True + is_add_created = False + + def __init__(self, *args, **kwargs): + """Clock schdule for method Myaddress accounts""" + super(MyAddress, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock schdule for method Myaddress accounts""" + # pylint: disable=unnecessary-lambda, deprecated-lambda + # self.addresses_list = state.kivyapp.variable_1 + self.addresses_list = BMConfigParser().addresses() + if state.searcing_text: + self.ids.refresh_layout.scroll_y = 1.0 + filtered_list = [ + x for x in BMConfigParser().addresses() + if self.filter_address(x) + ] + self.addresses_list = filtered_list + self.addresses_list = [obj for obj in reversed(self.addresses_list)] + self.ids.tag_label.text = '' + if self.addresses_list: + self.ids.tag_label.text = 'My Addresses' + self.has_refreshed = True + self.set_mdList(0, 15) + self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) + else: + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No address found!" if state.searcing_text + else "yet no address is created by user!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + if not state.searcing_text and not self.is_add_created: + try: + self.manager.current = 'login' + except Exception: + pass + + def set_mdList(self, first_index, last_index): + """Creating the mdlist""" + data = [] + for address in self.addresses_list[first_index:last_index]: + data.append({ + 'text': BMConfigParser().get(address, 'label'), + 'secondary_text': address}) + for item in data: + is_enable = BMConfigParser().get(item['secondary_text'], 'enabled') + meny = CustomTwoLineAvatarIconListItem( + text=item['text'], secondary_text=item['secondary_text'], + theme_text_color='Custom' if is_enable == 'true' else 'Primary', + text_color=ThemeClsColor,) + meny._txt_right_pad = dp(70) + try: + meny.canvas.children[6].rgba = [0, 0, 0, 0] if is_enable == 'true' else [0.5, 0.5, 0.5, 0.5] + except Exception: + try: + meny.canvas.children[9].rgba = [0, 0, 0, 0] if is_enable == 'true' else [0.5, 0.5, 0.5, 0.5] + except Exception as e: + print('Exception: ', e) + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(item['text'].strip())))) + meny.bind(on_press=partial( + self.myadd_detail, item['secondary_text'], item['text'])) + if state.association == item['secondary_text'] and is_enable == 'true': + badge_obj = BadgeText( + size_hint=(None, None), + size=[90 if platform == 'android' else 50, 60], + text='Active', halign='center', + font_style='Body1', theme_text_color='Custom', + text_color=ThemeClsColor + ) + badge_obj.font_size = '13sp' + meny.add_widget(badge_obj) + else: + meny.add_widget(ToggleBtn(active=True if is_enable == 'true' else False)) + self.ids.ml.add_widget(meny) + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll down""" + if self.ids.refresh_layout.scroll_y <= -0.0 and self.has_refreshed: + self.ids.refresh_layout.scroll_y = 0.06 + my_addresses = len(self.ids.ml.children) + if my_addresses != len(self.addresses_list): + self.update_addressBook_on_scroll(my_addresses) + self.has_refreshed = ( + True if my_addresses != len(self.addresses_list) else False + ) + + def update_addressBook_on_scroll(self, my_addresses): + """Loads more data on scroll down""" + self.set_mdList(my_addresses, my_addresses + 20) + + # @staticmethod + def myadd_detail(self, fromaddress, label, *args): + """Load myaddresses details""" + if BMConfigParser().get(fromaddress, 'enabled') == 'true': + obj = MyaddDetailPopup() + self.address_label = obj.address_label = label + self.text_address = obj.address = fromaddress + width = .9 if platform == 'android' else .6 + self.myadddetail_popup = MDDialog( + type="custom", + size_hint=(width, .25), + content_cls=obj, + ) + self.myadddetail_popup.set_normal_height() + self.myadddetail_popup.auto_dismiss = False + self.myadddetail_popup.open() + # p.set_address(fromaddress, label) + else: + width = .8 if platform == 'android' else .55 + dialog_box = MDDialog( + text='Address is not currently active. Please click on Toggle button to active it.', + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Ok", on_release=lambda x: callback_for_menu_items("Ok") + ), + ], + ) + dialog_box.open() + + def callback_for_menu_items(text_item, *arg): + """Callback of alert box""" + dialog_box.dismiss() + toast(text_item) + + # @staticmethod + # def callback_for_menu_items(text_item, *arg): + # """Callback of alert box""" + # toast(text_item) + + def refresh_callback(self, *args): + """Method updates the state of application, + While the spinner remains on the screen""" + def refresh_callback(interval): + """Method used for loading the myaddress screen data""" + state.searcing_text = '' + # state.kivyapp.root.ids.sc10.children[2].active = False + self.ids.search_bar.ids.search_field.text = '' + self.has_refreshed = True + self.ids.ml.clear_widgets() + self.init_ui() + self.ids.refresh_layout.refresh_done() + self.tick = 0 + Clock.schedule_once(self.address_permision_callback, 0) + Clock.schedule_once(refresh_callback, 1) + + @staticmethod + def filter_address(address): + """Method will filter the my address list data""" + if [ + x for x in [ + BMConfigParser().get(address, 'label').lower(), + address.lower() + ] + if (state.searcing_text).lower() in x + ]: + return True + return False + + def disableAddress(self, address, instance): + """This method is use for disabling address""" + BMConfigParser().set(str(address), 'enabled', 'false') + BMConfigParser().save() + instance.parent.parent.theme_text_color = 'Primary' + try: + instance.parent.parent.canvas.children[6].rgba = [0.5, 0.5, 0.5, 0.5] + except Exception: + instance.parent.parent.canvas.children[9].rgba = [0.5, 0.5, 0.5, 0.5] + toast('Address disabled') + Clock.schedule_once(self.address_permision_callback, 0) + + def enableAddress(self, address, instance): + """This method is use for enabling address""" + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().save() + instance.parent.parent.theme_text_color = 'Custom' + try: + instance.parent.parent.canvas.children[6].rgba = [0, 0, 0, 0] + except Exception: + instance.parent.parent.canvas.children[9].rgba = [0, 0, 0, 0] + toast('Address Enabled') + Clock.schedule_once(self.address_permision_callback, 0) + + def address_permision_callback(self, dt=0): + """callback for enable or disable addresses""" + addresses = [addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true'] + self.parent.parent.ids.content_drawer.ids.btn.values = addresses + self.parent.parent.ids.sc3.children[1].ids.btn.values = addresses + + def toggleAction(self, instance): + """This method is used for enable or disable address""" + addr = instance.parent.parent.secondary_text + if instance.active: + self.enableAddress(addr, instance) + else: + self.disableAddress(addr, instance) diff --git a/src/bitmessagekivy/baseclass/network.py b/src/bitmessagekivy/baseclass/network.py new file mode 100644 index 00000000..89e18215 --- /dev/null +++ b/src/bitmessagekivy/baseclass/network.py @@ -0,0 +1,41 @@ +import state + +from kivy.clock import Clock +from kivy.properties import StringProperty +from kivy.uix.screenmanager import Screen +from bitmessagekivy.baseclass.common import ThemeClsColor + + +class NetworkStat(Screen): + """NetworkStat class for kivy Ui""" + + text_variable_1 = StringProperty( + '{0}::{1}'.format('Total Connections', '0')) + text_variable_2 = StringProperty( + 'Processed {0} per-to-per messages'.format('0')) + text_variable_3 = StringProperty( + 'Processed {0} brodcast messages'.format('0')) + text_variable_4 = StringProperty( + 'Processed {0} public keys'.format('0')) + text_variable_5 = StringProperty( + 'Processed {0} object to be synced'.format('0')) + + def __init__(self, *args, **kwargs): + """Init method for network stat""" + super(NetworkStat, self).__init__(*args, **kwargs) + Clock.schedule_interval(self.init_ui, 1) + + def init_ui(self, dt=0): + """Clock Schdule for method networkstat screen""" + import network.stats + 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(state.numberOfMessagesProcessed)) + self.text_variable_3 = 'Processed {0} brodcast messages'.format( + str(state.numberOfBroadcastsProcessed)) + self.text_variable_4 = 'Processed {0} public keys'.format( + str(state.numberOfPubkeysProcessed)) + self.text_variable_5 = '{0} object to be synced'.format( + len(objectracker.missingObjects)) \ No newline at end of file diff --git a/src/bitmessagekivy/baseclass/payment.py b/src/bitmessagekivy/baseclass/payment.py new file mode 100644 index 00000000..fa7bb817 --- /dev/null +++ b/src/bitmessagekivy/baseclass/payment.py @@ -0,0 +1,67 @@ +from bmconfigparser import BMConfigParser + +from kivy.uix.boxlayout import BoxLayout +from kivymd.uix.behaviors.elevation import RectangularElevationBehavior +from kivy.uix.screenmanager import Screen +from kivymd.uix.label import MDLabel +from kivymd.uix.list import ( + IRightBodyTouch, + OneLineAvatarIconListItem +) + +import state + + +class Payment(Screen): + """Payment Screen class for kivy Ui""" + + def get_free_credits(self, instance): + """Get the available credits""" + # pylint: disable=no-self-use + state.availabe_credit = instance.parent.children[1].text + existing_credits = state.kivyapp.root.ids.sc18.ids.cred.text + if float(existing_credits.split()[1]) > 0: + 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.cred.text = '{0}'.format( + state.availabe_credit) + + def create_hidden_payment_address(self, instance): + """This is basically used for creating hidden address used in payment for purchasing credits""" + if BMConfigParser().paymentaddress(): + toast('hidden payment address already exist for buying subscription...') + else: + streamNumberForAddress = 1 + eighteenByteRipe = False + nonceTrialsPerByte = 1000 + payloadLengthExtraBytes = 1000 + queues.addressGeneratorQueue.put(( + 'createPaymentAddress', 4, streamNumberForAddress, '', 1, + "", eighteenByteRipe, nonceTrialsPerByte, + payloadLengthExtraBytes)) + toast('hidden payment address Creating for buying subscription....') + + +class Category(BoxLayout, RectangularElevationBehavior): + """Category class for kivy Ui""" + elevation_normal = .01 + + +class ProductLayout(BoxLayout, RectangularElevationBehavior): + """ProductLayout class for kivy Ui""" + elevation_normal = .01 + + +class PaymentMethodLayout(BoxLayout): + """PaymentMethodLayout class for kivy Ui""" + + +class ListItemWithLabel(OneLineAvatarIconListItem): + """ListItemWithLabel class for kivy Ui""" + + +class RightLabel(IRightBodyTouch, MDLabel): + """RightLabel class for kivy Ui""" diff --git a/src/bitmessagekivy/baseclass/popup.py b/src/bitmessagekivy/baseclass/popup.py new file mode 100644 index 00000000..5668c29c --- /dev/null +++ b/src/bitmessagekivy/baseclass/popup.py @@ -0,0 +1,232 @@ +from bitmessagekivy.get_platform import platform +from bitmessagekivy import kivy_helper_search + +from kivy.clock import Clock +from kivy.properties import StringProperty + +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.popup import Popup + +import state +from addresses import decodeAddress +from datetime import datetime + +from bitmessagekivy.baseclass.common import toast + + +class LoadingPopup(Popup): + """LoadingPopup class for kivy Ui""" + + def __init__(self, **kwargs): + super(LoadingPopup, self).__init__(**kwargs) + # call dismiss_popup in 2 seconds + Clock.schedule_once(self.dismiss_popup, 0.5) + + def dismiss_popup(self, dt): + """Dismiss popups""" + self.dismiss() + + +class GrashofPopup(BoxLayout): + """GrashofPopup class for kivy Ui""" + + valid = False + + def __init__(self, **kwargs): + """Grash of pop screen settings""" + super(GrashofPopup, self).__init__(**kwargs) + + def checkAddress_valid(self, instance): + """Checking address is valid or not""" + my_addresses = ( + state.kivyapp.root.ids.content_drawer.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.' + elif entered_text: + text = self.addressChanged(entered_text) + + if entered_text in my_addresses or entered_text in add_book: + self.ids.address.error = True + self.ids.address.helper_text = text + elif entered_text and self.valid: + self.ids.address.error = False + elif entered_text: + self.ids.address.error = True + self.ids.address.helper_text = text + else: + self.ids.address.error = False + self.ids.address.helper_text = 'This field is required' + + def checkLabel_valid(self, instance): + """Checking address label is unique or not""" + entered_label = instance.text.strip() + addr_labels = [labels[0] for labels in kivy_helper_search.search_sql( + folder="addressbook")] + if entered_label in addr_labels: + self.ids.label.error = True + self.ids.label.helper_text = 'label name already exists.' + elif entered_label: + self.ids.label.error = False + else: + self.ids.label.error = False + self.ids.label.helper_text = 'This field is required' + + def _onSuccess(self, addressVersion, streamNumber, ripe): + pass + + def addressChanged(self, addr): + """Address validation callback, performs validation and gives feedback""" + status, addressVersion, streamNumber, ripe = decodeAddress( + str(addr)) + self.valid = status == 'success' + if self.valid: + text = "Address is valid." + self._onSuccess(addressVersion, streamNumber, ripe) + elif status == 'missingbm': + text = "The address should start with ''BM-''" + elif status == 'checksumfailed': + text = ( + "The address is not typed or copied correctly" + # " (the checksum failed)." + ) + elif status == 'versiontoohigh': + text = ( + "The version number of this address is higher than this" + " software can support. Please upgrade Bitmessage.") + elif status == 'invalidcharacters': + text = "The address contains invalid characters." + elif status == 'ripetooshort': + text = "Some data encoded in the address is too short." + elif status == 'ripetoolong': + text = "Some data encoded in the address is too long." + elif status == 'varintmalformed': + text = "Some data encoded in the address is malformed." + return text + + +class AddbookDetailPopup(BoxLayout): + """AddbookDetailPopup class for kivy Ui""" + + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + """Set screen of address detail page""" + super(AddbookDetailPopup, self).__init__(**kwargs) + + def checkLabel_valid(self, instance): + """Checking address label is unique of not""" + entered_label = str(instance.text.strip()) + address_list = kivy_helper_search.search_sql(folder="addressbook") + addr_labels = [labels[0] for labels in address_list] + add_dict = dict(address_list) + if self.address and entered_label in addr_labels \ + and self.address != add_dict[entered_label]: + self.ids.add_label.error = True + self.ids.add_label.helper_text = 'label name already exists.' + elif entered_label: + self.ids.add_label.error = False + else: + self.ids.add_label.error = False + self.ids.add_label.helper_text = 'This field is required' + + +class MyaddDetailPopup(BoxLayout): + """MyaddDetailPopup class for kivy Ui""" + + address_label = StringProperty() + address = StringProperty() + + def __init__(self, **kwargs): + """My Address Details screen setting""" + super(MyaddDetailPopup, self).__init__(**kwargs) + + def send_message_from(self): + """Method used to fill from address of composer autofield""" + state.kivyapp.set_navbar_for_composer() + window_obj = state.kivyapp.root.ids + window_obj.sc3.children[1].ids.ti.text = self.address + window_obj.sc3.children[1].ids.btn.text = self.address + window_obj.sc3.children[1].ids.txt_input.text = '' + window_obj.sc3.children[1].ids.subject.text = '' + window_obj.sc3.children[1].ids.body.text = '' + window_obj.scr_mngr.current = 'create' + self.parent.parent.parent.dismiss() + + # @staticmethod + def close_pop(self): + """Pop is Canceled""" + self.parent.parent.parent.dismiss() + toast('Canceled') + + +class AppClosingPopup(Popup): + """AppClosingPopup class for kivy Ui""" + + def __init__(self, **kwargs): + super(AppClosingPopup, self).__init__(**kwargs) + + def closingAction(self, text): + """Action on closing window""" + if text == 'Yes': + print("*******************EXITING FROM APPLICATION*******************") + import shutdown + shutdown.doCleanShutdown() + else: + self.dismiss() + toast(text) + + +class SenderDetailPopup(Popup): + """SenderDetailPopup class for kivy Ui""" + + to_addr = StringProperty() + from_addr = StringProperty() + time_tag = StringProperty() + + def __init__(self, **kwargs): + """this metthod initialized the send message detial popup""" + super(SenderDetailPopup, self).__init__(**kwargs) + + def assignDetail(self, to_addr, from_addr, timeinseconds): + """Detailes assigned""" + self.to_addr = to_addr + self.from_addr = from_addr + time_obj = datetime.fromtimestamp(int(timeinseconds)) + self.time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") + device_type = 2 if platform == 'android' else 1.5 + pop_height = 1.2 * device_type * (self.ids.sd_label.height + self.ids.dismiss_btn.height) + if len(to_addr) > 3: + self.height = 0 + self.height = pop_height + self.ids.to_addId.size_hint_y = None + self.ids.to_addId.height = 50 + self.ids.to_addtitle.add_widget(ToAddressTitle()) + frmaddbox = ToAddrBoxlayout() + frmaddbox.set_toAddress(to_addr) + self.ids.to_addId.add_widget(frmaddbox) + else: + self.ids.space_1.height = dp(0) + self.ids.space_2.height = dp(0) + self.ids.myadd_popup_box.spacing = dp(8 if platform == 'android' else 3) + self.height = 0 + self.height = pop_height / 1.2 + + +class ToAddrBoxlayout(BoxLayout): + """ToAddrBoxlayout class for kivy Ui""" + to_addr = StringProperty() + + def set_toAddress(self, to_addr): + """This method is use to set to address""" + self.to_addr = to_addr + + +class ToAddressTitle(BoxLayout): + """ToAddressTitle class for BoxLayout behaviour""" + diff --git a/src/bitmessagekivy/baseclass/qrcode.py b/src/bitmessagekivy/baseclass/qrcode.py new file mode 100644 index 00000000..fcf97328 --- /dev/null +++ b/src/bitmessagekivy/baseclass/qrcode.py @@ -0,0 +1,23 @@ +import state +from bitmessagekivy.baseclass.common import toast +from kivy.uix.screenmanager import Screen +from kivy.properties import StringProperty + + +class ShowQRCode(Screen): + """ShowQRCode Screen class for kivy Ui""" + address = StringProperty() + + def qrdisplay(self, instasnce, address): + """Method used for showing QR Code""" + self.ids.qr.clear_widgets() + state.kivyapp.set_toolbar_for_QrCode() + try: + from kivy.garden.qrcode import QRCodeWidget + except Exception: + from kivy_garden.qrcode import QRCodeWidget + self.address = address + self.ids.qr.add_widget(QRCodeWidget(data=address)) + self.ids.qr.children[0].show_border = False + instasnce.parent.parent.parent.dismiss() + toast('Show QR code') \ No newline at end of file diff --git a/src/bitmessagekivy/baseclass/scan_screen.py b/src/bitmessagekivy/baseclass/scan_screen.py new file mode 100644 index 00000000..34aface6 --- /dev/null +++ b/src/bitmessagekivy/baseclass/scan_screen.py @@ -0,0 +1,113 @@ +from bitmessagekivy.get_platform import platform +import os + +from kivy.clock import Clock +from kivy.lang import Builder +from kivy.properties import ( + BooleanProperty, + ObjectProperty, + StringProperty +) + +from kivy.uix.screenmanager import Screen + + +# if platform != "android": +# from kivy.config import Config +# from kivy_garden.zbarcam import ZBarCam +# from pyzbar.pyzbar import ZBarSymbol + +# Config.set("input", "mouse", "mouse, multitouch_on_demand") +# elif platform == "android": +# from jnius import autoclass, cast +# from android.runnable import run_on_ui_thread +# from android import python_act as PythonActivity + +# Toast = autoclass("android.widget.Toast") +# String = autoclass("java.lang.String") +# CharSequence = autoclass("java.lang.CharSequence") +# context = PythonActivity.mActivity + +# @run_on_ui_thread +# def show_toast(text, length): +# """Its showing toast on screen""" +# t = Toast.makeText(context, text, length) +# t.show() + + +class ScanScreen(Screen): + camera_avaialbe = BooleanProperty(False) + previous_open_screen = StringProperty() + pop_up_instance = ObjectProperty() + + def __init__(self, *args, **kwargs): + """Getting AddressBook Details""" + super(ScanScreen, self).__init__(*args, **kwargs) + self.check_camera() + + def check_camera(self): + """This method is used for checking camera avaibility""" + if platform != "android": + import cv2 + cap = cv2.VideoCapture(0) + while(cap.isOpened()): + print('Camera is available!') + self.camera_avaialbe = True + break + else: + print("Camera is not available!") + self.camera_avaialbe = False + + def get_screen(self, screen_name, instance=None): + """This method is used for getting previous screen name""" + self.previous_open_screen = screen_name + if screen_name != 'composer': + self.pop_up_instance = instance + + def on_pre_enter(self): + """ + on_pre_enter works little better on android + It affects screen transition on linux + """ + if not self.children: + tmp = Builder.load_file( + os.path.join(os.path.dirname(__file__), "kv/{}.kv").format("scanner") + ) + self.add_widget(tmp) + if platform == "android": + Clock.schedule_once(self.start_camera, 0) + + def on_enter(self): + """ + on_enter works better on linux + It creates a black screen on android until camera gets loaded + """ + # print(self.children) + if platform != "android": + # pass + Clock.schedule_once(self.start_camera, 0) + + def on_leave(self): + # pass + Clock.schedule_once(self.stop_camera, 0) + + def start_camera(self, *args): + """Its used for starting camera for scanning qrcode""" + self.xcam = self.children[0].ids.zbarcam.ids.xcamera + if platform == "android": + self.xcam.play = True + + else: + Clock.schedule_once(self.open_cam, 0) + + def stop_camera(self, *args): + """Its used for stop the camera""" + self.xcam.play = False + if platform != "android": + self.xcam._camera._device.release() + + def open_cam(self, *args): + """It will open up the camera""" + if not self.xcam._camera._device.isOpened(): + self.xcam._camera._device.open(self.xcam._camera._index) + self.xcam.play = True \ No newline at end of file diff --git a/src/bitmessagekivy/baseclass/sent.py b/src/bitmessagekivy/baseclass/sent.py new file mode 100644 index 00000000..ec5ddf0d --- /dev/null +++ b/src/bitmessagekivy/baseclass/sent.py @@ -0,0 +1,247 @@ +from bitmessagekivy.get_platform import platform +# from bitmessagekivy import identiconGeneration +from bitmessagekivy import kivy_helper_search +from bmconfigparser import BMConfigParser +from functools import partial +from helper_sql import sqlExecute +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import StringProperty, ListProperty +from kivy.uix.button import Button +from kivy.uix.carousel import Carousel +from kivy.uix.screenmanager import Screen +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem + +import state + +from bitmessagekivy.baseclass.common import ( + showLimitedCnt, initailize_detail_page, ThemeClsColor, + avatarImageFirstLetter, AddTimeWidget, AvatarSampleWidget, + toast +) + + +class Sent(Screen): + """Sent Screen class for kivy Ui""" + + queryreturn = ListProperty() + has_refreshed = True + account = StringProperty() + + def __init__(self, *args, **kwargs): + """Association with the screen""" + super(Sent, self).__init__(*args, **kwargs) + if 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 sent accounts""" + self.loadSent() + print(dt) + + def loadSent(self, where="", what=""): + """Load Sent list for Sent messages""" + self.account = state.association + if state.searcing_text: + self.ids.scroll_y.scroll_y = 1.0 + where = ['subject', 'message'] + what = state.searcing_text + xAddress = 'fromaddress' + data = [] + self.ids.tag_label.text = '' + self.sentDataQuery(xAddress, where, what) + if self.queryreturn: + self.ids.tag_label.text = 'Sent' + self.set_sentCount(state.sent_count) + for mail in self.queryreturn: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': (mail[2][:50] + '........' if len( + mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( + '\t', '').replace(' ', ''), + 'ackdata': mail[5], 'senttime': mail[6]},) + self.set_mdlist(data, 0) + self.has_refreshed = True + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_sentCount('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="No message found!" if state.searcing_text + else "yet no message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def sentDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): + """This method is used to retrieving data from sent table""" + self.queryreturn = kivy_helper_search.search_sql( + xAddress, + self.account, + 'sent', + where, + what, + False, + start_indx, + end_indx) + + def set_mdlist(self, data, set_index=0): + """This method is used to create the mdList""" + total_sent_msg = len(self.ids.ml.children) + for item in data: + meny = TwoLineAvatarIconListItem( + text=item['text'], secondary_text=item['secondary_text'], + theme_text_color='Custom', + text_color=ThemeClsColor) + meny._txt_right_pad = dp(70) + meny.add_widget(AvatarSampleWidget( + source=state.imageDir + '/text_images/{}.png'.format( + avatarImageFirstLetter(item['secondary_text'].strip())))) + meny.bind(on_press=partial(self.sent_detail, item['ackdata'])) + meny.add_widget(AddTimeWidget(item['senttime'])) + carousel = Carousel(direction='right') + carousel.height = meny.height + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial(self.delete, item['ackdata'])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + # ach_btn = Button(text='Achieve') + # ach_btn.background_color = (0, 1, 0, 1) + # ach_btn.bind(on_press=partial(self.archive, item['ackdata'])) + # carousel.add_widget(ach_btn) + carousel.index = 1 + self.ids.ml.add_widget(carousel, index=set_index) + updated_msgs = len(self.ids.ml.children) + self.has_refreshed = True if total_sent_msg != updated_msgs else False + + def update_sent_messagelist(self): + """This method is used to update screen when new mail is sent""" + self.account = state.association + if len(self.ids.ml.children) < 3: + self.ids.ml.clear_widgets() + self.loadSent() + if state.association == state.check_sent_acc: + total_sent = int(state.sent_count) + 1 + state.sent_count = str(int(state.sent_count) + 1) + self.set_sentCount(total_sent) + else: + total_sent = int(state.sent_count) + else: + data = [] + self.sentDataQuery('fromaddress', '', '', 0, 1) + if state.association == state.check_sent_acc: + total_sent = int(state.sent_count) + 1 + state.sent_count = str(int(state.sent_count) + 1) + self.set_sentCount(total_sent) + else: + total_sent = int(state.sent_count) + for mail in self.queryreturn: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': (mail[2][:50] + '........' if len( + mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( + '\t', '').replace(' ', ''), + 'ackdata': mail[5], 'senttime': mail[6]}) + self.set_mdlist(data, total_sent - 1) + if state.msg_counter_objs and state.association == ( + state.check_sent_acc): + state.all_count = str(int(state.all_count) + 1) + state.msg_counter_objs.allmail_cnt.badge_text = state.all_count + state.check_sent_acc = None + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll down""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + total_sent_msg = len(self.ids.ml.children) + self.update_sent_screen_on_scroll(total_sent_msg) + + def update_sent_screen_on_scroll(self, total_sent_msg, where="", what=""): + """This method is used to load more data on scroll down""" + if state.searcing_text: + where = ['subject', 'message'] + what = state.searcing_text + self.sentDataQuery('fromaddress', where, what, total_sent_msg, 5) + data = [] + for mail in self.queryreturn: + data.append({ + 'text': mail[1].strip(), + 'secondary_text': mail[2][:50] + '........' if len( + mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace( + '\n', ''))[0:50] + '........', + 'ackdata': mail[5], 'senttime': mail[6]}) + self.set_mdlist(data, 0) + + @staticmethod + def set_sentCount(total_sent): + """Set the total no. of sent message count""" + src_mng_obj = state.kivyapp.root.ids.content_drawer.ids.send_cnt + state.kivyapp.root.ids.content_drawer.ids.send_cnt.ids.badge_txt.text + if state.association: + src_mng_obj.ids.badge_txt.text = showLimitedCnt(int(total_sent)) + else: + src_mng_obj.ids.badge_txt.text = '0' + + def sent_detail(self, ackdata, *args): + """Load sent mail details""" + state.detailPageType = 'sent' + state.mail_id = ackdata + 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' + initailize_detail_page(src_mng_obj) + + def delete(self, data_index, instance, *args): + """Delete sent mail from sent mail listing""" + msg_count_objs = self.parent.parent.ids.content_drawer.ids + if int(state.sent_count) > 0: + msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(state.sent_count) - 1) + msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(state.trash_count) + 1) + msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count) - 1) + state.sent_count = str(int(state.sent_count) - 1) + state.trash_count = str(int(state.trash_count) + 1) + state.all_count = str(int(state.all_count) - 1) + if int(state.sent_count) <= 0: + self.ids.tag_label.text = '' + sqlExecute( + "UPDATE sent SET folder = 'trash'" + " WHERE ackdata = ?;", data_index) + self.ids.ml.remove_widget(instance.parent.parent) + 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 ackdata = ?;", data_index) + self.ids.ml.remove_widget(instance.parent.parent) + self.update_trash() + + def update_trash(self): + """Update trash screen mails which is deleted from inbox""" + try: + self.parent.screens[4].clear_widgets() + self.parent.screens[4].add_widget(Trash()) + 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()) diff --git a/src/bitmessagekivy/baseclass/settings.py b/src/bitmessagekivy/baseclass/settings.py new file mode 100644 index 00000000..fa01d472 --- /dev/null +++ b/src/bitmessagekivy/baseclass/settings.py @@ -0,0 +1,91 @@ +from kivy.uix.screenmanager import Screen + + +class Setting(Screen): + """Setting Screen for kivy Ui""" + exp_text = "By default, if you send a message to someone and he is offline for more than two days, Bitmessage will\ + send the message again after an additional two days. This will be continued with exponential backoff\ + forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them.\ + Here you may change that behavior by having Bitmessage give up after a certain number of days \ + or months." + + # languages = { + # 'ar': 'Arabic', + # 'cs': 'Czech', + # 'da': 'Danish', + # 'de': 'German', + # 'en': 'English', + # 'eo': 'Esperanto', + # 'fr': 'French', + # 'it': 'Italian', + # 'ja': 'Japanese', + # 'nl': 'Dutch', + # 'no': 'Norwegian', + # 'pl': 'Polish', + # 'pt': 'Portuguese', + # 'ru': 'Russian', + # 'sk': 'Slovak', + # 'zh': 'Chinese', + # } + # newlocale = None + + # def __init__(self, *args, **kwargs): + # """Trash method, delete sent message and add in Trash""" + # super(Setting, self).__init__(*args, **kwargs) + # if self.newlocale is None: + # self.newlocale = l10n.getTranslationLanguage() + # lang = locale.normalize(l10n.getTranslationLanguage()) + # langs = [ + # lang.split(".")[0] + "." + l10n.encoding, + # lang.split(".")[0] + "." + 'UTF-8', + # lang + # ] + # if 'win32' in platform or 'win64' in platform: + # langs = [l10n.getWindowsLocale(lang)] + # for lang in langs: + # try: + # l10n.setlocale(locale.LC_ALL, lang) + # if 'win32' not in platform and 'win64' not in platform: + # l10n.encoding = locale.nl_langinfo(locale.CODESET) + # else: + # l10n.encoding = locale.getlocale()[1] + # logger.info("Successfully set locale to %s", lang) + # break + # except: + # logger.error("Failed to set locale to %s", lang, exc_info=True) + + # Clock.schedule_once(self.init_ui, 0) + + # def init_ui(self, dt=0): + # """Initialization for Ui""" + # if self.newlocale is None: + # self.newlocale = l10n.getTranslationLanguage() + # # state.kivyapp.tr = Lang(self.newlocale) + # state.kivyapp.tr = Lang(self.newlocale) + # menu_items = [{"text": f"{i}"} for i in self.languages.values()] + # self.menu = MDDropdownMenu( + # caller=self.ids.dropdown_item, + # items=menu_items, + # position="auto", + # width_mult=3.5, + # ) + # self.menu.bind(on_release=self.set_item) + + # def set_item(self, instance_menu, instance_menu_item): + # self.ids.dropdown_item.set_item(instance_menu_item.text) + # instance_menu.dismiss() + + # def change_language(self): + # lang = self.ids.dropdown_item.current_item + # for k, v in self.languages.items(): + # if v == lang: + # BMConfigParser().set('bitmessagesettings', 'userlocale', k) + # BMConfigParser().save() + # state.kivyapp.tr = Lang(k) + # self.children[0].active = True + # Clock.schedule_once(partial(self.language_callback, k), 1) + + # def language_callback(self, lang, dt=0): + # self.children[0].active = False + # state.kivyapp.tr = Lang(lang) + # toast('Language changed') \ No newline at end of file diff --git a/src/bitmessagekivy/baseclass/trash.py b/src/bitmessagekivy/baseclass/trash.py new file mode 100644 index 00000000..ee27f4bc --- /dev/null +++ b/src/bitmessagekivy/baseclass/trash.py @@ -0,0 +1,196 @@ +from bitmessagekivy.get_platform import platform +from bmconfigparser import BMConfigParser +from helper_sql import sqlExecute, sqlQuery +from functools import partial +from kivy.clock import Clock +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + StringProperty +) +from kivy.uix.button import Button +from kivymd.uix.button import MDFlatButton +from kivy.uix.carousel import Carousel +from kivymd.uix.dialog import MDDialog +from kivymd.uix.label import MDLabel +from kivymd.uix.list import TwoLineAvatarIconListItem +from kivy.uix.screenmanager import Screen + +import state + +from bitmessagekivy.baseclass.common import ( + showLimitedCnt, initailize_detail_page, avatarImageFirstLetter, + AddTimeWidget, ThemeClsColor, AvatarSampleWidget +) + +from bitmessagekivy.baseclass.common import ( + toast, showLimitedCnt, ThemeClsColor, chipTag, + AddTimeWidget, AvatarSampleWidget +) + + +class Trash(Screen): + """Trash Screen class for kivy Ui""" + + trash_messages = ListProperty() + has_refreshed = True + # delete_index = StringProperty() + table_name = StringProperty() + + def __init__(self, *args, **kwargs): + """Trash method, delete sent message and add in Trash""" + super(Trash, self).__init__(*args, **kwargs) + Clock.schedule_once(self.init_ui, 0) + + def init_ui(self, dt=0): + """Clock Schdule for method trash screen""" + if state.association == '': + if BMConfigParser().addresses(): + state.association = BMConfigParser().addresses()[0] + self.ids.tag_label.text = '' + self.trashDataQuery(0, 20) + if self.trash_messages: + self.ids.tag_label.text = 'Trash' + # src_mng_obj = state.kivyapp.root.children[2].children[0].ids + # src_mng_obj.trash_cnt.badge_text = state.trash_count + self.set_TrashCnt(state.trash_count) + self.set_mdList() + self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) + else: + self.set_TrashCnt('0') + content = MDLabel( + font_style='Caption', + theme_text_color='Primary', + text="yet no trashed message for this account!!!!!!!!!!!!!", + halign='center', + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def trashDataQuery(self, start_indx, end_indx): + """Trash message query""" + self.trash_messages = sqlQuery( + "SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'sent' as folder, ackdata As" + " id, DATE(senttime) As actionTime, senttime as msgtime FROM sent" + " WHERE folder = 'trash' and fromaddress = '{0}' UNION" + " SELECT toaddress, fromaddress, subject, message," + " folder ||',' || 'inbox' as folder, msgid As id," + " DATE(received) As actionTime, received as msgtime FROM inbox" + " WHERE folder = 'trash' and toaddress = '{0}'" + " ORDER BY actionTime DESC limit {1}, {2}".format( + state.association, start_indx, end_indx)) + + def set_TrashCnt(self, Count): # pylint: disable=no-self-use + """This method is used to set trash message count""" + trashCnt_obj = state.kivyapp.root.ids.content_drawer.ids.trash_cnt + trashCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) + + def set_mdList(self): + """This method is used to create the mdlist""" + total_trash_msg = len(self.ids.ml.children) + for item in self.trash_messages: + subject = item[2].decode() if isinstance(item[2], bytes) else item[2] + body = item[3].decode() if isinstance(item[3], bytes) else item[3] + meny = TwoLineAvatarIconListItem( + text=item[1], + secondary_text=(item[2][:50] + '........' if len( + subject) >= 50 else (subject + ',' + body)[0:50] + '........').replace('\t', '').replace(' ', ''), + theme_text_color='Custom', + text_color=ThemeClsColor) + meny._txt_right_pad = dp(70) + img_latter = state.imageDir + '/text_images/{}.png'.format( + subject[0].upper() if (subject[0].upper() >= 'A' and subject[0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget(source=img_latter)) + meny.add_widget(AddTimeWidget(item[7])) + meny.add_widget(chipTag('inbox 'if 'inbox' in item[4] else 'sent')) + 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], item[4])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + self.has_refreshed = True if total_trash_msg != len( + self.ids.ml.children) else False + + def check_scroll_y(self, instance, somethingelse): + """Load data on scroll""" + if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: + self.ids.scroll_y.scroll_y = 0.06 + total_trash_msg = len(self.ids.ml.children) + self.update_trash_screen_on_scroll(total_trash_msg) + + def update_trash_screen_on_scroll(self, total_trash_msg): + """Load more data on scroll down""" + self.trashDataQuery(total_trash_msg, 5) + self.set_mdList() + + def delete_permanently(self, data_index, folder, instance, *args): + """Deleting trash mail permanently""" + self.table_name = folder.split(',')[1] + self.delete_index = data_index + self.delete_confirmation() + + def callback_for_screen_load(self, dt=0): + """This methos is for loading screen""" + self.ids.ml.clear_widgets() + self.init_ui(0) + self.children[1].active = False + toast('Message is permanently deleted') + + def delete_confirmation(self): + """Show confirmation delete popup""" + width = .8 if platform == 'android' else .55 + dialog_box = MDDialog( + text='Are you sure you want to delete this' + ' message permanently from trash?', + size_hint=(width, .25), + buttons=[ + MDFlatButton( + text="Yes", on_release=lambda x: callback_for_delete_msg("Yes") + ), + MDFlatButton( + text="No", on_release=lambda x: callback_for_delete_msg("No"), + ), + ],) + dialog_box.open() + + def callback_for_delete_msg(text_item, *arg): + """Getting the callback of alert box""" + if text_item == 'Yes': + self.delete_message_from_trash() + else: + toast(text_item) + dialog_box.dismiss() + + # def callback_for_delete_msg(self, text_item, *arg): + # """Getting the callback of alert box""" + # if text_item == 'Yes': + # self.delete_message_from_trash() + # else: + # toast(text_item) + + def delete_message_from_trash(self): + """Deleting message from trash""" + self.children[1].active = True + if self.table_name == 'inbox': + sqlExecute( + "DELETE FROM inbox WHERE msgid = ?;", self.delete_index) + elif self.table_name == 'sent': + sqlExecute( + "DELETE FROM sent WHERE ackdata = ?;", self.delete_index) + if int(state.trash_count) > 0: + # msg_count_objs.trash_cnt.badge_text = str( + # int(state.trash_count) - 1) + self.set_TrashCnt(int(state.trash_count) - 1) + state.trash_count = str(int(state.trash_count) - 1) + Clock.schedule_once(self.callback_for_screen_load, 1) diff --git a/src/bitmessagekivy/kv/maildetail.kv b/src/bitmessagekivy/kv/maildetail.kv index 07851e8e..38b199df 100644 --- a/src/bitmessagekivy/kv/maildetail.kv +++ b/src/bitmessagekivy/kv/maildetail.kv @@ -78,4 +78,10 @@ canvas.before: Color: rgba: (0,0,0,1) - Loader: \ No newline at end of file + # Loader: + + +: + canvas.before: + Color: + rgba: (0,0,0,1) diff --git a/src/bitmessagekivy/kv/composer.kv b/src/bitmessagekivy/kv/msg_composer.kv similarity index 98% rename from src/bitmessagekivy/kv/composer.kv rename to src/bitmessagekivy/kv/msg_composer.kv index 2f06305d..558f6d0c 100644 --- a/src/bitmessagekivy/kv/composer.kv +++ b/src/bitmessagekivy/kv/msg_composer.kv @@ -1,3 +1,8 @@ +: + name: 'create' + Loader: + + : ScrollView: id: id_scroll @@ -136,6 +141,7 @@ canvas.before: Color: rgba: (0,0,0,1) + : diff --git a/src/bitmessagekivy/kv/qrcode.kv b/src/bitmessagekivy/kv/qrcode.kv new file mode 100644 index 00000000..cadaa996 --- /dev/null +++ b/src/bitmessagekivy/kv/qrcode.kv @@ -0,0 +1,33 @@ +: + name: 'showqrcode' + BoxLayout: + orientation: 'vertical' + size_hint: (None, None) + pos_hint:{'center_x': .5, 'top': 0.9} + size: (app.window_size[0]/1.8, app.window_size[0]/1.8) + id: qr + BoxLayout: + orientation: 'vertical' + MyMDTextField: + size_hint_y: None + font_style: 'Body1' + theme_text_color: 'Primary' + text: app.tr._(root.address) + multiline: True + readonly: True + line_color_normal: [0,0,0,0] + _current_line_color: [0,0,0,0] + line_color_focus: [0,0,0,0] + halign: 'center' + font_size: dp(15) + bold: True + canvas.before: + Color: + rgba: (0,0,0,1) + # MDLabel: + # size_hint_y: None + # font_style: 'Body1' + # theme_text_color: 'Primary' + # text: "[b]BM-2cV7Y8imvAevK6z6YmhYRcj2t7rghBtDSZ[/b]" + # markup: True + # pos_hint: {'x': .28, 'y': 0.6} \ No newline at end of file diff --git a/src/bitmessagekivy/kv/scan_screen.kv b/src/bitmessagekivy/kv/scan_screen.kv new file mode 100644 index 00000000..dbcff5a1 --- /dev/null +++ b/src/bitmessagekivy/kv/scan_screen.kv @@ -0,0 +1,2 @@ +: + name:'scanscreen' \ No newline at end of file diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index c051c8b6..53b7d04f 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -74,8 +74,8 @@ on_release: app.rest_default_avatar_img() theme_text_color: "Custom" text_color: app.theme_cls.primary_color - # opacity: 1 if app.current_address_label() else 0 - # disabled: False if app.current_address_label() else True + opacity: 1 if app.current_address_label() else 0 + disabled: False if app.current_address_label() else True opacity: 0 disabled: True @@ -126,19 +126,10 @@ option_cls: Factory.get("MySpinnerOption") font_size: '12.5sp' text: app.getDefaultAccData(self) - #background_color: color_button if self.state == 'normal' else color_button_pressed - #background_down: 'atlas://data/images/defaulttheme/spinner' color: color_font background_normal: '' background_color: app.theme_cls.primary_color - #background_color: (0.62,0.67,0.72,1) - # values: app.variable_1 on_text:app.getCurrentAccountData(self.text) - # Image: - # source: app.get_default_image() - # x: self.width/6 - # y: self.parent.y + self.parent.height/4 - # size: self.parent.height/2, self.parent.height/2 ArrowImg: NavigationItem: id: inbox_cnt @@ -252,8 +243,8 @@ MDNavigationLayout: height: root.height - toolbar.height Inbox: id:sc1 - Page: - id:sc2 + # Page: + # id:sc2 Create: id:sc3 Sent: @@ -264,8 +255,8 @@ MDNavigationLayout: id:sc6 Random: id:sc7 - Spam: - id:sc8 + # Spam: + # id:sc8 Setting: id:sc9 MyAddress: @@ -276,24 +267,24 @@ MDNavigationLayout: id:sc12 NetworkStat: id:sc13 - MailDetail: - id:sc14 + # MailDetail: + # id:sc14 ShowQRCode: id:sc15 Draft: id:sc16 Allmails: id:sc17 - Credits: - id:sc18 - Starred: - id:sc19 - Archieve: - id:sc20 - ChatRoom: - id:sc21 - ChatList: - id:sc22 + # Credits: + # id:sc18 + # Starred: + # id:sc19 + # Archieve: + # id:sc20 + # ChatRoom: + # id:sc21 + # ChatList: + # id:sc22 ScanScreen: id:sc23 @@ -303,74 +294,51 @@ MDNavigationLayout: ContentNavigationDrawer: id: content_drawer -: - name: 'page' - Label: - text:"I am in Page" - color: 0,0,0,1 - -: - name: 'create' - Loader: - -: - name: 'spam' - Label: - text:"I am in Spam" - color: 0,0,0,1 - -: - name: 'showqrcode' - BoxLayout: - orientation: 'vertical' - size_hint: (None, None) - pos_hint:{'center_x': .5, 'top': 0.9} - size: (app.window_size[0]/1.8, app.window_size[0]/1.8) - id: qr - BoxLayout: - orientation: 'vertical' - MyMDTextField: - size_hint_y: None - font_style: 'Body1' - theme_text_color: 'Primary' - text: app.tr._(root.address) - multiline: True - readonly: True - line_color_normal: [0,0,0,0] - _current_line_color: [0,0,0,0] - line_color_focus: [0,0,0,0] - halign: 'center' - font_size: dp(15) - bold: True - canvas.before: - Color: - rgba: (0,0,0,1) - # MDLabel: - # size_hint_y: None - # font_style: 'Body1' - # theme_text_color: 'Primary' - # text: "[b]BM-2cV7Y8imvAevK6z6YmhYRcj2t7rghBtDSZ[/b]" - # markup: True - # pos_hint: {'x': .28, 'y': 0.6} - -: - name: 'starred' - Label: - text:"I am in Starred" - color: 0,0,0,1 - - color: 0,0,0,1 - -: - name: 'archieve' - Label: - text:"I am in Archieve" - color: 0,0,0,1 - - color: 0,0,0,1 - -: - name:'scanscreen' - - \ No newline at end of file +: + source: app.image_path +('/down-arrow.png' if self.parent.is_open == True else '/right-arrow.png') + size: 15, 15 + x: self.parent.x + self.parent.width - self.width - 5 + y: self.parent.y + self.parent.height/2 - self.height + 5 + + +: + # id: search_bar + size_hint_y: None + height: self.minimum_height + + MDIconButton: + icon: 'magnify' + + MDTextField: + id: search_field + hint_text: 'Search' + on_text: app.searchQuery(self) + canvas.before: + Color: + rgba: (0,0,0,1) + + +: + id: spinner + size_hint: None, None + size: dp(46), dp(46) + pos_hint: {'center_x': 0.5, 'center_y': 0.5} + active: False + +: + size_hint_y: None + height: dp(56) + spacing: '10dp' + pos_hint: {'center_x':0.45, 'center_y': .1} + + Widget: + + MDFloatingActionButton: + icon: 'plus' + opposite_colors: True + elevation_normal: 8 + md_bg_color: [0.941, 0, 0,1] + on_press: app.root.ids.scr_mngr.current = 'create' + on_press: app.clear_composer() + diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 05bb1a41..161b22c2 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -9,15 +9,13 @@ Bitmessage android(mobile) interface """ - from bitmessagekivy.get_platform import platform import os -import time # from bitmessagekivy import identiconGeneration from bitmessagekivy import kivy_helper_search from bitmessagekivy.uikivysignaler import UIkivySignaler from bmconfigparser import BMConfigParser -from debug import logger +# from debug import logger from functools import partial from helper_sql import sqlExecute, sqlQuery from kivymd.app import MDApp @@ -33,57 +31,32 @@ from kivy.properties import ( 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 kivy.uix.spinner import Spinner -from kivy.uix.textinput import TextInput -from kivymd.uix.button import MDIconButton from kivymd.uix.dialog import MDDialog from kivymd.uix.label import MDLabel -from kivymd.uix.button import MDFlatButton, MDRaisedButton +from kivymd.uix.button import MDRaisedButton from kivymd.uix.list import ( - ILeftBody, - ILeftBodyTouch, IRightBodyTouch, - TwoLineAvatarIconListItem, - OneLineIconListItem, OneLineAvatarIconListItem, OneLineListItem ) -# from kivymd.uix.navigationdrawer import ( -# MDNavigationDrawer, -# NavigationDrawerHeaderBase -# ) -from kivymd.uix.selectioncontrol import MDCheckbox, MDSwitch -from kivymd.uix.chip import MDChip from kivy.uix.screenmanager import RiseInTransition, SlideTransition, FallOutTransition import queues from semaphores import kivyuisignaler import state -from addresses import decodeAddress -from datetime import datetime -from kivymd.uix.behaviors.elevation import RectangularElevationBehavior from kivymd.uix.bottomsheet import MDCustomBottomSheet -from kivy.effects.dampedscroll import DampedScrollEffect -from kivymd.uix.menu import MDDropdownMenu from kivy.lang import Observable import gettext import l10n import locale +import ast + +from bitmessagekivy.baseclass.common import toast if platform != "android": from kivy.config import Config @@ -107,88 +80,17 @@ elif platform == "android": t = Toast.makeText(context, text, length) t.show() + +with open(os.path.join(os.path.dirname(__file__), "screens_data.json") + ) as read_file: + all_data = ast.literal_eval(read_file.read()) + data_screens = list(all_data.keys()) + +for modules in data_screens: + exec(all_data[modules]['Import']) + # pylint: disable=too-few-public-methods,too-many-arguments,attribute-defined-outside-init -KVFILES = [ - "settings", - "popup", - "allmails", - "draft", - "maildetail", - "common_widgets", - "addressbook", - "myaddress", - "composer", - "payment", - "sent", - "network", - "login", - "credits", - "trash", - "inbox", - "chat_room", - "chat_list" -] - -ThemeClsColor = [0.12, 0.58, 0.95, 1] - - -def toast(text): - """Method will display the toast message""" - # pylint: disable=redefined-outer-name - from kivymd.toast.kivytoast import toast - - toast(text) - return None - - -def showLimitedCnt(total_msg): - """This method set the total count limit in badge_text""" - return "99+" if total_msg > 99 else str(total_msg) - - -def ShowTimeHistoy(act_time): - """This method is used to return the message sent or receive time""" - action_time = datetime.fromtimestamp(int(act_time)) - crnt_date = datetime.now() - duration = crnt_date - action_time - display_data = ( - action_time.strftime("%d/%m/%Y") - if duration.days >= 365 - else action_time.strftime("%I:%M %p").lstrip("0") - if duration.days == 0 and crnt_date.strftime("%d/%m/%Y") == action_time.strftime("%d/%m/%Y") - else action_time.strftime("%d %b") - ) - return display_data - - -def AddTimeWidget(time): # pylint: disable=redefined-outer-name - """This method is used to create TimeWidget""" - action_time = TimeTagRightSampleWidget( - text=str(ShowTimeHistoy(time)), - font_style="Caption", - size=[120, 140] if platform == "android" else [64, 80], - ) - action_time.font_size = "11sp" - return action_time - - -def chipTag(text): - """This method is used for showing chip tag""" - obj = MDChip() - # obj.size_hint = (None, None) - obj.size_hint = (0.16 if platform == "android" else 0.08, None) - obj.text = text - obj.icon = "" - obj.pos_hint = { - "center_x": 0.91 if platform == "android" else 0.94, - "center_y": 0.3 - } - obj.height = dp(18) - obj.text_color = (1,1,1,1) - obj.radius =[8] - return obj - class Lang(Observable): observers = [] @@ -229,1072 +131,46 @@ class Lang(Observable): func(largs, None, None) -class Inbox(Screen): - """Inbox Screen class for kivy Ui""" +class NavigationItem(OneLineAvatarIconListItem): + """NavigationItem class for kivy Ui""" + badge_text = StringProperty() + icon = StringProperty() + active = BooleanProperty(False) - queryreturn = ListProperty() - has_refreshed = True - account = StringProperty() - - def __init__(self, *args, **kwargs): - """Method Parsing the address""" - super(Inbox, self).__init__(*args, **kwargs) - Clock.schedule_once(self.init_ui, 0) - - @staticmethod - def set_defaultAddress(): - """This method set's default address""" - if state.association == "": - if BMConfigParser().addresses(): - state.association = BMConfigParser().addresses()[0] - - def init_ui(self, dt=0): - """Clock schdule for method inbox accounts""" - self.loadMessagelist() - - def loadMessagelist(self, where="", what=""): - """Load Inbox list for Inbox messages""" - self.set_defaultAddress() - self.account = state.association - if state.searcing_text: - # self.children[2].children[0].children[0].scroll_y = 1.0 - self.ids.scroll_y.scroll_y = 1.0 - where = ["subject", "message"] - what = state.searcing_text - xAddress = "toaddress" - data = [] - self.ids.tag_label.text = "" - self.inboxDataQuery(xAddress, where, what) - self.ids.tag_label.text = "" - if self.queryreturn: - self.ids.tag_label.text = "Inbox" - state.kivyapp.get_inbox_count() - self.set_inboxCount(state.inbox_count) - for mail in self.queryreturn: - # third_text = mail[3].replace('\n', ' ') - body = mail[3].decode() if isinstance(mail[3], bytes) else mail[3] - subject = mail[5].decode() if isinstance(mail[5], bytes) else mail[5] - data.append( - { - "text": mail[4].strip(), - "secondary_text": ( - subject[:50] + "........" - if len(subject) >= 50 - else (subject + "," + body)[0:50] + "........" - ) - .replace("\t", "") - .replace(" ", ""), - "msgid": mail[1], - "received": mail[6] - } - ) - - self.has_refreshed = True - self.set_mdList(data) - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - self.set_inboxCount("0") - content = MDLabel( - font_style="Caption", - theme_text_color="Primary", - text="No message found!" - if state.searcing_text - else "yet no message for this account!!!!!!!!!!!!!", - halign="center", - size_hint_y=None, - valign="top" - ) - self.ids.ml.add_widget(content) - - def set_inboxCount(self, msgCnt): # pylint: disable=no-self-use - """This method is used to sent inbox message count""" - src_mng_obj = state.kivyapp.root.ids.content_drawer.ids - src_mng_obj.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(msgCnt)) - state.kivyapp.get_sent_count() - state.all_count = str( - int(state.sent_count) + int(state.inbox_count)) - src_mng_obj.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count)) - - def inboxDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): - """This method is used for retrieving inbox data""" - self.queryreturn = kivy_helper_search.search_sql( - xAddress, self.account, "inbox", where, what, False, start_indx, end_indx - ) - - def set_mdList(self, data): - """This method is used to create the mdList""" - total_message = len(self.ids.ml.children) - for item in data: - meny = TwoLineAvatarIconListItem( - text=item["text"], - secondary_text=item["secondary_text"], - theme_text_color="Custom", - text_color=NavigateApp().theme_cls.primary_color - ) - meny._txt_right_pad = dp(70) - meny.add_widget( - AvatarSampleWidget( - source=state.imageDir + "/text_images/{}.png".format( - avatarImageFirstLetter(item["secondary_text"].strip()) - ) - ) - ) - meny.bind(on_press=partial(self.inbox_detail, item["msgid"])) - meny.add_widget(AddTimeWidget(item["received"])) - carousel = Carousel(direction="right") - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text="Delete") - del_btn.background_normal = "" - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete, item["msgid"])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - # ach_btn = Button(text='Achieve') - # ach_btn.background_color = (0, 1, 0, 1) - # ach_btn.bind(on_press=partial(self.archive, item['msgid'])) - # carousel.add_widget(ach_btn) - carousel.index = 1 - self.ids.ml.add_widget(carousel) - update_message = len(self.ids.ml.children) - self.has_refreshed = True if total_message != update_message else False - - def check_scroll_y(self, instance, somethingelse): - """Loads data on scroll""" - if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: - self.ids.scroll_y.scroll_y = 0.06 - total_message = len(self.ids.ml.children) - self.update_inbox_screen_on_scroll(total_message) - - def update_inbox_screen_on_scroll(self, total_message, where="", what=""): - """This method is used to load more data on scroll down""" - data = [] - if state.searcing_text: - where = ["subject", "message"] - what = state.searcing_text - self.inboxDataQuery("toaddress", where, what, total_message, 5) - for mail in self.queryreturn: - # third_text = mail[3].replace('\n', ' ') - subject = mail[3].decode() if isinstance(mail[3], bytes) else mail[3] - body = mail[5].decode() if isinstance(mail[5], bytes) else mail[5] - data.append( - { - "text": mail[4].strip(), - "secondary_text": body[:50] + "........" - if len(body) >= 50 - else (body + "," + subject.replace("\n", ""))[0:50] + "........", - "msgid": mail[1], - "received": mail[6] - } - ) - self.set_mdList(data) - - def inbox_detail(self, msg_id, *args): - """Load inbox page details""" - state.detailPageType = "inbox" - state.mail_id = msg_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 delete(self, data_index, instance, *args): - """Delete inbox mail from inbox listing""" - sqlExecute("UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", data_index) - msg_count_objs = self.parent.parent.ids.content_drawer.ids - if int(state.inbox_count) > 0: - msg_count_objs.inbox_cnt.ids.badge_txt.text = showLimitedCnt( - int(state.inbox_count) - 1 - ) - msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt( - int(state.trash_count) + 1 - ) - state.inbox_count = str(int(state.inbox_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) - if int(state.all_count) > 0: - msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt( - int(state.all_count) - 1 - ) - state.all_count = str(int(state.all_count) - 1) - - if int(state.inbox_count) <= 0: - # self.ids.identi_tag.children[0].text = '' - self.ids.tag_label.text = '' - 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 msgid = ?;", data_index) - self.ids.ml.remove_widget(instance.parent.parent) - self.update_trash() - - def update_trash(self): - """Update trash screen mails which is deleted from inbox""" - try: - self.parent.screens[4].clear_widgets() - self.parent.screens[4].add_widget(Trash()) - except Exception: - self.parent.parent.screens[4].clear_widgets() - self.parent.parent.screens[4].add_widget(Trash()) - - 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""" - state.searcing_text = "" - self.children[2].children[1].ids.search_field.text = "" - self.ids.ml.clear_widgets() - self.loadMessagelist(state.association) - self.has_refreshed = True - self.ids.refresh_layout.refresh_done() - self.tick = 0 - - Clock.schedule_once(refresh_callback, 1) + def currentlyActive(self): + """Currenly active""" + for nav_obj in self.parent.children: + nav_obj.active = False + self.active = True -class CustomTwoLineAvatarIconListItem(TwoLineAvatarIconListItem): - """CustomTwoLineAvatarIconListItem class for kivy Ui""" +class NavigationDrawerDivider(OneLineListItem): + """ + A small full-width divider that can be placed + in the :class:`MDNavigationDrawer` + """ - -class MyAddress(Screen): - """MyAddress screen class for kivy Ui""" - - address_label = StringProperty() - text_address = StringProperty() - addresses_list = ListProperty() - has_refreshed = True - is_add_created = False - - def __init__(self, *args, **kwargs): - """Clock schdule for method Myaddress accounts""" - super(MyAddress, self).__init__(*args, **kwargs) - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock schdule for method Myaddress accounts""" - # pylint: disable=unnecessary-lambda, deprecated-lambda - # self.addresses_list = state.kivyapp.variable_1 - self.addresses_list = BMConfigParser().addresses() - if state.searcing_text: - self.ids.refresh_layout.scroll_y = 1.0 - filtered_list = [ - x for x in BMConfigParser().addresses() - if self.filter_address(x) - ] - self.addresses_list = filtered_list - self.addresses_list = [obj for obj in reversed(self.addresses_list)] - self.ids.tag_label.text = '' - if self.addresses_list: - self.ids.tag_label.text = 'My Addresses' - self.has_refreshed = True - self.set_mdList(0, 15) - self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) - else: - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="No address found!" if state.searcing_text - else "yet no address is created by user!!!!!!!!!!!!!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - if not state.searcing_text and not self.is_add_created: - try: - self.manager.current = 'login' - except Exception: - pass - - def set_mdList(self, first_index, last_index): - """Creating the mdlist""" - data = [] - for address in self.addresses_list[first_index:last_index]: - data.append({ - 'text': BMConfigParser().get(address, 'label'), - 'secondary_text': address}) - for item in data: - is_enable = BMConfigParser().get(item['secondary_text'], 'enabled') - meny = CustomTwoLineAvatarIconListItem( - text=item['text'], secondary_text=item['secondary_text'], - theme_text_color='Custom' if is_enable == 'true' else 'Primary', - text_color=ThemeClsColor,) - meny._txt_right_pad = dp(70) - try: - meny.canvas.children[6].rgba = [0, 0, 0, 0] if is_enable == 'true' else [0.5, 0.5, 0.5, 0.5] - except Exception: - try: - meny.canvas.children[9].rgba = [0, 0, 0, 0] if is_enable == 'true' else [0.5, 0.5, 0.5, 0.5] - except Exception as e: - print('Exception: ', e) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/text_images/{}.png'.format( - avatarImageFirstLetter(item['text'].strip())))) - meny.bind(on_press=partial( - self.myadd_detail, item['secondary_text'], item['text'])) - if state.association == item['secondary_text'] and is_enable == 'true': - badge_obj = BadgeText( - size_hint=(None, None), - size=[90 if platform == 'android' else 50, 60], - text='Active', halign='center', - font_style='Body1', theme_text_color='Custom', - text_color=ThemeClsColor - ) - badge_obj.font_size = '13sp' - meny.add_widget(badge_obj) - else: - meny.add_widget(ToggleBtn(active=True if is_enable == 'true' else False)) - self.ids.ml.add_widget(meny) - - def check_scroll_y(self, instance, somethingelse): - """Load data on scroll down""" - if self.ids.refresh_layout.scroll_y <= -0.0 and self.has_refreshed: - self.ids.refresh_layout.scroll_y = 0.06 - my_addresses = len(self.ids.ml.children) - if my_addresses != len(self.addresses_list): - self.update_addressBook_on_scroll(my_addresses) - self.has_refreshed = ( - True if my_addresses != len(self.addresses_list) else False - ) - - def update_addressBook_on_scroll(self, my_addresses): - """Loads more data on scroll down""" - self.set_mdList(my_addresses, my_addresses + 20) - - # @staticmethod - def myadd_detail(self, fromaddress, label, *args): - """Load myaddresses details""" - if BMConfigParser().get(fromaddress, 'enabled') == 'true': - obj = MyaddDetailPopup() - self.address_label = obj.address_label = label - self.text_address = obj.address = fromaddress - width = .9 if platform == 'android' else .6 - self.myadddetail_popup = MDDialog( - type="custom", - size_hint=(width, .25), - content_cls=obj, - ) - self.myadddetail_popup.set_normal_height() - self.myadddetail_popup.auto_dismiss = False - self.myadddetail_popup.open() - # p.set_address(fromaddress, label) - else: - width = .8 if platform == 'android' else .55 - dialog_box = MDDialog( - text='Address is not currently active. Please click on Toggle button to active it.', - size_hint=(width, .25), - buttons=[ - MDFlatButton( - text="Ok", on_release=lambda x: callback_for_menu_items("Ok") - ), - ], - ) - dialog_box.open() - - def callback_for_menu_items(text_item, *arg): - """Callback of alert box""" - dialog_box.dismiss() - toast(text_item) - - # @staticmethod - # def callback_for_menu_items(text_item, *arg): - # """Callback of alert box""" - # toast(text_item) - - def refresh_callback(self, *args): - """Method updates the state of application, - While the spinner remains on the screen""" - def refresh_callback(interval): - """Method used for loading the myaddress screen data""" - state.searcing_text = '' - # state.kivyapp.root.ids.sc10.children[2].active = False - self.ids.search_bar.ids.search_field.text = '' - self.has_refreshed = True - self.ids.ml.clear_widgets() - self.init_ui() - self.ids.refresh_layout.refresh_done() - self.tick = 0 - Clock.schedule_once(self.address_permision_callback, 0) - Clock.schedule_once(refresh_callback, 1) - - @staticmethod - def filter_address(address): - """Method will filter the my address list data""" - if [ - x for x in [ - BMConfigParser().get(address, 'label').lower(), - address.lower() - ] - if (state.searcing_text).lower() in x - ]: - return True - return False - - def disableAddress(self, address, instance): - """This method is use for disabling address""" - BMConfigParser().set(str(address), 'enabled', 'false') - BMConfigParser().save() - instance.parent.parent.theme_text_color = 'Primary' - try: - instance.parent.parent.canvas.children[6].rgba = [0.5, 0.5, 0.5, 0.5] - except Exception: - instance.parent.parent.canvas.children[9].rgba = [0.5, 0.5, 0.5, 0.5] - toast('Address disabled') - Clock.schedule_once(self.address_permision_callback, 0) - - def enableAddress(self, address, instance): - """This method is use for enabling address""" - BMConfigParser().set(address, 'enabled', 'true') - BMConfigParser().save() - instance.parent.parent.theme_text_color = 'Custom' - try: - instance.parent.parent.canvas.children[6].rgba = [0, 0, 0, 0] - except Exception: - instance.parent.parent.canvas.children[9].rgba = [0, 0, 0, 0] - toast('Address Enabled') - Clock.schedule_once(self.address_permision_callback, 0) - - def address_permision_callback(self, dt=0): - """callback for enable or disable addresses""" - addresses = [addr for addr in BMConfigParser().addresses() - if BMConfigParser().get(str(addr), 'enabled') == 'true'] - self.parent.parent.ids.content_drawer.ids.btn.values = addresses - self.parent.parent.ids.sc3.children[1].ids.btn.values = addresses - - def toggleAction(self, instance): - """This method is used for enable or disable address""" - addr = instance.parent.parent.secondary_text - if instance.active: - self.enableAddress(addr, instance) - else: - self.disableAddress(addr, instance) - - -class AddressBook(Screen): - """AddressBook Screen class for kivy Ui""" - - queryreturn = ListProperty() - has_refreshed = True - address_label = StringProperty() - address = StringProperty() - - def __init__(self, *args, **kwargs): - """Getting AddressBook Details""" - super(AddressBook, self).__init__(*args, **kwargs) - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock Schdule for method AddressBook""" - self.loadAddresslist(None, 'All', '') - print(dt) - - def loadAddresslist(self, account, where="", what=""): - """Clock Schdule for method AddressBook""" - if state.searcing_text: - self.ids.scroll_y.scroll_y = 1.0 - where = ['label', 'address'] - what = state.searcing_text - xAddress = '' - self.ids.tag_label.text = '' - self.queryreturn = kivy_helper_search.search_sql( - xAddress, account, "addressbook", where, what, False) - self.queryreturn = [obj for obj in reversed(self.queryreturn)] - if self.queryreturn: - self.ids.tag_label.text = 'Address Book' - self.has_refreshed = True - self.set_mdList(0, 20) - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="No contact found!" if state.searcing_text - else "No contact found yet...... ", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def set_mdList(self, start_index, end_index): - """Creating the mdList""" - for item in self.queryreturn[start_index:end_index]: - meny = TwoLineAvatarIconListItem( - text=item[0], secondary_text=item[1], theme_text_color='Custom', - text_color=ThemeClsColor) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/text_images/{}.png'.format( - avatarImageFirstLetter(item[0].strip())))) - meny.bind(on_press=partial( - self.addBook_detail, item[1], item[0])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete_address, item[1])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) - - def check_scroll_y(self, instance, somethingelse): - """Load data on scroll""" - if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: - self.ids.scroll_y.scroll_y = 0.06 - exist_addresses = len(self.ids.ml.children) - if exist_addresses != len(self.queryreturn): - self.update_addressBook_on_scroll(exist_addresses) - self.has_refreshed = ( - True if exist_addresses != len(self.queryreturn) else False - ) - - def update_addressBook_on_scroll(self, exist_addresses): - """Load more data on scroll down""" - self.set_mdList(exist_addresses, exist_addresses + 5) - - @staticmethod - def refreshs(*args): - """Refresh the Widget""" - # state.navinstance.ids.sc11.ids.ml.clear_widgets() - # state.navinstance.ids.sc11.loadAddresslist(None, 'All', '') - - # @staticmethod - def addBook_detail(self, address, label, *args): - """Addressbook details""" - obj = AddbookDetailPopup() - self.address_label = obj.address_label = label - self.address = obj.address = address - width = .9 if platform == 'android' else .8 - self.addbook_popup = MDDialog( - type="custom", - size_hint=(width, .25), - content_cls=obj, - buttons=[ - MDRaisedButton( - text="Send message to", - text_color=state.kivyapp.theme_cls.primary_color, - on_release=self.send_message_to, - ), - MDRaisedButton( - text="Save", text_color=state.kivyapp.theme_cls.primary_color, - on_release=self.update_addbook_label, - ), - MDRaisedButton( - text="Cancel", text_color=state.kivyapp.theme_cls.primary_color, - on_release=self.close_pop, - ), - ], - ) - self.addbook_popup.set_normal_height() - self.addbook_popup.auto_dismiss = False - self.addbook_popup.open() - - def delete_address(self, address, instance, *args): - """Delete inbox mail from inbox listing""" - self.ids.ml.remove_widget(instance.parent.parent) - # if len(self.ids.ml.children) == 0: - if self.ids.ml.children is not None: - self.ids.tag_label.text = '' - sqlExecute( - "DELETE FROM addressbook WHERE address = '{}';".format(address)) - - def close_pop(self, instance): - """Pop is Canceled""" - self.addbook_popup.dismiss() - toast('Canceled') - - def update_addbook_label(self, instance): - """Updating the label of address book address""" - address_list = kivy_helper_search.search_sql(folder="addressbook") - stored_labels = [labels[0] for labels in address_list] - add_dict = dict(address_list) - label = str(self.addbook_popup.content_cls.ids.add_label.text) - if label in stored_labels and self.address == add_dict[label]: - stored_labels.remove(label) - if label and label not in stored_labels: - sqlExecute( - "UPDATE addressbook SET label = '{}' WHERE" - " address = '{}';".format( - label, self.addbook_popup.content_cls.address)) - state.kivyapp.root.ids.sc11.ids.ml.clear_widgets() - state.kivyapp.root.ids.sc11.loadAddresslist(None, 'All', '') - self.addbook_popup.dismiss() - toast('Saved') - - def send_message_to(self, instance): - """Method used to fill to_address of composer autofield""" - state.kivyapp.set_navbar_for_composer() - window_obj = state.kivyapp.root.ids - window_obj.sc3.children[1].ids.txt_input.text = self.address - window_obj.sc3.children[1].ids.ti.text = '' - window_obj.sc3.children[1].ids.btn.text = 'Select' - window_obj.sc3.children[1].ids.subject.text = '' - window_obj.sc3.children[1].ids.body.text = '' - window_obj.scr_mngr.current = 'create' - self.addbook_popup.dismiss() - - -class SelectableRecycleBoxLayout( - FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout -): - """Adds selection and focus behaviour to the view""" - - # pylint: disable = duplicate-bases - - -class SelectableLabel(RecycleDataViewBehavior, Label): - """Add selection support to the Label""" - - index = None - selected = BooleanProperty(False) - selectable = BooleanProperty(True) - - def refresh_view_attrs(self, rv, index, data): - """Catch and handle the view changes""" - self.index = index - return super(SelectableLabel, self).refresh_view_attrs(rv, index, data) - - def on_touch_down(self, touch): # pylint: disable=inconsistent-return-statements - """Add selection on touch down""" - if super(SelectableLabel, self).on_touch_down(touch): - return True - if self.collide_point(*touch.pos) and self.selectable: - return self.parent.select_with_touch(self.index, touch) - - def apply_selection(self, rv, index, is_selected): - """Respond to the selection of items in the view""" - self.selected = is_selected - if is_selected: - 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): - """Recycling View class for kivy Ui""" + disabled = True + divider = None + _txt_top_pad = NumericProperty(dp(8)) + _txt_bot_pad = NumericProperty(dp(8)) def __init__(self, **kwargs): - """Recycling Method""" - super(RV, self).__init__(**kwargs) + # pylint: disable=bad-super-call + super(OneLineListItem, self).__init__(**kwargs) + self.height = dp(16) -class DropDownWidget(BoxLayout): - """DropDownWidget class for kivy Ui""" +class NavigationDrawerSubheader(OneLineListItem): + """ + A subheader for separating content in :class:`MDNavigationDrawer` - # pylint: disable=too-many-statements + Works well alongside :class:`NavigationDrawerDivider` + """ - txt_input = ObjectProperty() - rv = ObjectProperty() - - def send(self, navApp): - """Send message from one address to another""" - fromAddress = self.ids.ti.text.strip() - toAddress = self.ids.txt_input.text.strip() - subject = self.ids.subject.text.strip() - message = self.ids.body.text.strip() - encoding = 3 - print("message: ", self.ids.body.text) - sendMessageToPeople = True - if sendMessageToPeople: - if toAddress != "" and subject and message: - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress - ) - if status == "success": - navApp.root.ids.sc3.children[0].active = True - if state.detailPageType == "draft" and state.send_draft_mail: - sqlExecute( - "UPDATE sent SET toaddress = ?" - ", fromaddress = ? , subject = ?" - ", message = ?, folder = 'sent'" - ", senttime = ?, lastactiontime = ?" - " WHERE ackdata = ?;", - toAddress, - fromAddress, - subject, - message, - int(time.time()), - int(time.time()), - 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().safeGetInt( - 'bitmessagesettings', 'ttl')) - state.check_sent_acc = fromAddress - # state.msg_counter_objs = self.parent.parent.parent.parent\ - # .parent.parent.children[2].children[0].ids - if state.detailPageType == 'draft' \ - and state.send_draft_mail: - state.draft_count = str(int(state.draft_count) - 1) - # state.msg_counter_objs.draft_cnt.badge_text = ( - # state.draft_count) - state.detailPageType = '' - state.send_draft_mail = None - self.parent.parent.parent.ids.sc4.update_sent_messagelist() - allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt - allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(state.all_count) + 1) - state.all_count = str(int(state.all_count) + 1) - Clock.schedule_once(self.callback_for_msgsend, 3) - queues.workerQueue.put(('sendmessage', toAddress)) - print("sqlExecute successfully #######################") - state.in_composer = True - return - else: - msg = 'Enter a valid recipients address' - elif not toAddress: - msg = 'Please fill the form completely' - else: - msg = 'Please fill the form completely' - self.address_error_message(msg) - - @staticmethod - def callback_for_msgsend(dt=0): - """Callback method for messagesend""" - state.kivyapp.root.ids.sc3.children[0].active = False - state.in_sent_method = True - state.kivyapp.back_press() - toast("sent") - - def address_error_message(self, msg): - """Generates error message""" - width = .8 if platform == 'android' else .55 - dialog_box = MDDialog( - text=msg, - size_hint=(width, .25), - buttons=[ - MDFlatButton( - text="Ok", on_release=lambda x: callback_for_menu_items("Ok") - ), - ],) - dialog_box.open() - - def callback_for_menu_items(text_item, *arg): - """Callback of alert box""" - dialog_box.dismiss() - toast(text_item) - - def reset_composer(self): - """Method will reset composer""" - self.ids.ti.text = "" - self.ids.btn.text = "Select" - self.ids.txt_input.text = "" - self.ids.subject.text = "" - self.ids.body.text = "" - toast("Reset message") - - def auto_fill_fromaddr(self): - """Fill the text automatically From Address""" - self.ids.ti.text = self.ids.btn.text - self.ids.ti.focus = True - - def is_camara_attached(self): - self.parent.parent.parent.ids.sc23.check_camera() - is_available = self.parent.parent.parent.ids.sc23.camera_avaialbe - return is_available - - def camera_alert(self): - width = .8 if platform == 'android' else .55 - altet_txt = 'Currently this feature is not avaialbe!'if platform == 'android' else 'Camera is not available!' - dialog_box = MDDialog( - text=altet_txt, - size_hint=(width, .25), - buttons=[ - MDFlatButton( - text="Ok", on_release=lambda x: callback_for_menu_items("Ok") - ), - ], - ) - dialog_box.open() - - def callback_for_menu_items(text_item, *arg): - """Callback of alert box""" - dialog_box.dismiss() - toast(text_item) - - -class ScanScreen(Screen): - camera_avaialbe = BooleanProperty(False) - previous_open_screen = StringProperty() - pop_up_instance = ObjectProperty() - - def __init__(self, *args, **kwargs): - """Getting AddressBook Details""" - super(ScanScreen, self).__init__(*args, **kwargs) - self.check_camera() - - def check_camera(self): - """This method is used for checking camera avaibility""" - if platform != "android": - import cv2 - cap = cv2.VideoCapture(0) - while(cap.isOpened()): - print('Camera is available!') - self.camera_avaialbe = True - break - else: - print("Camera is not available!") - self.camera_avaialbe = False - - def get_screen(self, screen_name, instance=None): - """This method is used for getting previous screen name""" - self.previous_open_screen = screen_name - if screen_name != 'composer': - self.pop_up_instance = instance - - def on_pre_enter(self): - """ - on_pre_enter works little better on android - It affects screen transition on linux - """ - if not self.children: - tmp = Builder.load_file( - os.path.join(os.path.dirname(__file__), "kv/{}.kv").format("scanner") - ) - self.add_widget(tmp) - if platform == "android": - Clock.schedule_once(self.start_camera, 0) - - def on_enter(self): - """ - on_enter works better on linux - It creates a black screen on android until camera gets loaded - """ - # print(self.children) - if platform != "android": - # pass - Clock.schedule_once(self.start_camera, 0) - - def on_leave(self): - # pass - Clock.schedule_once(self.stop_camera, 0) - - def start_camera(self, *args): - """Its used for starting camera for scanning qrcode""" - self.xcam = self.children[0].ids.zbarcam.ids.xcamera - if platform == "android": - self.xcam.play = True - - else: - Clock.schedule_once(self.open_cam, 0) - - def stop_camera(self, *args): - """Its used for stop the camera""" - self.xcam.play = False - if platform != "android": - self.xcam._camera._device.release() - - def open_cam(self, *args): - """It will open up the camera""" - if not self.xcam._camera._device.isOpened(): - self.xcam._camera._device.open(self.xcam._camera._index) - self.xcam.play = True - - -class MyTextInput(TextInput): - """MyTextInput class for kivy Ui""" - - txt_input = ObjectProperty() - flt_list = ObjectProperty() - word_list = ListProperty() - starting_no = NumericProperty(3) - suggestion_text = '' - - def __init__(self, **kwargs): - """Getting Text Input.""" - super(MyTextInput, self).__init__(**kwargs) - self.__lineBreak__ = 0 - - def on_text(self, instance, value): - """Find all the occurrence of the word""" - self.parent.parent.parent.parent.parent.ids.rv.data = [] - matches = [self.word_list[i] for i in range( - len(self.word_list)) if self.word_list[ - i][:self.starting_no] == value[:self.starting_no]] - display_data = [] - for i in matches: - display_data.append({'text': i}) - self.parent.parent.parent.parent.parent.ids.rv.data = display_data - if len(matches) <= 10: - self.parent.height = (250 + (len(matches) * 20)) - else: - self.parent.height = 400 - - def keyboard_on_key_down(self, window, keycode, text, modifiers): - """Keyboard on key Down""" - if self.suggestion_text and keycode[1] == 'tab': - self.insert_text(self.suggestion_text + ' ') - return True - return super(MyTextInput, self).keyboard_on_key_down( - window, keycode, text, modifiers) - - -class Payment(Screen): - """Payment Screen class for kivy Ui""" - - def get_free_credits(self, instance): - """Get the available credits""" - # pylint: disable=no-self-use - state.availabe_credit = instance.parent.children[1].text - existing_credits = state.kivyapp.root.ids.sc18.ids.cred.text - if float(existing_credits.split()[1]) > 0: - 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.cred.text = '{0}'.format( - state.availabe_credit) - - def create_hidden_payment_address(self, instance): - """This is basically used for creating hidden address used in payment for purchasing credits""" - if BMConfigParser().paymentaddress(): - toast('hidden payment address already exist for buying subscription...') - else: - streamNumberForAddress = 1 - eighteenByteRipe = False - nonceTrialsPerByte = 1000 - payloadLengthExtraBytes = 1000 - queues.addressGeneratorQueue.put(( - 'createPaymentAddress', 4, streamNumberForAddress, '', 1, - "", eighteenByteRipe, nonceTrialsPerByte, - payloadLengthExtraBytes)) - toast('hidden payment address Creating for buying subscription....') - - -class Category(BoxLayout, RectangularElevationBehavior): - """Category class for kivy Ui""" - elevation_normal = .01 - - -class ProductLayout(BoxLayout, RectangularElevationBehavior): - """ProductLayout class for kivy Ui""" - elevation_normal = .01 - - -class PaymentMethodLayout(BoxLayout): - """PaymentMethodLayout class for kivy Ui""" - - -class ListItemWithLabel(OneLineAvatarIconListItem): - """ListItemWithLabel class for kivy Ui""" - - -class RightLabel(IRightBodyTouch, MDLabel): - """RightLabel class for kivy Ui""" - - -class HomeScreen(Screen): - """HomeScreen class for kivy Ui""" - - -class Credits(Screen): - """Credits Screen class for kivy Ui""" - - available_credits = StringProperty('{0}'.format('€ 0')) - - -class Login(Screen): - """Login Screeen class for kivy Ui""" - log_text1 = ( - 'You may generate addresses by using either random numbers' - ' or by using a passphrase If you use a passphrase, the address' - ' is called a deterministic; address The Random Number option is' - ' selected by default but deterministic addresses have several pros' - ' and cons:') - log_text2 = ('If talk about pros You can recreate your addresses on any computer' - ' from memory, You need-not worry about backing up your keys.dat file' - ' as long as you can remember your passphrase and aside talk about cons' - ' You must remember (or write down) your You must remember the address' - ' version number and the stream number along with your passphrase If you' - ' choose a weak passphrase and someone on the Internet can brute-force it,' - ' they can read your messages and send messages as you') - - -class NetworkStat(Screen): - """NetworkStat class for kivy Ui""" - - text_variable_1 = StringProperty( - '{0}::{1}'.format('Total Connections', '0')) - text_variable_2 = StringProperty( - 'Processed {0} per-to-per messages'.format('0')) - text_variable_3 = StringProperty( - 'Processed {0} brodcast messages'.format('0')) - text_variable_4 = StringProperty( - 'Processed {0} public keys'.format('0')) - text_variable_5 = StringProperty( - 'Processed {0} object to be synced'.format('0')) - - def __init__(self, *args, **kwargs): - """Init method for network stat""" - super(NetworkStat, self).__init__(*args, **kwargs) - Clock.schedule_interval(self.init_ui, 1) - - def init_ui(self, dt=0): - """Clock Schdule for method networkstat screen""" - import network.stats - 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(state.numberOfMessagesProcessed)) - self.text_variable_3 = 'Processed {0} brodcast messages'.format( - str(state.numberOfBroadcastsProcessed)) - self.text_variable_4 = 'Processed {0} public keys'.format( - str(state.numberOfPubkeysProcessed)) - self.text_variable_5 = '{0} object to be synced'.format( - len(objectracker.missingObjects)) + disabled = True + divider = None + theme_text_color = 'Secondary' class ContentNavigationDrawer(BoxLayout): @@ -1315,582 +191,19 @@ class ContentNavigationDrawer(BoxLayout): self.ids.btn.is_open = False -class Random(Screen): - """Random Screen class for Ui""" - - is_active = BooleanProperty(False) - checked = StringProperty("") - - def generateaddress(self, navApp): - """Method for Address Generator""" - # entered_label = str(self.ids.lab.text).strip() - entered_label = str(self.ids.add_random_bx.children[0].ids.lab.text).strip() - if not entered_label: - self.ids.add_random_bx.children[0].ids.lab.focus = True - streamNumberForAddress = 1 - eighteenByteRipe = False - nonceTrialsPerByte = 1000 - payloadLengthExtraBytes = 1000 - lables = [BMConfigParser().get(obj, 'label') - for obj in BMConfigParser().addresses()] - if entered_label and entered_label not in lables: - toast('Address Creating...') - queues.addressGeneratorQueue.put(( - 'createRandomAddress', 4, streamNumberForAddress, entered_label, 1, - "", eighteenByteRipe, nonceTrialsPerByte, - payloadLengthExtraBytes)) - self.parent.parent.ids.toolbar.opacity = 1 - self.parent.parent.ids.toolbar.disabled = False - state.kivyapp.loadMyAddressScreen(True) - self.manager.current = 'myaddress' - Clock.schedule_once(self.address_created_callback, 6) - - def address_created_callback(self, dt=0): - """New address created""" - state.kivyapp.loadMyAddressScreen(False) - state.kivyapp.root.ids.sc10.ids.ml.clear_widgets() - state.kivyapp.root.ids.sc10.is_add_created = True - state.kivyapp.root.ids.sc10.init_ui() - self.reset_address_spinner() - toast('New address created') - - def reset_address_spinner(self): - """reseting spinner address and UI""" - addresses = [addr for addr in BMConfigParser().addresses() - if BMConfigParser().get(str(addr), 'enabled') == 'true'] - self.manager.parent.ids.content_drawer.ids.btn.values = [] - self.manager.parent.ids.sc3.children[1].ids.btn.values = [] - self.manager.parent.ids.content_drawer.ids.btn.values = addresses - self.manager.parent.ids.sc3.children[1].ids.btn.values = addresses - - @staticmethod - def add_validation(instance): - """Checking validation at address creation time""" - entered_label = str(instance.text.strip()) - lables = [BMConfigParser().get(obj, 'label') - for obj in BMConfigParser().addresses()] - if entered_label in lables: - instance.error = True - instance.helper_text = 'it is already exist you'\ - ' can try this Ex. ( {0}_1, {0}_2 )'.format( - entered_label) - elif entered_label: - instance.error = False - else: - instance.error = False - instance.helper_text = 'This field is required' - - def reset_address_label(self, n): - """Resetting address labels""" - if not self.ids.add_random_bx.children: - self.ids.add_random_bx.add_widget(RandomBoxlayout()) +class BadgeText(IRightBodyTouch, MDLabel): + """BadgeText class for kivy Ui""" -class Sent(Screen): - """Sent Screen class for kivy Ui""" - - queryreturn = ListProperty() - has_refreshed = True - account = StringProperty() +class CustomSpinner(Spinner): + """CustomSpinner class for kivy Ui""" def __init__(self, *args, **kwargs): - """Association with the screen""" - super(Sent, 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 sent accounts""" - self.loadSent() - print(dt) - - def loadSent(self, where="", what=""): - """Load Sent list for Sent messages""" - self.account = state.association - if state.searcing_text: - self.ids.scroll_y.scroll_y = 1.0 - where = ['subject', 'message'] - what = state.searcing_text - xAddress = 'fromaddress' - data = [] - self.ids.tag_label.text = '' - self.sentDataQuery(xAddress, where, what) - if self.queryreturn: - self.ids.tag_label.text = 'Sent' - self.set_sentCount(state.sent_count) - for mail in self.queryreturn: - data.append({ - 'text': mail[1].strip(), - 'secondary_text': (mail[2][:50] + '........' if len( - mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( - '\t', '').replace(' ', ''), - 'ackdata': mail[5], 'senttime': mail[6]},) - self.set_mdlist(data, 0) - self.has_refreshed = True - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - self.set_sentCount('0') - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="No message found!" if state.searcing_text - else "yet no message for this account!!!!!!!!!!!!!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def sentDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): - """This method is used to retrieving data from sent table""" - self.queryreturn = kivy_helper_search.search_sql( - xAddress, - self.account, - 'sent', - where, - what, - False, - start_indx, - end_indx) - - def set_mdlist(self, data, set_index=0): - """This method is used to create the mdList""" - total_sent_msg = len(self.ids.ml.children) - for item in data: - meny = TwoLineAvatarIconListItem( - text=item['text'], secondary_text=item['secondary_text'], - theme_text_color='Custom', - text_color=ThemeClsColor) - meny._txt_right_pad = dp(70) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/text_images/{}.png'.format( - avatarImageFirstLetter(item['secondary_text'].strip())))) - meny.bind(on_press=partial(self.sent_detail, item['ackdata'])) - meny.add_widget(AddTimeWidget(item['senttime'])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete, item['ackdata'])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - # ach_btn = Button(text='Achieve') - # ach_btn.background_color = (0, 1, 0, 1) - # ach_btn.bind(on_press=partial(self.archive, item['ackdata'])) - # carousel.add_widget(ach_btn) - carousel.index = 1 - self.ids.ml.add_widget(carousel, index=set_index) - updated_msgs = len(self.ids.ml.children) - self.has_refreshed = True if total_sent_msg != updated_msgs else False - - def update_sent_messagelist(self): - """This method is used to update screen when new mail is sent""" - self.account = state.association - if len(self.ids.ml.children) < 3: - self.ids.ml.clear_widgets() - self.loadSent() - if state.association == state.check_sent_acc: - total_sent = int(state.sent_count) + 1 - state.sent_count = str(int(state.sent_count) + 1) - self.set_sentCount(total_sent) - else: - total_sent = int(state.sent_count) - else: - data = [] - self.sentDataQuery('fromaddress', '', '', 0, 1) - if state.association == state.check_sent_acc: - total_sent = int(state.sent_count) + 1 - state.sent_count = str(int(state.sent_count) + 1) - self.set_sentCount(total_sent) - else: - total_sent = int(state.sent_count) - for mail in self.queryreturn: - data.append({ - 'text': mail[1].strip(), - 'secondary_text': (mail[2][:50] + '........' if len( - mail[2]) >= 50 else (mail[2] + ',' + mail[3])[0:50] + '........').replace( - '\t', '').replace(' ', ''), - 'ackdata': mail[5], 'senttime': mail[6]}) - self.set_mdlist(data, total_sent - 1) - if state.msg_counter_objs and state.association == ( - state.check_sent_acc): - state.all_count = str(int(state.all_count) + 1) - state.msg_counter_objs.allmail_cnt.badge_text = state.all_count - state.check_sent_acc = None - - def check_scroll_y(self, instance, somethingelse): - """Load data on scroll down""" - if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: - self.ids.scroll_y.scroll_y = 0.06 - total_sent_msg = len(self.ids.ml.children) - self.update_sent_screen_on_scroll(total_sent_msg) - - def update_sent_screen_on_scroll(self, total_sent_msg, where="", what=""): - """This method is used to load more data on scroll down""" - if state.searcing_text: - where = ['subject', 'message'] - what = state.searcing_text - self.sentDataQuery('fromaddress', where, what, total_sent_msg, 5) - data = [] - for mail in self.queryreturn: - data.append({ - 'text': mail[1].strip(), - 'secondary_text': mail[2][:50] + '........' if len( - mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace( - '\n', ''))[0:50] + '........', - 'ackdata': mail[5], 'senttime': mail[6]}) - self.set_mdlist(data, 0) - - @staticmethod - def set_sentCount(total_sent): - """Set the total no. of sent message count""" - src_mng_obj = state.kivyapp.root.ids.content_drawer.ids.send_cnt - state.kivyapp.root.ids.content_drawer.ids.send_cnt.ids.badge_txt.text - if state.association: - src_mng_obj.ids.badge_txt.text = showLimitedCnt(int(total_sent)) - else: - src_mng_obj.ids.badge_txt.text = '0' - - def sent_detail(self, ackdata, *args): - """Load sent mail details""" - state.detailPageType = 'sent' - state.mail_id = ackdata - if self.manager: - src_mng_obj = self.manager - else: - src_mng_obj = self.parent.parent - src_mng_obj.screens[13].clear_widgets() - src_mng_obj.screens[13].add_widget(MailDetail()) - src_mng_obj.current = 'mailDetail' - - def delete(self, data_index, instance, *args): - """Delete sent mail from sent mail listing""" - msg_count_objs = self.parent.parent.ids.content_drawer.ids - if int(state.sent_count) > 0: - msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(state.sent_count) - 1) - msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(state.trash_count) + 1) - msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count) - 1) - state.sent_count = str(int(state.sent_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) - state.all_count = str(int(state.all_count) - 1) - if int(state.sent_count) <= 0: - self.ids.tag_label.text = '' - sqlExecute( - "UPDATE sent SET folder = 'trash'" - " WHERE ackdata = ?;", data_index) - self.ids.ml.remove_widget(instance.parent.parent) - 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 ackdata = ?;", data_index) - self.ids.ml.remove_widget(instance.parent.parent) - self.update_trash() - - def update_trash(self): - """Update trash screen mails which is deleted from inbox""" - try: - self.parent.screens[4].clear_widgets() - self.parent.screens[4].add_widget(Trash()) - 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 class for kivy Ui""" - - trash_messages = ListProperty() - has_refreshed = True - # delete_index = StringProperty() - table_name = StringProperty() - - def __init__(self, *args, **kwargs): - """Trash method, delete sent message and add in Trash""" - super(Trash, self).__init__(*args, **kwargs) - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock Schdule for method trash screen""" - if state.association == '': - if BMConfigParser().addresses(): - state.association = BMConfigParser().addresses()[0] - self.ids.tag_label.text = '' - self.trashDataQuery(0, 20) - if self.trash_messages: - self.ids.tag_label.text = 'Trash' - # src_mng_obj = state.kivyapp.root.children[2].children[0].ids - # src_mng_obj.trash_cnt.badge_text = state.trash_count - self.set_TrashCnt(state.trash_count) - self.set_mdList() - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - self.set_TrashCnt('0') - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="yet no trashed message for this account!!!!!!!!!!!!!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def trashDataQuery(self, start_indx, end_indx): - """Trash message query""" - self.trash_messages = sqlQuery( - "SELECT toaddress, fromaddress, subject, message," - " folder ||',' || 'sent' as folder, ackdata As" - " id, DATE(senttime) As actionTime, senttime as msgtime FROM sent" - " WHERE folder = 'trash' and fromaddress = '{0}' UNION" - " SELECT toaddress, fromaddress, subject, message," - " folder ||',' || 'inbox' as folder, msgid As id," - " DATE(received) As actionTime, received as msgtime FROM inbox" - " WHERE folder = 'trash' and toaddress = '{0}'" - " ORDER BY actionTime DESC limit {1}, {2}".format( - state.association, start_indx, end_indx)) - - def set_TrashCnt(self, Count): # pylint: disable=no-self-use - """This method is used to set trash message count""" - trashCnt_obj = state.kivyapp.root.ids.content_drawer.ids.trash_cnt - trashCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) - - def set_mdList(self): - """This method is used to create the mdlist""" - total_trash_msg = len(self.ids.ml.children) - for item in self.trash_messages: - subject = item[2].decode() if isinstance(item[2], bytes) else item[2] - body = item[3].decode() if isinstance(item[3], bytes) else item[3] - meny = TwoLineAvatarIconListItem( - text=item[1], - secondary_text=(item[2][:50] + '........' if len( - subject) >= 50 else (subject + ',' + body)[0:50] + '........').replace('\t', '').replace(' ', ''), - theme_text_color='Custom', - text_color=ThemeClsColor) - meny._txt_right_pad = dp(70) - img_latter = state.imageDir + '/text_images/{}.png'.format( - subject[0].upper() if (subject[0].upper() >= 'A' and subject[0].upper() <= 'Z') else '!') - meny.add_widget(AvatarSampleWidget(source=img_latter)) - meny.add_widget(AddTimeWidget(item[7])) - meny.add_widget(chipTag('inbox 'if 'inbox' in item[4] else 'sent')) - 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], item[4])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) - self.has_refreshed = True if total_trash_msg != len( - self.ids.ml.children) else False - - def check_scroll_y(self, instance, somethingelse): - """Load data on scroll""" - if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: - self.ids.scroll_y.scroll_y = 0.06 - total_trash_msg = len(self.ids.ml.children) - self.update_trash_screen_on_scroll(total_trash_msg) - - def update_trash_screen_on_scroll(self, total_trash_msg): - """Load more data on scroll down""" - self.trashDataQuery(total_trash_msg, 5) - self.set_mdList() - - def delete_permanently(self, data_index, folder, instance, *args): - """Deleting trash mail permanently""" - self.table_name = folder.split(',')[1] - self.delete_index = data_index - self.delete_confirmation() - - def callback_for_screen_load(self, dt=0): - """This methos is for loading screen""" - self.ids.ml.clear_widgets() - self.init_ui(0) - self.children[1].active = False - toast('Message is permanently deleted') - - def delete_confirmation(self): - """Show confirmation delete popup""" - width = .8 if platform == 'android' else .55 - dialog_box = MDDialog( - text='Are you sure you want to delete this' - ' message permanently from trash?', - size_hint=(width, .25), - buttons=[ - MDFlatButton( - text="Yes", on_release=lambda x: callback_for_delete_msg("Yes") - ), - MDFlatButton( - text="No", on_release=lambda x: callback_for_delete_msg("No"), - ), - ],) - dialog_box.open() - - def callback_for_delete_msg(text_item, *arg): - """Getting the callback of alert box""" - if text_item == 'Yes': - self.delete_message_from_trash() - else: - toast(text_item) - dialog_box.dismiss() - - # def callback_for_delete_msg(self, text_item, *arg): - # """Getting the callback of alert box""" - # if text_item == 'Yes': - # self.delete_message_from_trash() - # else: - # toast(text_item) - - def delete_message_from_trash(self): - """Deleting message from trash""" - self.children[1].active = True - if self.table_name == 'inbox': - sqlExecute( - "DELETE FROM inbox WHERE msgid = ?;", self.delete_index) - elif self.table_name == 'sent': - sqlExecute( - "DELETE FROM sent WHERE ackdata = ?;", self.delete_index) - if int(state.trash_count) > 0: - # msg_count_objs.trash_cnt.badge_text = str( - # int(state.trash_count) - 1) - self.set_TrashCnt(int(state.trash_count) - 1) - state.trash_count = str(int(state.trash_count) - 1) - Clock.schedule_once(self.callback_for_screen_load, 1) - - -class Page(Screen): - """Page Screen class for kivy Ui""" - - -class Create(Screen): - """Creates Screen class for kivy Ui""" - - def __init__(self, **kwargs): - """Getting Labels and address from addressbook""" - super(Create, self).__init__(**kwargs) - Window.softinput_mode = "below_target" - widget_1 = DropDownWidget() - widget_1.ids.txt_input.word_list = [ - addr[1] for addr in sqlQuery( - "SELECT label, address from addressbook")] - widget_1.ids.txt_input.starting_no = 2 - self.add_widget(widget_1) - self.children[0].ids.id_scroll.bind(scroll_y=self.check_scroll_y) - - def check_scroll_y(self, instance, somethingelse): - """show data on scroll down""" - if self.children[1].ids.btn.is_open: - self.children[1].ids.btn.is_open = False - - -class Setting(Screen): - """Setting Screen for kivy Ui""" - exp_text = "By default, if you send a message to someone and he is offline for more than two days, Bitmessage will\ - send the message again after an additional two days. This will be continued with exponential backoff\ - forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them.\ - Here you may change that behavior by having Bitmessage give up after a certain number of days \ - or months." - - # languages = { - # 'ar': 'Arabic', - # 'cs': 'Czech', - # 'da': 'Danish', - # 'de': 'German', - # 'en': 'English', - # 'eo': 'Esperanto', - # 'fr': 'French', - # 'it': 'Italian', - # 'ja': 'Japanese', - # 'nl': 'Dutch', - # 'no': 'Norwegian', - # 'pl': 'Polish', - # 'pt': 'Portuguese', - # 'ru': 'Russian', - # 'sk': 'Slovak', - # 'zh': 'Chinese', - # } - # newlocale = None - - # def __init__(self, *args, **kwargs): - # """Trash method, delete sent message and add in Trash""" - # super(Setting, self).__init__(*args, **kwargs) - # if self.newlocale is None: - # self.newlocale = l10n.getTranslationLanguage() - # lang = locale.normalize(l10n.getTranslationLanguage()) - # langs = [ - # lang.split(".")[0] + "." + l10n.encoding, - # lang.split(".")[0] + "." + 'UTF-8', - # lang - # ] - # if 'win32' in platform or 'win64' in platform: - # langs = [l10n.getWindowsLocale(lang)] - # for lang in langs: - # try: - # l10n.setlocale(locale.LC_ALL, lang) - # if 'win32' not in platform and 'win64' not in platform: - # l10n.encoding = locale.nl_langinfo(locale.CODESET) - # else: - # l10n.encoding = locale.getlocale()[1] - # logger.info("Successfully set locale to %s", lang) - # break - # except: - # logger.error("Failed to set locale to %s", lang, exc_info=True) - - # Clock.schedule_once(self.init_ui, 0) - - # def init_ui(self, dt=0): - # """Initialization for Ui""" - # if self.newlocale is None: - # self.newlocale = l10n.getTranslationLanguage() - # # state.kivyapp.tr = Lang(self.newlocale) - # state.kivyapp.tr = Lang(self.newlocale) - # menu_items = [{"text": f"{i}"} for i in self.languages.values()] - # self.menu = MDDropdownMenu( - # caller=self.ids.dropdown_item, - # items=menu_items, - # position="auto", - # width_mult=3.5, - # ) - # self.menu.bind(on_release=self.set_item) - - # def set_item(self, instance_menu, instance_menu_item): - # # import pdb;pdb.set_trace() - # self.ids.dropdown_item.set_item(instance_menu_item.text) - # instance_menu.dismiss() - - # def change_language(self): - # lang = self.ids.dropdown_item.current_item - # for k, v in self.languages.items(): - # if v == lang: - # BMConfigParser().set('bitmessagesettings', 'userlocale', k) - # BMConfigParser().save() - # state.kivyapp.tr = Lang(k) - # self.children[0].active = True - # Clock.schedule_once(partial(self.language_callback, k), 1) - - # def language_callback(self, lang, dt=0): - # self.children[0].active = False - # state.kivyapp.tr = Lang(lang) - # toast('Language changed') + """Method used for setting size of spinner""" + super(CustomSpinner, self).__init__(*args, **kwargs) + self.dropdown_cls.max_height = Window.size[1] / 3 + self.values = list(addr for addr in BMConfigParser().addresses() + if BMConfigParser().get(str(addr), 'enabled') == 'true') class NavigateApp(MDApp): @@ -1917,9 +230,16 @@ class NavigateApp(MDApp): def build(self): """Method builds the widget""" - for kv_file in KVFILES: - Builder.load_file(os.path.join(os.path.dirname(__file__), "kv/{}.kv").format(kv_file)) - self.obj_1 = AddressBook() + print('data_screens: ', data_screens) + for kv in data_screens: + Builder.load_file( + os.path.join( + os.path.dirname(__file__), + "kv", + f"{all_data[kv]['kv_string']}.kv", + ) + ) + # self.obj_1 = AddressBook() kivysignalthread = UIkivySignaler() kivysignalthread.daemon = True kivysignalthread.start() @@ -2244,6 +564,7 @@ class NavigateApp(MDApp): def clear_composer(self): """If slow down, the new composer edit screen""" self.set_navbar_for_composer() + # import pdb;pdb.set_trace() composer_obj = self.root.ids.sc3.children[1].ids composer_obj.ti.text = '' composer_obj.btn.text = 'Select' @@ -2484,12 +805,13 @@ class NavigateApp(MDApp): """This method is used for loading screen on every click""" if instance.text == 'Inbox': self.root.ids.scr_mngr.current = 'inbox' - self.root.ids.sc1.children[1].active = True + # self.root.ids.sc1.children[1].active = True elif instance.text == 'All Mails': self.root.ids.scr_mngr.current = 'allmails' try: self.root.ids.sc17.children[1].active = True except Exception: + # import pdb;pdb.set_trace() self.root.ids.sc17.children[0].children[1].active = True Clock.schedule_once(partial(self.load_screen_callback, instance), 1) @@ -2633,1008 +955,5 @@ class NavigateApp(MDApp): instance.open() -class GrashofPopup(BoxLayout): - """GrashofPopup class for kivy Ui""" - - valid = False - - def __init__(self, **kwargs): - """Grash of pop screen settings""" - super(GrashofPopup, self).__init__(**kwargs) - - def checkAddress_valid(self, instance): - """Checking address is valid or not""" - my_addresses = ( - state.kivyapp.root.ids.content_drawer.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.' - elif entered_text: - text = self.addressChanged(entered_text) - - if entered_text in my_addresses or entered_text in add_book: - self.ids.address.error = True - self.ids.address.helper_text = text - elif entered_text and self.valid: - self.ids.address.error = False - elif entered_text: - self.ids.address.error = True - self.ids.address.helper_text = text - else: - self.ids.address.error = False - self.ids.address.helper_text = 'This field is required' - - def checkLabel_valid(self, instance): - """Checking address label is unique or not""" - entered_label = instance.text.strip() - addr_labels = [labels[0] for labels in kivy_helper_search.search_sql( - folder="addressbook")] - if entered_label in addr_labels: - self.ids.label.error = True - self.ids.label.helper_text = 'label name already exists.' - elif entered_label: - self.ids.label.error = False - else: - self.ids.label.error = False - self.ids.label.helper_text = 'This field is required' - - def _onSuccess(self, addressVersion, streamNumber, ripe): - pass - - def addressChanged(self, addr): - """Address validation callback, performs validation and gives feedback""" - status, addressVersion, streamNumber, ripe = decodeAddress( - str(addr)) - self.valid = status == 'success' - if self.valid: - text = "Address is valid." - self._onSuccess(addressVersion, streamNumber, ripe) - elif status == 'missingbm': - text = "The address should start with ''BM-''" - elif status == 'checksumfailed': - text = ( - "The address is not typed or copied correctly" - # " (the checksum failed)." - ) - elif status == 'versiontoohigh': - text = ( - "The version number of this address is higher than this" - " software can support. Please upgrade Bitmessage.") - elif status == 'invalidcharacters': - text = "The address contains invalid characters." - elif status == 'ripetooshort': - text = "Some data encoded in the address is too short." - elif status == 'ripetoolong': - text = "Some data encoded in the address is too long." - elif status == 'varintmalformed': - text = "Some data encoded in the address is malformed." - return text - - -class InfoLayout(BoxLayout, RectangularElevationBehavior): - """InfoLayout class for kivy Ui""" - - -class AvatarSampleWidget(ILeftBody, Image): - """AvatarSampleWidget class for kivy Ui""" - - -class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): - """IconLeftSampleWidget class for kivy Ui""" - - -class IconRightSampleWidget(IRightBodyTouch, MDIconButton): - """IconRightSampleWidget class for kivy Ui""" - - -class TimeTagRightSampleWidget(IRightBodyTouch, MDLabel): - """TimeTagRightSampleWidget class for Ui""" - - -class ToggleBtn(IRightBodyTouch, MDSwitch): - """ToggleBtn class for kivy Ui""" - - -class CheckboxLeftSampleWidget(ILeftBodyTouch, MDCheckbox): - """CheckboxLeftSampleWidget class for kivy Ui""" - - -class MailDetail(Screen): # pylint: disable=too-many-instance-attributes - """MailDetail Screen class for kivy Ui""" - - to_addr = StringProperty() - from_addr = StringProperty() - subject = StringProperty() - message = StringProperty() - status = StringProperty() - page_type = StringProperty() - time_tag = StringProperty() - avatarImg = StringProperty() - - def __init__(self, *args, **kwargs): - """Mail Details method""" - super(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' or state.detailPageType == 'draft': - data = sqlQuery( - "select toaddress, fromaddress, subject, message, status," - " ackdata, senttime from sent where ackdata = ?;", state.mail_id) - state.status = self - state.ackdata = data[0][5] - self.assign_mail_details(data) - state.kivyapp.set_mail_detail_header() - elif state.detailPageType == 'inbox': - data = sqlQuery( - "select toaddress, fromaddress, subject, message, received from inbox" - " where msgid = ?;", state.mail_id) - self.assign_mail_details(data) - state.kivyapp.set_mail_detail_header() - - def assign_mail_details(self, data): - """Assigning mail details""" - subject = data[0][2].decode() if isinstance(data[0][2], bytes) else data[0][2] - body = data[0][3].decode() if isinstance(data[0][2], bytes) else data[0][3] - self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' ' - self.from_addr = data[0][1] - - self.subject = subject.capitalize( - ) if subject.capitalize() else '(no subject)' - self.message = body - if len(data[0]) == 7: - self.status = data[0][4] - self.time_tag = ShowTimeHistoy(data[0][4]) if state.detailPageType == 'inbox' else ShowTimeHistoy(data[0][6]) - self.avatarImg = state.imageDir + '/avatar.png' if state.detailPageType == 'draft' else ( - state.imageDir + '/text_images/{0}.png'.format(avatarImageFirstLetter(self.subject.strip()))) - self.timeinseconds = data[0][4] if state.detailPageType == 'inbox' else data[0][6] - - def delete_mail(self): - """Method for mail delete""" - msg_count_objs = state.kivyapp.root.ids.content_drawer.ids - state.searcing_text = '' - self.children[0].children[0].active = True - if state.detailPageType == 'sent': - state.kivyapp.root.ids.sc4.ids.sent_search.ids.search_field.text = '' - sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE" - " ackdata = ?;", state.mail_id) - msg_count_objs.send_cnt.ids.badge_txt.text = str(int(state.sent_count) - 1) - state.sent_count = str(int(state.sent_count) - 1) - self.parent.screens[3].ids.ml.clear_widgets() - self.parent.screens[3].loadSent(state.association) - elif state.detailPageType == 'inbox': - state.kivyapp.root.ids.sc1.ids.inbox_search.ids.search_field.text = '' - sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE" - " msgid = ?;", state.mail_id) - msg_count_objs.inbox_cnt.ids.badge_txt.text = str( - int(state.inbox_count) - 1) - state.inbox_count = str(int(state.inbox_count) - 1) - self.parent.screens[0].ids.ml.clear_widgets() - self.parent.screens[0].loadMessagelist(state.association) - - elif state.detailPageType == 'draft': - sqlExecute("DELETE FROM sent WHERE ackdata = ?;", state.mail_id) - msg_count_objs.draft_cnt.ids.badge_txt.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()) - - if state.detailPageType != 'draft': - msg_count_objs.trash_cnt.ids.badge_txt.text = str( - int(state.trash_count) + 1) - msg_count_objs.allmail_cnt.ids.badge_txt.text = str( - int(state.all_count) - 1) - state.trash_count = str(int(state.trash_count) + 1) - state.all_count = str(int(state.all_count) - 1) if int(state.all_count) else '0' - 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()) - Clock.schedule_once(self.callback_for_delete, 4) - - def callback_for_delete(self, dt=0): - """Delete method from allmails""" - if state.detailPageType: - self.children[0].children[0].active = False - state.kivyapp.set_common_header() - self.parent.current = 'allmails' \ - if state.is_allmail else state.detailPageType - state.detailPageType = '' - toast('Deleted') - - def inbox_reply(self): - """Reply inbox messages""" - state.in_composer = True - data = sqlQuery( - "select toaddress, fromaddress, subject, message, received from inbox where" - " msgid = ?;", state.mail_id) - composer_obj = self.parent.screens[2].children[1].ids - composer_obj.ti.text = data[0][0] - composer_obj.btn.text = data[0][0] - composer_obj.txt_input.text = data[0][1] - split_subject = data[0][2].split('Re:', 1) - composer_obj.subject.text = 'Re: ' + (split_subject[1] if len(split_subject) > 1 else split_subject[0]) - time_obj = datetime.fromtimestamp(int(data[0][4])) - time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") - # sender_name = BMConfigParser().get(data[0][1], 'label') - sender_name = data[0][1] - composer_obj.body.text = ( - '\n\n --------------On ' + time_tag + ', ' + sender_name + ' wrote:--------------\n' + data[0][3]) - composer_obj.body.focus = True - composer_obj.body.cursor = (0, 0) - state.kivyapp.root.ids.sc3.children[1].ids.rv.data = '' - self.parent.current = 'create' - state.kivyapp.set_navbar_for_composer() - - def write_msg(self, navApp): - """Write on draft mail""" - state.send_draft_mail = state.mail_id - data = sqlQuery( - "select toaddress, fromaddress, subject, message from sent where" - " ackdata = ?;", state.mail_id) - composer_ids = ( - self.parent.parent.ids.sc3.children[1].ids) - composer_ids.ti.text = data[0][1] - composer_ids.btn.text = data[0][1] - composer_ids.txt_input.text = data[0][0] - composer_ids.subject.text = data[0][2] if data[0][2] != '(no subject)' else '' - composer_ids.body.text = data[0][3] - self.parent.current = 'create' - navApp.set_navbar_for_composer() - - def detailedPopup(self): - """Detailed popup""" - obj = SenderDetailPopup() - obj.open() - arg = (self.to_addr, self.from_addr, self.timeinseconds) - obj.assignDetail(*arg) - - @staticmethod - def callback_for_menu_items(text_item, *arg): - """Callback of alert box""" - toast(text_item) - - -class MyaddDetailPopup(BoxLayout): - """MyaddDetailPopup class for kivy Ui""" - - address_label = StringProperty() - address = StringProperty() - - def __init__(self, **kwargs): - """My Address Details screen setting""" - super(MyaddDetailPopup, self).__init__(**kwargs) - - def send_message_from(self): - """Method used to fill from address of composer autofield""" - state.kivyapp.set_navbar_for_composer() - window_obj = state.kivyapp.root.ids - window_obj.sc3.children[1].ids.ti.text = self.address - window_obj.sc3.children[1].ids.btn.text = self.address - window_obj.sc3.children[1].ids.txt_input.text = '' - window_obj.sc3.children[1].ids.subject.text = '' - window_obj.sc3.children[1].ids.body.text = '' - window_obj.scr_mngr.current = 'create' - self.parent.parent.parent.dismiss() - - # @staticmethod - def close_pop(self): - """Pop is Canceled""" - self.parent.parent.parent.dismiss() - toast('Canceled') - - -class AddbookDetailPopup(BoxLayout): - """AddbookDetailPopup class for kivy Ui""" - - address_label = StringProperty() - address = StringProperty() - - def __init__(self, **kwargs): - """Set screen of address detail page""" - super(AddbookDetailPopup, self).__init__(**kwargs) - - def checkLabel_valid(self, instance): - """Checking address label is unique of not""" - entered_label = str(instance.text.strip()) - address_list = kivy_helper_search.search_sql(folder="addressbook") - addr_labels = [labels[0] for labels in address_list] - add_dict = dict(address_list) - if self.address and entered_label in addr_labels \ - and self.address != add_dict[entered_label]: - self.ids.add_label.error = True - self.ids.add_label.helper_text = 'label name already exists.' - elif entered_label: - self.ids.add_label.error = False - else: - self.ids.add_label.error = False - self.ids.add_label.helper_text = 'This field is required' - - -class ShowQRCode(Screen): - """ShowQRCode Screen class for kivy Ui""" - address = StringProperty() - - def qrdisplay(self, instasnce, address): - """Method used for showing QR Code""" - self.ids.qr.clear_widgets() - state.kivyapp.set_toolbar_for_QrCode() - try: - from kivy.garden.qrcode import QRCodeWidget - except Exception: - from kivy_garden.qrcode import QRCodeWidget - self.address = address - self.ids.qr.add_widget(QRCodeWidget(data=address)) - self.ids.qr.children[0].show_border = False - instasnce.parent.parent.parent.dismiss() - toast('Show QR code') - - -class Draft(Screen): - """Draft screen class for kivy Ui""" - - data = ListProperty() - account = StringProperty() - queryreturn = ListProperty() - has_refreshed = True - - def __init__(self, *args, **kwargs): - """Method used for storing draft messages""" - super(Draft, self).__init__(*args, **kwargs) - if 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""" - self.account = state.association - self.loadDraft() - - def loadDraft(self, where="", what=""): - """Load draft list for Draft messages""" - xAddress = 'fromaddress' - self.ids.tag_label.text = '' - self.draftDataQuery(xAddress, where, what) - # if state.msg_counter_objs: - # state.msg_counter_objs.draft_cnt.children[0].children[0].text = showLimitedCnt(len(self.queryreturn)) - if self.queryreturn: - self.ids.tag_label.text = 'Draft' - self.set_draftCnt(state.draft_count) - self.set_mdList() - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - self.set_draftCnt('0') - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def draftDataQuery(self, xAddress, where, what, start_indx=0, end_indx=20): - """This methosd is for retrieving draft messages""" - self.queryreturn = kivy_helper_search.search_sql( - xAddress, self.account, "draft", where, what, - False, start_indx, end_indx) - - def set_draftCnt(self, Count): # pylint: disable=no-self-use - """This method set the count of draft mails""" - draftCnt_obj = state.kivyapp.root.ids.content_drawer.ids.draft_cnt - draftCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) - - def set_mdList(self): - """This method is used to create mdlist""" - data = [] - total_draft_msg = len(self.ids.ml.children) - for mail in self.queryreturn: - third_text = mail[3].replace('\n', ' ') - data.append({ - 'text': mail[1].strip(), - 'secondary_text': mail[2][:10] + '...........' if len( - mail[2]) > 10 else mail[2] + '\n' + " " + ( - third_text[:25] + '...!') if len( - third_text) > 25 else third_text, - 'ackdata': mail[5], 'senttime': mail[6]}) - for item in data: - meny = TwoLineAvatarIconListItem( - text='Draft', secondary_text=item['text'], - theme_text_color='Custom', - text_color=ThemeClsColor) - meny._txt_right_pad = dp(70) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/avatar.png')) - meny.bind(on_press=partial( - self.draft_detail, item['ackdata'])) - meny.add_widget(AddTimeWidget(item['senttime'])) - carousel = Carousel(direction='right') - carousel.height = meny.height - carousel.size_hint_y = None - carousel.ignore_perpendicular_swipes = True - carousel.data_index = 0 - carousel.min_move = 0.2 - del_btn = Button(text='Delete') - del_btn.background_normal = '' - del_btn.background_color = (1, 0, 0, 1) - del_btn.bind(on_press=partial(self.delete_draft, item['ackdata'])) - carousel.add_widget(del_btn) - carousel.add_widget(meny) - carousel.index = 1 - self.ids.ml.add_widget(carousel) - updated_msg = len(self.ids.ml.children) - self.has_refreshed = True if total_draft_msg != updated_msg else False - - def check_scroll_y(self, instance, somethingelse): - """Load data on scroll""" - if self.ids.scroll_y.scroll_y <= -0.0 and self.has_refreshed: - self.ids.scroll_y.scroll_y = 0.06 - total_draft_msg = len(self.ids.ml.children) - self.update_draft_screen_on_scroll(total_draft_msg) - - def update_draft_screen_on_scroll(self, total_draft_msg, where='', what=''): - """Load more data on scroll down""" - self.draftDataQuery('fromaddress', where, what, total_draft_msg, 5) - self.set_mdList() - - def draft_detail(self, ackdata, *args): - """Show draft Details""" - state.detailPageType = 'draft' - state.mail_id = ackdata - 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): - """Delete draft message permanently""" - sqlExecute("DELETE FROM sent WHERE ackdata = ?;", data_index) - if int(state.draft_count) > 0: - state.draft_count = str(int(state.draft_count) - 1) - self.set_draftCnt(state.draft_count) - if int(state.draft_count) <= 0: - # self.ids.identi_tag.children[0].text = '' - self.ids.tag_label.text = '' - self.ids.ml.remove_widget(instance.parent.parent) - toast('Deleted') - - @staticmethod - def draft_msg(src_object): - """Save draft mails""" - composer_object = state.kivyapp.root.ids.sc3.children[1].ids - fromAddress = str(composer_object.ti.text) - toAddress = str(composer_object.txt_input.text) - subject = str(composer_object.subject.text) - message = str(composer_object.body.text) - encoding = 3 - sendMessageToPeople = True - if sendMessageToPeople: - streamNumber, ripe = decodeAddress(toAddress)[2:] - from addresses import addBMIfNotPresent - toAddress = addBMIfNotPresent(toAddress) - stealthLevel = BMConfigParser().safeGetInt( - 'bitmessagesettings', 'ackstealthlevel') - from helper_ackPayload import genAckPayload - ackdata = genAckPayload(streamNumber, stealthLevel) - sqlExecute( - '''INSERT INTO sent VALUES - (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, - int(time.time()), - int(time.time()), - 0, - 'msgqueued', - 0, - 'draft', - encoding, - BMConfigParser().safeGetInt('bitmessagesettings', 'ttl')) - state.msg_counter_objs = src_object.children[2].children[0].ids - state.draft_count = str(int(state.draft_count) + 1) \ - if state.association == fromAddress else state.draft_count - src_object.ids.sc16.clear_widgets() - src_object.ids.sc16.add_widget(Draft()) - toast('Save draft') - return - - -class CustomSpinner(Spinner): - """CustomSpinner class for kivy Ui""" - - def __init__(self, *args, **kwargs): - """Method used for setting size of spinner""" - super(CustomSpinner, self).__init__(*args, **kwargs) - self.dropdown_cls.max_height = Window.size[1] / 3 - self.values = list(addr for addr in BMConfigParser().addresses() - if BMConfigParser().get(str(addr), 'enabled') == 'true') - - -class Allmails(Screen): - """Allmails Screen for kivy Ui""" - - data = ListProperty() - has_refreshed = True - all_mails = ListProperty() - account = StringProperty() - - def __init__(self, *args, **kwargs): - """Method Parsing the address""" - super(Allmails, self).__init__(*args, **kwargs) - if 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.loadMessagelist() - print(dt) - - def loadMessagelist(self): - """Load Inbox, Sent anf Draft list of messages""" - self.account = state.association - self.ids.tag_label.text = '' - self.allMessageQuery(0, 20) - if self.all_mails: - self.ids.tag_label.text = 'All Mails' - state.kivyapp.get_inbox_count() - state.kivyapp.get_sent_count() - state.all_count = str( - int(state.sent_count) + int(state.inbox_count)) - self.set_AllmailCnt(state.all_count) - self.set_mdlist() - # self.ids.refresh_layout.bind(scroll_y=self.check_scroll_y) - self.ids.scroll_y.bind(scroll_y=self.check_scroll_y) - else: - self.set_AllmailCnt('0') - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="yet no message for this account!!!!!!!!!!!!!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def allMessageQuery(self, start_indx, end_indx): - """Retrieving data from inbox or sent both tables""" - self.all_mails = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder, ackdata" - " As id, DATE(senttime) As actionTime, senttime as msgtime FROM sent WHERE" - " folder = 'sent' and fromaddress = '{0}'" - " UNION SELECT toaddress, fromaddress, subject, message, folder," - " msgid As id, DATE(received) As actionTime, received as msgtime FROM inbox" - " WHERE folder = 'inbox' and toaddress = '{0}'" - " ORDER BY actionTime DESC limit {1}, {2}".format( - self.account, start_indx, end_indx)) - - def set_AllmailCnt(self, Count): # pylint: disable=no-self-use - """This method is used to set allmails message count""" - allmailCnt_obj = state.kivyapp.root.ids.content_drawer.ids.allmail_cnt - allmailCnt_obj.ids.badge_txt.text = showLimitedCnt(int(Count)) - - def set_mdlist(self): - """This method is used to create mdList for allmaills""" - data_exist = len(self.ids.ml.children) - for item in self.all_mails: - body = item[3].decode() if isinstance(item[3], bytes) else item[3] - subject = item[2].decode() if isinstance(item[2], bytes) else item[2] - meny = TwoLineAvatarIconListItem( - text=item[1], - secondary_text=(subject[:50] + '........' if len( - subject) >= 50 else ( - subject + ',' + body)[0:50] + '........').replace('\t', '').replace(' ', ''), - theme_text_color='Custom', - text_color=ThemeClsColor) - meny._txt_right_pad = dp(70) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/text_images/{}.png'.format( - avatarImageFirstLetter(body.strip())))) - meny.bind(on_press=partial( - self.mail_detail, item[5], item[4])) - meny.add_widget(AddTimeWidget(item[7])) - meny.add_widget(chipTag(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) - updated_data = len(self.ids.ml.children) - self.has_refreshed = True if data_exist != updated_data else False - - def check_scroll_y(self, instance, somethingelse): - """Scroll fixed length""" - if self.ids.scroll_y.scroll_y <= -0.00 and self.has_refreshed: - self.ids.scroll_y.scroll_y = .06 - load_more = len(self.ids.ml.children) - self.updating_allmail(load_more) - - def updating_allmail(self, load_more): - """This method is used to update the all mail - listing value on the scroll of screen""" - self.allMessageQuery(load_more, 5) - self.set_mdlist() - - def mail_detail(self, unique_id, folder, *args): - """Load sent and inbox mail details""" - state.detailPageType = folder - state.is_allmail = True - state.mail_id = 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""" - if folder == 'inbox': - sqlExecute( - "UPDATE inbox SET folder = 'trash' WHERE msgid = ?;", - unique_id) - else: - sqlExecute( - "UPDATE sent SET folder = 'trash' WHERE ackdata = ?;", - unique_id) - self.ids.ml.remove_widget(instance.parent.parent) - try: - msg_count_objs = self.parent.parent.ids.content_drawer.ids - nav_lay_obj = self.parent.parent.ids - except Exception: - msg_count_objs = self.parent.parent.parent.ids.content_drawer.ids - nav_lay_obj = self.parent.parent.parent.ids - if folder == 'inbox': - msg_count_objs.inbox_cnt.ids.badge_txt.text = showLimitedCnt(int(state.inbox_count) - 1) - state.inbox_count = str(int(state.inbox_count) - 1) - nav_lay_obj.sc1.ids.ml.clear_widgets() - nav_lay_obj.sc1.loadMessagelist(state.association) - else: - msg_count_objs.send_cnt.ids.badge_txt.text = showLimitedCnt(int(state.sent_count) - 1) - state.sent_count = str(int(state.sent_count) - 1) - nav_lay_obj.sc4.ids.ml.clear_widgets() - nav_lay_obj.sc4.loadSent(state.association) - if folder != 'inbox': - msg_count_objs.allmail_cnt.ids.badge_txt.text = showLimitedCnt(int(state.all_count) - 1) - state.all_count = str(int(state.all_count) - 1) - msg_count_objs.trash_cnt.ids.badge_txt.text = showLimitedCnt(int(state.trash_count) + 1) - state.trash_count = str(int(state.trash_count) + 1) - if int(state.all_count) <= 0: - self.ids.tag_label.text = '' - nav_lay_obj.sc5.clear_widgets() - nav_lay_obj.sc5.add_widget(Trash()) - nav_lay_obj.sc17.remove_widget(instance.parent.parent) - toast('Deleted') - - def refresh_callback(self, *args): - """Method updates the state of application, - While the spinner remains on the screen""" - def refresh_callback(interval): - """Load 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 function is used to the first letter for the avatar image""" - try: - if letter_string[0].upper() >= 'A' and letter_string[0].upper() <= 'Z': - img_latter = letter_string[0].upper() - elif int(letter_string[0]) >= 0 and int(letter_string[0]) <= 9: - img_latter = letter_string[0] - else: - img_latter = '!' - except ValueError: - img_latter = '!' - return img_latter if img_latter else '!' - - -class Starred(Screen): - """Starred Screen class for kivy Ui""" - - -class Archieve(Screen): - """Archieve Screen class for kivy Ui""" - - -class Spam(Screen): - """Spam Screen class for kivy Ui""" - - -class LoadingPopup(Popup): - """LoadingPopup class for kivy Ui""" - - def __init__(self, **kwargs): - super(LoadingPopup, self).__init__(**kwargs) - # call dismiss_popup in 2 seconds - Clock.schedule_once(self.dismiss_popup, 0.5) - - def dismiss_popup(self, dt): - """Dismiss popups""" - self.dismiss() - - -class AddressDropdown(OneLineIconListItem): - """AddressDropdown class for kivy Ui""" - - -class BadgeText(IRightBodyTouch, MDLabel): - """BadgeText class for kivy Ui""" - - -class NavigationItem(OneLineAvatarIconListItem): - """NavigationItem class for kivy Ui""" - badge_text = StringProperty() - icon = StringProperty() - active = BooleanProperty(False) - - def currentlyActive(self): - """Currenly active""" - for nav_obj in self.parent.children: - nav_obj.active = False - self.active = True - - -class NavigationDrawerDivider(OneLineListItem): - """ - A small full-width divider that can be placed - in the :class:`MDNavigationDrawer` - """ - - disabled = True - divider = None - _txt_top_pad = NumericProperty(dp(8)) - _txt_bot_pad = NumericProperty(dp(8)) - - def __init__(self, **kwargs): - # pylint: disable=bad-super-call - super(OneLineListItem, self).__init__(**kwargs) - self.height = dp(16) - - -class NavigationDrawerSubheader(OneLineListItem): - """ - A subheader for separating content in :class:`MDNavigationDrawer` - - Works well alongside :class:`NavigationDrawerDivider` - """ - - disabled = True - divider = None - theme_text_color = 'Secondary' - - -class AppClosingPopup(Popup): - """AppClosingPopup class for kivy Ui""" - - def __init__(self, **kwargs): - super(AppClosingPopup, self).__init__(**kwargs) - - def closingAction(self, text): - """Action on closing window""" - if text == 'Yes': - print("*******************EXITING FROM APPLICATION*******************") - import shutdown - shutdown.doCleanShutdown() - else: - self.dismiss() - toast(text) - - -class SenderDetailPopup(Popup): - """SenderDetailPopup class for kivy Ui""" - - to_addr = StringProperty() - from_addr = StringProperty() - time_tag = StringProperty() - - def __init__(self, **kwargs): - """this metthod initialized the send message detial popup""" - super(SenderDetailPopup, self).__init__(**kwargs) - - def assignDetail(self, to_addr, from_addr, timeinseconds): - """Detailes assigned""" - self.to_addr = to_addr - self.from_addr = from_addr - time_obj = datetime.fromtimestamp(int(timeinseconds)) - self.time_tag = time_obj.strftime("%d %b %Y, %I:%M %p") - device_type = 2 if platform == 'android' else 1.5 - pop_height = 1.2 * device_type * (self.ids.sd_label.height + self.ids.dismiss_btn.height) - if len(to_addr) > 3: - self.height = 0 - self.height = pop_height - self.ids.to_addId.size_hint_y = None - self.ids.to_addId.height = 50 - self.ids.to_addtitle.add_widget(ToAddressTitle()) - frmaddbox = ToAddrBoxlayout() - frmaddbox.set_toAddress(to_addr) - self.ids.to_addId.add_widget(frmaddbox) - else: - self.ids.space_1.height = dp(0) - self.ids.space_2.height = dp(0) - self.ids.myadd_popup_box.spacing = dp(8 if platform == 'android' else 3) - self.height = 0 - self.height = pop_height / 1.2 - - -class OneLineListTitle(OneLineListItem): - """OneLineListTitle class for kivy Ui""" - __events__ = ('on_long_press', ) - long_press_time = NumericProperty(1) - - def on_state(self, instance, value): - """On state""" - if value == 'down': - lpt = self.long_press_time - self._clockev = Clock.schedule_once(self._do_long_press, lpt) - else: - self._clockev.cancel() - - def _do_long_press(self, dt): - """Do long press""" - self.dispatch('on_long_press') - - def on_long_press(self, *largs): - """On long press""" - self.copymessageTitle(self.text) - - def copymessageTitle(self, title_text): - """this method is for displaying dialog box""" - self.title_text = title_text - width = .8 if platform == 'android' else .55 - self.dialog_box = MDDialog( - text=title_text, - size_hint=(width, .25), - buttons=[ - MDFlatButton( - text="Copy", on_release=self.callback_for_copy_title - ), - MDFlatButton( - text="Cancel", on_release=self.callback_for_copy_title, - ), - ],) - self.dialog_box.open() - - def callback_for_copy_title(self, instance): - """Callback of alert box""" - if instance.text == 'Copy': - Clipboard.copy(self.title_text) - self.dialog_box.dismiss() - toast(instance.text) - - -class ToAddrBoxlayout(BoxLayout): - """ToAddrBoxlayout class for kivy Ui""" - to_addr = StringProperty() - - def set_toAddress(self, to_addr): - """This method is use to set to address""" - self.to_addr = to_addr - - -class ToAddressTitle(BoxLayout): - """ToAddressTitle class for BoxLayout behaviour""" - - -class RandomBoxlayout(BoxLayout): - """RandomBoxlayout class for BoxLayout behaviour""" - - -def esc_markup(msg): - """this method is for replacing some property""" - return (msg.replace('&', '&') - .replace('[', '&bl;') - .replace(']', '&br;')) - - -class ChatRoom(Screen): - """ChatRoom Screen class for kivy Ui""" - def send_msg(self): - """This method is for sending message""" - msg = self.ids.message.text - if msg: - self.ids.chat_logs.text += ( - '[b][color=2980b9]{}:[/color][/b] {}\n' - .format('Me', esc_markup(msg))) - # obj = MDChip(label=msg, radius=7) - # obj.icon = '' - # self.ids.ml.add_widget(obj) - self.ids.message.text = '' - - -class ChatList(Screen): - """ChatList Screen class for kivy Ui""" - queryreturn = ListProperty() - has_refreshed = True - - def __init__(self, *args, **kwargs): - """Getting ChatList Details""" - super(ChatList, self).__init__(*args, **kwargs) - Clock.schedule_once(self.init_ui, 0) - - def init_ui(self, dt=0): - """Clock Schdule for method ChatList""" - self.loadAddresslist(None, 'All', '') - print(dt) - - def loadAddresslist(self, account="", where="", what=""): - """Clock Schdule for method ChatList""" - self.queryreturn = kivy_helper_search.search_sql( - '', account, "addressbook", where, what, False) - self.queryreturn = [obj for obj in reversed(self.queryreturn)] - if self.queryreturn: - self.set_mdList() - else: - content = MDLabel( - font_style='Caption', - theme_text_color='Primary', - text="No contact found!", - halign='center', - size_hint_y=None, - valign='top') - self.ids.ml.add_widget(content) - - def set_mdList(self): - """Creating the mdList""" - for item in self.queryreturn: - meny = TwoLineAvatarIconListItem( - text=item[0], secondary_text=item[1], theme_text_color='Custom', - text_color=ThemeClsColor) - meny.add_widget(AvatarSampleWidget( - source=state.imageDir + '/text_images/{}.png'.format( - avatarImageFirstLetter(item[0].strip())))) - meny.bind(on_release=partial( - self.redirect_to_chat, item[0], item[1])) - self.ids.ml.add_widget(meny) - - def redirect_to_chat(self, label, addr, *args): - """This method is redirecting on chatroom""" - self.manager.transition = RiseInTransition() - state.kivyapp.set_toolbar_for_QrCode() - label = label[:14].capitalize() + '...' if len(label) > 15 else label.capitalize() - addrs = ' (' + addr + ')' - self.manager.parent.ids.toolbar.title = label + addrs - self.manager.parent.ids.sc21.ids.chat_logs.text = '' - self.manager.current = 'chroom' +class PaymentMethodLayout(BoxLayout): + """PaymentMethodLayout class for kivy Ui""" diff --git a/src/bitmessagekivy/screens_data.json b/src/bitmessagekivy/screens_data.json new file mode 100644 index 00000000..7bc6a65b --- /dev/null +++ b/src/bitmessagekivy/screens_data.json @@ -0,0 +1,79 @@ +{ + "Inbox": { + "kv_string": "inbox", + "name_screen": "inbox", + "Import": "from bitmessagekivy.baseclass.inbox import Inbox", + }, + "Sent": { + "kv_string": "sent", + "name_screen": "sent", + "Import": "from bitmessagekivy.baseclass.sent import Sent", + }, + "Draft": { + "kv_string": "draft", + "name_screen": "draft", + "Import": "from bitmessagekivy.baseclass.draft import Draft", + }, + "Trash": { + "kv_string": "trash", + "name_screen": "trash", + "Import": "from bitmessagekivy.baseclass.trash import Trash", + }, + "All Mails": { + "kv_string": "allmails", + "name_screen": "allmails", + "Import": "from bitmessagekivy.baseclass.allmail import Allmails", + }, + "Address Book": { + "kv_string": "addressbook", + "name_screen": "addressbook", + "Import": "from bitmessagekivy.baseclass.addressbook import AddressBook", + }, + "Settings": { + "kv_string": "settings", + "name_screen": "set", + "Import": "from bitmessagekivy.baseclass.settings import Setting", + }, + "Payment": { + "kv_string": "payment", + "name_screen": "payment", + "Import": "from bitmessagekivy.baseclass.payment import Payment", + }, + "Network status": { + "kv_string": "network", + "name_screen": "networkstat", + "Import": "from bitmessagekivy.baseclass.network import NetworkStat", + }, + "My addresses": { + "kv_string": "myaddress", + "name_screen": "myaddress", + "Import": "from bitmessagekivy.baseclass.myaddress import MyAddress", + }, + "MailDetail": { + "_comment1": "this is my comment", + "kv_string": "maildetail", + "name_screen": "mailDetail", + "Import": "from bitmessagekivy.baseclass.maildetail import MailDetail", + }, + "Create": { + "kv_string": "msg_composer", + "name_screen": "create", + "Import": "from bitmessagekivy.baseclass.msg_composer import Create", + }, + "Login": { + "kv_string": "login", + "Import": "from bitmessagekivy.baseclass.login import *", + }, + "Scanner": { + "kv_string": "scan_screen", + "Import": "from bitmessagekivy.baseclass.scan_screen import ScanScreen", + }, + "Popups": { + "kv_string": "popup", + "Import": "from bitmessagekivy.baseclass.popup import *", + }, + "Qrcode": { + "kv_string": "qrcode", + "Import": "from bitmessagekivy.baseclass.qrcode import ShowQRCode", + }, +} diff --git a/src/bitmessagekivy/tests/test_addressbook.py b/src/bitmessagekivy/tests/test_addressbook.py deleted file mode 100644 index d6d3922b..00000000 --- a/src/bitmessagekivy/tests/test_addressbook.py +++ /dev/null @@ -1,105 +0,0 @@ -import time -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -from bmconfigparser import BMConfigParser -from .common import ordered - -data = BMConfigParser().addresses() - - -class AddressBook(TeleniumTestProcess): - """AddressBook Screen Functionality Testing""" - - @ordered - def test_save_address(self): - """Save Address On Address Book Screen/Window""" - print("=====================Test -Save Address In Address Book=====================") - self.cli.sleep(6) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(4) - self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[6]') - self.cli.sleep(4) - self.cli.execute('app.addingtoaddressbook()') - self.cli.sleep(3) - self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') - self.cli.sleep(4) - self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') - self.cli.sleep(4) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(4) - self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]','text','peter') - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(4) - self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','sectorAppartment') - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(5) - self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text',data[0]) - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','') - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(4) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','BM-2cX78L9CZpb6GGC3rRVizYiUBwHELMLybd') - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(4) - - @ordered - def test_cancel_address(self): - """Cancel Address""" - print("=====================Test -Cancel Address=====================") - self.cli.sleep(3) - self.cli.execute('app.addingtoaddressbook()') - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]','text','prachi') - self.cli.sleep(3) - self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text',data[0]) - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[1]') - - @ordered - def test_send_message_to_addressbook(self): - """Directly Send Message To The User""" - print("=====================Test -Directly Send Message To The User=====================") - self.cli.sleep(4) - self.cli.click_on('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]') - self.cli.sleep(3) - self.cli.click_on('//MDRaisedButton[0]') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') - self.cli.sleep(2) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]') - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') - self.cli.sleep(3) - random_label="" - for char in "Hey This is Message From Address Book": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) - self.cli.sleep(0.2) - self.cli.click_on('//MDActionTopAppBarButton[2]') - self.cli.sleep(2) - - @ordered - def test_delete_address_from_address_contact(self): - """Delete Address From Address Book""" - print("=====================Test -Delete Address From Address Book=====================") - self.cli.sleep(3) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[6]') - self.cli.sleep(3) - self.cli.drag('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[0]', - '//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 2) - self.cli.sleep(2) - self.cli.click_on('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//Button[0]') - self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_allmail_message.py b/src/bitmessagekivy/tests/test_allmail_message.py deleted file mode 100644 index 7efad3f1..00000000 --- a/src/bitmessagekivy/tests/test_allmail_message.py +++ /dev/null @@ -1,26 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -from .common import ordered - - -class AllMailMessage(TeleniumTestProcess): - """AllMail Screen Functionality Testing""" - - @ordered - def test_show_allmail_list(self): - """Show All Messages on Mail Screen/Window""" - print("=====================Test -Show Messages Of Mail Screen=====================") - self.cli.sleep(5) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(4) - self.cli.click_on('//NavigationItem[5]') - self.cli.sleep(4) - - @ordered - def test_delete_message_from_allmail_list(self): - """Delete Message From Message body of Mail Screen/Window""" - print("=====================Test -Delete Messages Of Mail Screen=====================") - self.cli.sleep(4) - self.cli.click_on('//Allmails[0]/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]') - self.cli.sleep(5) - self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[1]') - self.cli.sleep(5) diff --git a/src/bitmessagekivy/tests/test_draft_message.py b/src/bitmessagekivy/tests/test_draft_message.py deleted file mode 100644 index 80c5114b..00000000 --- a/src/bitmessagekivy/tests/test_draft_message.py +++ /dev/null @@ -1,92 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -from .common import ordered - - -class DraftMessage(TeleniumTestProcess): - """Draft Screen Functionality Testing""" - - @ordered - def test_save_draft_message(self): - """Select A Draft Screen From Navigaion-Drawer-Box Then - Send a drafted message """ - print("=====================Test - Select A Draft Screen From Navigaion-Drawer-Box=====================") - # OPEN NAVIGATION-DRAWER - self.cli.sleep(4) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(2) - # OPEN INBOX SCREEN - self.cli.click_on('//NavigationItem[1]') - self.cli.sleep(2) - # CLICK ON PLUS ICON BUTTON - self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') - self.cli.sleep(3) - # SELECT - TO ADDRESS - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') - self.cli.sleep(2) - self.cli.click_on('//MyTextInput[0]') - self.cli.sleep(3) - # ADD FROM MESSAGE - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text",'BM-2cSsuH1bUWBski8bvdqnK2DivMqQCeQA1J') - self.cli.sleep(3) - # CLICK BACK-BUTTON - self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') - self.cli.sleep(5) - self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') - self.cli.sleep(3) - # SELECT - TO ADDRESS - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') - self.cli.sleep(1) - self.cli.click_on('//MyTextInput[0]') - self.cli.sleep(3) - # ADD FROM MESSAGE - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text",'BM-2cSsuH1bUWBski8bvdqnK2DivMqQCeQA1J') - self.cli.sleep(4) - random_label="" - for char in "Another Draft message": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', random_label) - self.cli.sleep(0.2) - # CLICK BACK-BUTTON - self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') - self.cli.sleep(4) - - @ordered - def test_edit_and_resend_draft_messgae(self): - """Select A Message From List of Messages Then - make changes and send it.""" - print("=====================Test - Edit A Message From Draft Screen=====================") - # OPEN NAVIGATION-DRAWER - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(4) - # OPEN DRAFT SCREEN - self.cli.click_on('//NavigationItem[3]') - self.cli.sleep(4) - # SHOW DRAFT MESSAGE AND SELECT FIRST MESSAGE - self.cli.click_on('//Carousel[0]//TwoLineAvatarIconListItem[0]') - self.cli.sleep(3) - # CLICK EDIT BUTTON - self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[0]') - self.cli.sleep(5) - random_label="" - for char in "Hey,This is draft Message Body": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) - self.cli.sleep(0.2) - self.cli.sleep(3) - self.cli.click_on('//MDActionTopAppBarButton[2]') - self.cli.sleep(5) - - @ordered - def test_delete_draft_message(self): - """Delete A Message From List of Messages""" - print("=====================Test - Delete A Message From List of Messages=====================") - self.cli.sleep(5) - # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(4) - self.cli.click_on('//NavigationItem[3]') - self.cli.sleep(5) - self.cli.click_on('//Carousel[0]//TwoLineAvatarIconListItem[0]') - self.cli.sleep(5) - self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[1]') - self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_myaddress_screen.py b/src/bitmessagekivy/tests/test_myaddress_screen.py deleted file mode 100644 index 7fd7da3e..00000000 --- a/src/bitmessagekivy/tests/test_myaddress_screen.py +++ /dev/null @@ -1,55 +0,0 @@ -from bmconfigparser import BMConfigParser -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -from .common import ordered - -data = BMConfigParser().addresses() - - -class MyAddressScreen(TeleniumTestProcess): - """MyAddress Screen Functionality Testing""" - - @ordered - def test_select_myaddress_list(self): - """Select Address From List of Address""" - print("=====================Test -Select Address From List of Address=====================") - self.cli.sleep(4) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[11]') - self.cli.sleep(4) - - @ordered - def test_show_Qrcode(self): - """Show the Qr code of selected address""" - print("=====================Test -Show QR code of selected address=====================") - self.cli.sleep(4) - self.cli.click_on('//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/CustomTwoLineAvatarIconListItem[0]') - self.cli.sleep(3) - self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[1]/MDLabel[0]') - self.cli.sleep(3) - self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') - self.cli.sleep(3) - - @ordered - def test_send_message_from(self): - """Send Message From Send Message From Button""" - print("=====================Test -Send Message From Send Message From Button=====================") - self.cli.sleep(4) - self.cli.click_on('//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/CustomTwoLineAvatarIconListItem[0]') - self.cli.sleep(4) - self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[0]/MDLabel[0]') - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput', "text", data[1]) - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Hey') - self.cli.sleep(3) - random_label="" - for char in "Hey,i am sending message directly from MyAddress book": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) - self.cli.sleep(0.2) - self.cli.sleep(2) - self.cli.click_on('//MDActionTopAppBarButton[2]') - self.cli.sleep(4) diff --git a/src/bitmessagekivy/tests/test_network_screen.py b/src/bitmessagekivy/tests/test_network_screen.py deleted file mode 100644 index d0185389..00000000 --- a/src/bitmessagekivy/tests/test_network_screen.py +++ /dev/null @@ -1,18 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess - - -class NetwrokStatusScreen(TeleniumTestProcess): - """NetwrokStatus Screen Functionality Testing""" - - def test_network_status(self): - """Show NetwrokStatus""" - print("=====================Test -Show NetwrokStatus=====================") - self.cli.sleep(4) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[10]') - self.cli.sleep(4) - self.cli.click_on('//NetworkStat/MDTabs[0]/MDTabsBar[0]/MDTabsScrollView[0]/MDGridLayout[0]/MDTabsLabel[1]') - self.cli.sleep(4) diff --git a/src/bitmessagekivy/tests/test_payment_subscription.py b/src/bitmessagekivy/tests/test_payment_subscription.py deleted file mode 100644 index 7f8341eb..00000000 --- a/src/bitmessagekivy/tests/test_payment_subscription.py +++ /dev/null @@ -1,25 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess - - -class PaymentScreen(TeleniumTestProcess): - """SubscriptionPayment Screen Functionality Testing""" - - def test_select_subscripton(self): - """Select Subscripton From List of Subscriptons""" - print("=====================Test -Select Subscripton From List of Subscriptons=====================") - self.cli.sleep(4) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[8]') - self.cli.sleep(3) - self.cli.drag('//Payment/BoxLayout[0]/ScrollView[0]/BoxLayout[0]/ProductCategoryLayout[0]/ProductLayout[1]', - '//Payment/BoxLayout[0]/ScrollView[0]/BoxLayout[0]/ProductCategoryLayout[0]/ProductLayout[0]', 1) - self.cli.sleep(2) - self.cli.click_on('//MDRaisedButton[3]') - self.cli.sleep(2) - self.cli.click_on('//ListItemWithLabel[0]') - self.cli.sleep(2) - self.cli.click_on('//MDRaisedButton[3]') - self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_sent_message.py b/src/bitmessagekivy/tests/test_sent_message.py deleted file mode 100644 index 6e0b8204..00000000 --- a/src/bitmessagekivy/tests/test_sent_message.py +++ /dev/null @@ -1,101 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -from bmconfigparser import BMConfigParser -from .common import ordered - -data = BMConfigParser().addresses() - - -class SendMessage(TeleniumTestProcess): - """Sent Screen Functionality Testing""" - - @ordered - def test_send_message_and_validation(self): - """ - Sending Message From Inbox Screen - opens a pop-up(screen)which send message from sender to reciever - """ - print("=====================Test - Sending Message From Inbox Screen=====================") - self.cli.sleep(3) - # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(2) - self.cli.click_on('//NavigationItem[1]') - self.cli.sleep(2) - self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/MyMDTextField[0]') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/MyTextInput[0]') - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/MyTextInput[0]', "text", "second add") - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]') - self.cli.sleep(4) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]') - self.cli.sleep(4) - self.cli.click_on('//MDIconButton[2]') - self.cli.sleep(3) - self.cli.click_on('//MDFlatButton[0]') - self.cli.sleep(5) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') - self.cli.sleep(2) - self.cli.click_on('//MyTextInput[0]') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]') - self.cli.sleep(2) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'heyyyyyy') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]') - self.cli.sleep(4) - random_label="" - for char in "how are you this is message body": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]','text',random_label) - self.cli.sleep(0.2) - self.cli.sleep(3) - self.cli.click_on('//MDIconButton[2]') - self.cli.sleep(3) - self.cli.click_on('//MDFlatButton[0]') - self.cli.sleep(6) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]',"text", data[0]) - self.cli.sleep(3) - self.cli.click_on('//MDIconButton[2]') - self.cli.sleep(3) - self.cli.click_on('//MDActionTopAppBarButton[2]') - self.cli.sleep(3) - - @ordered - def test_sent_multiple_messages(self): - """ - Sending Second Message From Inbox Screen - for testing the search and delete functionality for two messages on the screen - """ - print("=====================Test - Sending Message From Inbox Screen=====================") - self.cli.sleep(3) - # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(5) - self.cli.click_on('//NavigationItem[1]') - self.cli.sleep(3) - self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') - self.cli.sleep(3) - self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') - self.cli.sleep(2) - self.cli.click_on('//MyTextInput[0]') - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text", data[0]) - self.cli.sleep(3) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') - self.cli.sleep(3) - random_label="" - for char in "Hey This Is Second Message Body": - random_label += char - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]',"text",random_label) - self.cli.sleep(0.2) - self.cli.sleep(2) - self.cli.click_on('//MDActionTopAppBarButton[2]') - self.cli.sleep(5) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[2]') - self.cli.sleep(3) diff --git a/src/bitmessagekivy/tests/test_setting_screen.py b/src/bitmessagekivy/tests/test_setting_screen.py deleted file mode 100644 index b3773cb3..00000000 --- a/src/bitmessagekivy/tests/test_setting_screen.py +++ /dev/null @@ -1,16 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess - - -class SettingScreen(TeleniumTestProcess): - """Setting Screen Functionality Testing""" - - def test_setting_screen(self): - """Show Setting Screen""" - print("=====================Test -Show Setting Screen=====================") - self.cli.sleep(3) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(3) - self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) - self.cli.sleep(3) - self.cli.click_on('//NavigationItem[7]') - self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_trash_message.py b/src/bitmessagekivy/tests/test_trash_message.py deleted file mode 100644 index 08c27fd4..00000000 --- a/src/bitmessagekivy/tests/test_trash_message.py +++ /dev/null @@ -1,22 +0,0 @@ -from bitmessagekivy.tests.telenium_process import TeleniumTestProcess - - -class TrashMessage(TeleniumTestProcess): - """Trash Screen Functionality Testing""" - - def test_delete_trash_message(self): - """Delete Trash message permanently from trash message listing""" - print("=====================Test -Delete Message From Trash Message Listing=====================") - self.cli.sleep(4) - self.cli.execute('app.clickNavDrawer()') - self.cli.sleep(4) - self.cli.click_on('//NavigationItem[4]') - self.cli.sleep(4) - self.cli.drag('//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[0]', - '//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 2) - self.cli.sleep(4) - self.cli.click_on('//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//Button[0]') - self.cli.sleep(2) - # self.cli.click_on('//MDDialog/MDCard[0]/AnchorLayout[0]/MDBoxLayout[0]/MDFlatButton[0]') - self.cli.click_on('//MDDialog/DialogFakeCard[0]/AnchorLayout[0]/MDBoxLayout[0]/MDFlatButton[0]') - self.cli.sleep(4)