diff --git a/src/bitmessagekivy/main.kv b/src/bitmessagekivy/main.kv index 08847957..e5b0340c 100644 --- a/src/bitmessagekivy/main.kv +++ b/src/bitmessagekivy/main.kv @@ -53,15 +53,15 @@ color: color_font : - drawer_logo: './images/drawer_logo1.png' + drawer_logo: app.address_identicon() NavigationDrawerDivider: - + NavigationDrawerTwoLineListItem: text: "Accounts" NavigationDrawerIconButton: CustomSpinner: - pos_hint:{"x":0,"y":.25} id: btn + pos_hint:{"x":0,"y":.25} option_cls: Factory.get("MySpinnerOption") font_size: '12.5sp' text: app.getDefaultAccData() @@ -70,6 +70,11 @@ color: color_font values: app.variable_1 on_text:app.getCurrentAccountData(self.text) + Image: + source: app.get_default_image() + x: self.width/4 + y: self.parent.y + self.parent.height/2 - self.height + 10 + size: 20, 20 ArrowImg: NavigationDrawerIconButton: id: inbox_cnt @@ -200,6 +205,7 @@ NavigationLayout: id: search_field hint_text: 'Search' on_text: app.searchQuery(self) + ScreenManager: id: scr_mngr Inbox: @@ -304,7 +310,7 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(500) + height: self.minimum_height + 2 * self.parent.height/4 padding: dp(32) spacing: 15 BoxLayout: @@ -634,7 +640,118 @@ NavigationLayout: : name: 'payment' - + ScrollView: + do_scroll_x: False + BoxLayout: + orientation: 'horizontal' + padding: dp(20) + spacing: 10 + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Platinum' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 50.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Silver' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 100.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + BoxLayout: + orientation: 'vertical' + padding: dp(5) + canvas.before: + Color: + rgba: 0.957, 0.890, 0.843, 1 + Rectangle: + # self here refers to the widget i.e FloatLayout + pos: self.pos + size: self.size + MDLabel: + size_hint_y: None + font_style: 'Headline' + theme_text_color: 'Primary' + text: 'Gold' + halign: 'center' + MDLabel: + font_style: 'Subhead' + theme_text_color: 'Primary' + text: 'We provide subscriptions to real-time streaming market data directly from exchanges, quote aggregators and index providers. The Market Data Subscriptions page lets you sign up for additional market data subscriptions such as NASDAQ TotalView and NYSE Open Book or unsubscribe from market data. ' + halign: 'center' + MDLabel: + font_style: 'Headline' + theme_text_color: 'Primary' + text: '€ 500.0' + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + MDLabel: + font_style: 'Title' + text: 'Select' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + : id: popup @@ -663,10 +780,12 @@ NavigationLayout: hint_text: "Address" required: True helper_text_mode: "on_error" + on_text: root.checkAddress_valid(self) BoxLayout: spacing:5 orientation: 'horizontal' MDRaisedButton: + id: save_addr size_hint: 1.5, None height: dp(40) on_release: @@ -698,6 +817,7 @@ NavigationLayout: color: (1,1,1,1) halign: 'center' + : name: 'networkstat' MDTabbedPanel: @@ -795,23 +915,27 @@ NavigationLayout: BoxLayout: orientation: 'vertical' size_hint_y: None - height: dp(400) + height: dp(400) + self.minimum_height padding: dp(32) MDLabel: font_style: 'Headline' theme_text_color: 'Primary' text: root.subject halign: 'left' + font_size: '20sp' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: "From: " + root.from_addr halign: 'left' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' text: "To: " + root.to_addr halign: 'left' + CopyTextBtn: MDLabel: font_style: 'Subhead' theme_text_color: 'Primary' @@ -823,28 +947,46 @@ NavigationLayout: text: root.message halign: 'left' bold: True + CopyTextBtn: BoxLayout: - spacing:20 - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.inbox_reply() if root.page_type == 'inbox' else root.copy_sent_mail() if root.page_type == 'sent' else root.write_msg(app) - MDLabel: - font_style: 'Title' - text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' - MDRaisedButton: - size_hint: 1, None - height: dp(40) - on_press: root.delete_mail() - MDLabel: - font_style: 'Title' - text: 'Delete' - font_size: '13sp' - color: (1,1,1,1) - halign: 'center' + orientation: 'vertical' + size_hint_y: None + height: dp(100) + self.minimum_height + BoxLayout: + spacing:20 + MDRaisedButton: + size_hint: 1, None + height: dp(40) + on_press: root.inbox_reply() if root.page_type == 'inbox' else root.write_msg(app) if root.page_type == 'draft' else root.copy_sent_mail() + MDLabel: + font_style: 'Title' + text: 'Reply' if root.page_type == 'inbox' else 'Copy' if root.page_type == 'sent' else 'Write' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + MDRaisedButton: + size_hint: 1, None + height: dp(40) + on_press: root.delete_mail() + MDLabel: + font_style: 'Title' + text: 'Delete' + font_size: '13sp' + color: (1,1,1,1) + halign: 'center' + +: + id: cpyButton + color: 0,0,0,1 + background_color: (0,0,0,0) + center_x: self.parent.center_x * 2 - self.parent.parent.padding[0]/2 + center_y: self.parent.center_y + on_press:app.root.ids.sc14.copy_composer_text(self) + Image: + source: './images/copy_text.png' + center_x: self.parent.center_x + center_y: self.parent.center_y + size: 20, 20 : size_hint_y: None diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index ca82f405..48ff4738 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -61,6 +61,12 @@ import state from uikivysignaler import UIkivySignaler +import identiconGeneration + +import os + +from kivy.core.clipboard import Clipboard + # pylint: disable=unused-argument # pylint: disable=broad-except @@ -120,10 +126,7 @@ class Inbox(Screen): third_text = mail[3].replace('\n', ' ') data.append({ 'text': mail[4].strip(), - 'secondary_text': mail[5][:10] + '...........' if len( - mail[3]) > 10 else mail[3] + '\n' + " " + ( - third_text[:25] + '...!') if len( - third_text) > 25 else third_text, + 'secondary_text': mail[5][:50] + '........' if len(mail[5]) >= 50 else (mail[5] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'receivedTime': mail[6]}) for item in data: meny = ThreeLineAvatarIconListItem( @@ -131,11 +134,11 @@ class Inbox(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') else '!' + # img_latter = item['secondary_text'][0].upper() if ( + # item['secondary_text'][0].upper() >= 'A' and item[ + # 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.inbox_detail, item['receivedTime'])) carousel = Carousel(direction='right') @@ -269,11 +272,8 @@ class MyAddress(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['text'][0].upper() if ( - item['text'][0].upper() >= 'A' and item['text'][ - 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['text'].strip())))) meny.bind(on_press=partial( self.myadd_detail, item['secondary_text'], item['text'])) self.ids.ml.add_widget(meny) @@ -356,11 +356,8 @@ class AddressBook(Screen): secondary_text=item[1], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item[0][0].upper() if ( - item[0][0].upper() >= 'A' and item[0][ - 0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[0].strip())))) meny.bind(on_press=partial( self.addBook_detail, item[1], item[0])) carousel = Carousel(direction='right') @@ -470,8 +467,8 @@ class DropDownWidget(BoxLayout): # pylint: disable=too-many-locals fromAddress = str(self.ids.ti.text) toAddress = str(self.ids.txt_input.text) - subject = str(self.ids.subject.text) - message = str(self.ids.body.text) + subject = self.ids.subject.text.encode('utf-8').strip() + message = self.ids.body.text.encode('utf-8').strip() encoding = 3 print "message: ", self.ids.body.text sendMessageToPeople = True @@ -542,13 +539,7 @@ class DropDownWidget(BoxLayout): queues.workerQueue.put(('sendmessage', toAddress)) print "sqlExecute successfully #######################" - self.ids.body.text = '' - self.ids.ti.text = '' - self.ids.subject.text = '' - self.ids.txt_input.text = '' self.parent.parent.current = 'inbox' - self.ids.btn.text = 'select' - self.ids.ti.text = '' navApp.back_press() toast('send') return None @@ -709,7 +700,7 @@ class Random(Screen): eighteenByteRipe = False nonceTrialsPerByte = 1000 payloadLengthExtraBytes = 1000 - if self.ids.label.text: + if str(self.ids.label.text).strip(): queues.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, @@ -774,13 +765,9 @@ class Sent(Screen): if queryreturn: for mail in queryreturn: - third_text = mail[3].replace('\n', ' ') self.data.append({ 'text': mail[1].strip(), - 'secondary_text': mail[2][:10] + '...........' if len( - mail[2]) > 10 else mail[2] + '\n' + " " + ( - third_text[:25] + '...!') if len( - third_text) > 25 else third_text, + 'secondary_text': mail[2][:50] + '........' if len(mail[2]) >= 50 else (mail[2] + ',' + mail[3].replace('\n', ''))[0:50] + '........', 'lastactiontime': mail[6]}) for item in self.data: meny = ThreeLineAvatarIconListItem( @@ -788,11 +775,8 @@ class Sent(Screen): secondary_text=item['secondary_text'], theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = item['secondary_text'][0].upper() if ( - item['secondary_text'][0].upper() >= 'A' and item[ - 'secondary_text'][0].upper() <= 'Z') else '!' meny.add_widget(AvatarSampleWidget( - source='./images/text_images/{}.png'.format(img_latter))) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item['secondary_text'].strip())))) meny.bind(on_press=partial( self.sent_detail, item['lastactiontime'])) carousel = Carousel(direction='right') @@ -806,7 +790,7 @@ class Sent(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.delete, item['lastactiontime'])) carousel.add_widget(del_btn) @@ -881,9 +865,13 @@ class Sent(Screen): try: self.parent.screens[4].clear_widgets() self.parent.screens[4].add_widget(Trash()) + self.parent.screens[16].clear_widgets() + self.parent.screens[16].add_widget(Allmails()) except Exception: self.parent.parent.screens[4].clear_widgets() self.parent.parent.screens[4].add_widget(Trash()) + self.parent.parent.screens[16].clear_widgets() + self.parent.parent.screens[16].add_widget(Allmails()) class Trash(Screen): @@ -903,26 +891,58 @@ class Trash(Screen): state.association = BMConfigParser().addresses()[0] inbox = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from \ + "SELECT toaddress, fromaddress, subject, message, folder, received from \ inbox WHERE folder = 'trash' and toaddress = '{}';".format( state.association)) sent = sqlQuery( - "SELECT toaddress, fromaddress, subject, message, folder from \ + "SELECT toaddress, fromaddress, subject, message, folder, lastactiontime from \ sent WHERE folder = 'trash' and fromaddress = '{}';".format( state.association)) trash_data = inbox + sent - for item in trash_data: - meny = ThreeLineAvatarIconListItem( - text=item[1], - secondary_text=item[2], - theme_text_color='Custom', - text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/text_images/{}.png'.format( - item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') - meny.add_widget(AvatarSampleWidget(source=img_latter)) - self.ids.ml.add_widget(meny) + if trash_data: + for item in trash_data: + meny = ThreeLineAvatarIconListItem( + text=item[1], + secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', + theme_text_color='Custom', + text_color=NavigateApp().theme_cls.primary_color) + img_latter = './images/text_images/{}.png'.format( + item[2][0].upper() if (item[2][0].upper() >= 'A' and item[ + 2][0].upper() <= 'Z') else '!') + meny.add_widget(AvatarSampleWidget(source=img_latter)) + carousel = Carousel(direction='right') + if platform == 'android': + carousel.height = 150 + elif platform == 'linux': + carousel.height = meny.height - 10 + carousel.size_hint_y = None + carousel.ignore_perpendicular_swipes = True + carousel.data_index = 0 + carousel.min_move = 0.2 + del_btn = Button(text='Delete') + del_btn.background_normal = '' + del_btn.background_color = (1, 0, 0, 1) + del_btn.bind(on_press=partial( + self.delete_permanently, item[5])) + carousel.add_widget(del_btn) + carousel.add_widget(meny) + carousel.index = 1 + self.ids.ml.add_widget(carousel) + else: + content = MDLabel( + font_style='Body1', + theme_text_color='Primary', + text="yet no trashed message for this account!!!!!!!!!!!!!", + halign='center', + bold=True, + size_hint_y=None, + valign='top') + self.ids.ml.add_widget(content) + + def delete_permanently(self, data_index, instance, *args): + """Deleting trash mail permanently.""" + pass class Page(Screen): @@ -986,7 +1006,6 @@ class NavigateApp(App): def build(self): """Method builds the widget.""" - import os main_widget = Builder.load_file( os.path.join(os.path.dirname(__file__), 'main.kv')) self.nav_drawer = Navigatorss() @@ -1018,6 +1037,7 @@ class NavigateApp(App): def getCurrentAccountData(self, text): """Get Current Address Account Data.""" + self.set_identicon(text) address_label = self.current_address_label( BMConfigParser().get(text, 'label'), text) self.root_window.children[1].ids.toolbar.title = address_label @@ -1074,13 +1094,29 @@ class NavigateApp(App): p = GrashofPopup() p.open() - @staticmethod - def getDefaultAccData(): + def getDefaultAccData(self): """Getting Default Account Data.""" if BMConfigParser().addresses(): + img = identiconGeneration.generate(BMConfigParser().addresses()[0]) + self.createFolder('./images/default_identicon/') + img.texture.save('./images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0])) return BMConfigParser().addresses()[0] return 'Select Address' + def createFolder(self, directory): + """This method is used to create the directory when app starts""" + try: + if not os.path.exists(directory): + os.makedirs(directory) + except OSError: + print ('Error: Creating directory. ' + directory) + + def get_default_image(self): + if BMConfigParser().addresses(): + # BMConfigParser().addresses()[0] + return './images/default_identicon/{}.png'.format(BMConfigParser().addresses()[0]) + return '' + @staticmethod def addressexist(): """Checking address existence.""" @@ -1206,7 +1242,7 @@ class NavigateApp(App): return state.all_count @staticmethod - def current_address_label(current_add_label = None, current_addr = None): + def current_address_label(current_add_label=None, current_addr=None): """Getting current address labels.""" if BMConfigParser().addresses(): if current_add_label: @@ -1264,6 +1300,17 @@ class NavigateApp(App): text_field.bind(text=self.searchQuery) self.root.ids.search_bar.add_widget(text_field) + def set_identicon(self, text): + """This method is use for showing identicon in address spinner""" + img = identiconGeneration.generate(text) + img.size = 20, 20 + img.y = self.root.children[2].children[0].ids.btn.children[0].y + img.x = 5 + self.root.children[2].children[0].ids.btn.add_widget(img) + + def address_identicon(self): + return './images/drawer_logo1.png' + class GrashofPopup(Popup): """Methods for saving contacts, error messages.""" @@ -1280,19 +1327,16 @@ class GrashofPopup(Popup): def savecontact(self): """Method is used for Saving Contacts.""" - my_addresses = \ - self.parent.children[1].children[2].children[0].ids.btn.values - entered_text = str(self.ids.address.text) - if entered_text in my_addresses: - self.ids.address.focus = False - self.ids.address.helper_text = 'Please Enter corrent address' - elif entered_text == '': + label = self.ids.label.text.strip() + address = self.ids.address.text.strip() + if label == '' and address == '': + self.ids.label.focus = True + self.ids.address.focus = True + elif address == '': + self.ids.address.focus = True + elif label == '': self.ids.label.focus = True - # self.ids.address.focus = True - self.ids.label.helper_text = 'This field is required' - label = self.ids.label.text - address = self.ids.address.text stored_address = [addr[1] for addr in kivy_helper_search.search_sql( folder="addressbook")] if label and address and address not in stored_address: @@ -1328,6 +1372,30 @@ class GrashofPopup(Popup): """Pop is Canceled.""" toast('Canceled') + def checkAddress_valid(self, instance): + my_addresses = self.parent.children[1].children[2].children[0].ids.btn.values + add_book = [addr[1] for addr in kivy_helper_search.search_sql( + folder="addressbook")] + entered_text = str(instance.text).strip() + if entered_text in add_book: + text = 'Address is already in the addressbook.' + elif entered_text in my_addresses: + text = 'You can not save your own address.' + + if entered_text in my_addresses or entered_text in add_book: + if len(self.ids.popup_box.children) <= 2: + err_msg = MDLabel( + id='erro_msg', + font_style='Body2', + text=text, + font_size=5) + err_msg.color = 1, 0, 0, 1 + self.ids.popup_box.add_widget(err_msg) + self.ids.save_addr.disabled = True + elif len(self.ids.popup_box.children) > 2: + self.ids.popup_box.remove_widget(self.ids.popup_box.children[0]) + self.ids.save_addr.disabled = False + class AvatarSampleWidget(ILeftBody, Image): """Avatar Sample Widget.""" @@ -1443,7 +1511,7 @@ class MailDetail(Screen): self.parent.parent.current = 'allmails' state.is_allmail = False else: - self.parent.parent.current = state.detailPageType + self.parent.parent.current = state.detailPageType msg_count_objs.trash_cnt.badge_text = str(int(state.trash_count) + 1) msg_count_objs.allmail_cnt.badge_text = str(int(state.all_count) - 1) state.trash_count = str(int(state.trash_count) + 1) @@ -1484,6 +1552,15 @@ class MailDetail(Screen): self.parent.parent.current = 'create' navApp.set_navbar_for_composer() + def copy_composer_text(self, instance, *args): + """This method is used for copying the data from mail detail page""" + if len(instance.parent.text.split(':')) > 1: + cpy_text = instance.parent.text.split(':')[1].strip() + else: + cpy_text = instance.parent.text + Clipboard.copy(cpy_text) + toast('Copied') + class MyaddDetailPopup(Popup): """MyaddDetailPopup pop is used for showing my address detail.""" @@ -1651,7 +1728,7 @@ class Draft(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.delete_draft, item['lastactiontime'])) carousel.add_widget(del_btn) @@ -1694,12 +1771,12 @@ class Draft(Screen): if int(state.draft_count) > 0: msg_count_objs.draft_cnt.badge_text = str( int(state.draft_count) - 1) - msg_count_objs.allmail_cnt.badge_text = str( - int(state.all_count) - 1) + # msg_count_objs.allmail_cnt.badge_text = str( + # int(state.all_count) - 1) # msg_count_objs.trash_cnt.badge_text = str( # int(state.trash_count) + 1) state.draft_count = str(int(state.draft_count) - 1) - state.all_count = str(int(state.all_count) - 1) + # state.all_count = str(int(state.all_count) - 1) # state.trash_count = str(int(state.trash_count) + 1) self.ids.ml.remove_widget(instance.parent.parent) toast('Deleted') @@ -1764,8 +1841,9 @@ class CustomSpinner(Spinner): def __init__(self, *args, **kwargs): """Method used for setting size of spinner.""" super(CustomSpinner, self).__init__(*args, **kwargs) - max_value = 2.8 - self.dropdown_cls.max_height = self.height * max_value + max_value * 4 + # max_value = 2.8 + # self.dropdown_cls.max_height = self.height / 2 * max_value + max_value * 4 + self.dropdown_cls.max_height = Window.size[1] / 3 def remove_search_bar(obj): @@ -1814,17 +1892,12 @@ class Allmails(Screen): if all_mails: for item in all_mails: meny = ThreeLineAvatarIconListItem( - text='Draft' if item[4] == 'draft' else item[1], - secondary_text=item[1] if item[4] == 'draft' else item[2], + text=item[1], + secondary_text=item[2][:50] + '........' if len(item[2]) >= 50 else (item[2] + ',' + item[3].replace('\n', ''))[0:50] + '........', theme_text_color='Custom', text_color=NavigateApp().theme_cls.primary_color) - img_latter = './images/avatar.png' if item[ - 4] == 'draft' else './images/text_images/{}.png'.format( - item[2][0].upper() if ( - item[2][0].upper() >= 'A' and item[ - 2][0].upper() <= 'Z') else '!') meny.add_widget(AvatarSampleWidget( - source=img_latter)) + source='./images/text_images/{}.png'.format(avatarImageFirstLetter(item[2].strip())))) meny.bind(on_press=partial( self.mail_detail, item[5], item[4])) carousel = Carousel(direction='right') @@ -1838,7 +1911,7 @@ class Allmails(Screen): carousel.min_move = 0.2 del_btn = Button(text='Delete') del_btn.background_normal = '' - del_btn.background_color = (1.0, 0.0, 0.0, 1.0) + del_btn.background_color = (1, 0, 0, 1) del_btn.bind(on_press=partial( self.swipe_delete, item[5], item[4])) carousel.add_widget(del_btn) @@ -1927,3 +2000,15 @@ class Allmails(Screen): self.ids.refresh_layout.refresh_done() self.tick = 0 Clock.schedule_once(refresh_callback, 1) + + +def avatarImageFirstLetter(letter_string): + """This method is used to the first letter for the avatar image""" + if letter_string[0].upper() >= 'A' and letter_string[0].upper() <= 'Z': + img_latter = letter_string[0].upper() + elif int(letter_string[0]) >= 0 and int(letter_string[0]) <= 9: + img_latter = letter_string[0] + else: + img_latter = '!' + + return img_latter \ No newline at end of file diff --git a/src/identiconGeneration.py b/src/identiconGeneration.py new file mode 100644 index 00000000..2465c030 --- /dev/null +++ b/src/identiconGeneration.py @@ -0,0 +1,82 @@ +import hashlib +from PIL import Image +from kivy.core.image import Image as CoreImage +# Core classes for loading images and converting them to a Texture. The raw image data can be keep in memory for further access +from kivy.uix.image import Image as kiImage +from io import BytesIO + +# constants +RESOLUTION = 128, 128 +V_RESOLUTION = 7, 7 +BACKGROUND_COLOR = 255, 255, 255, 255 +MODE = "RGB" + + +def generate(Generate_string=None): + hash_string = generate_hash(Generate_string) + color = random_color(hash_string) + image = Image.new(MODE, V_RESOLUTION, BACKGROUND_COLOR) + image = generate_image(image, color, hash_string) + image = image.resize(RESOLUTION, 0) + + data = BytesIO() + image.save(data, format='png') + data.seek(0) + # yes you actually need this + im = CoreImage(BytesIO(data.read()), ext='png') + beeld = kiImage() + # only use this line in first code instance + beeld.texture = im.texture + return beeld + # image.show() + + +def generate_hash(string): + try: + # make input case insensitive + string = str.lower(string) + hash_object = hashlib.md5(str.encode(string)) + print(hash_object.hexdigest()) + + # returned object is a hex string + return hash_object.hexdigest() + + except IndexError: + print("Error: Please enter a string as an argument.") + + +def random_color(hash_string): + # remove first three digits from hex string + split = 6 + rgb = hash_string[:split] + + split = 2 + r = rgb[:split] + g = rgb[split:2 * split] + b = rgb[2 * split:3 * split] + + color = (int(r, 16), int(g, 16), + int(b, 16), 0xFF) + + return color + + +def generate_image(image, color, hash_string): + hash_string = hash_string[6:] + + lower_x = 1 + lower_y = 1 + upper_x = int(V_RESOLUTION[0] / 2) + 1 + upper_y = V_RESOLUTION[1] - 1 + limit_x = V_RESOLUTION[0] - 1 + index = 0 + + for x in range(lower_x, upper_x): + for y in range(lower_y, upper_y): + if int(hash_string[index], 16) % 2 == 0: + image.putpixel((x, y), color) + image.putpixel((limit_x - x, y), color) + + index = index + 1 + + return image diff --git a/src/images/copy_text.png b/src/images/copy_text.png new file mode 100644 index 00000000..dcc63611 Binary files /dev/null and b/src/images/copy_text.png differ