Kivy - General fixes/improvements #2281
@ -55,13 +55,13 @@ class Random(Screen):
|
|||||||
toast('Creating New Address ...')
|
toast('Creating New Address ...')
|
||||||
self.parent.parent.ids.toolbar.opacity = 1
|
self.parent.parent.ids.toolbar.opacity = 1
|
||||||
self.parent.parent.ids.toolbar.disabled = False
|
self.parent.parent.ids.toolbar.disabled = False
|
||||||
App.get_running_app().loadMyAddressScreen(True)
|
App.get_running_app().load_my_address_screen(True)
|
||||||
self.manager.current = 'myaddress'
|
self.manager.current = 'myaddress'
|
||||||
Clock.schedule_once(self.address_created_callback, 6)
|
Clock.schedule_once(self.address_created_callback, 6)
|
||||||
|
|
||||||
def address_created_callback(self, dt=0):
|
def address_created_callback(self, dt=0):
|
||||||
"""New address created"""
|
"""New address created"""
|
||||||
App.get_running_app().loadMyAddressScreen(False)
|
App.get_running_app().load_my_address_screen(False)
|
||||||
App.get_running_app().root.ids.id_myaddress.ids.ml.clear_widgets()
|
App.get_running_app().root.ids.id_myaddress.ids.ml.clear_widgets()
|
||||||
App.get_running_app().root.ids.id_myaddress.is_add_created = True
|
App.get_running_app().root.ids.id_myaddress.is_add_created = True
|
||||||
App.get_running_app().root.ids.id_myaddress.init_ui()
|
App.get_running_app().root.ids.id_myaddress.init_ui()
|
||||||
|
@ -26,7 +26,7 @@ class ShowQRCode(Screen):
|
|||||||
def qrdisplay(self, instance, address):
|
def qrdisplay(self, instance, address):
|
||||||
"""Method used for showing QR Code"""
|
"""Method used for showing QR Code"""
|
||||||
self.ids.qr.clear_widgets()
|
self.ids.qr.clear_widgets()
|
||||||
self.kivy_running_app.set_toolbar_for_QrCode()
|
self.kivy_running_app.set_toolbar_for_qr_code()
|
||||||
self.address = address # used for label
|
self.address = address # used for label
|
||||||
self.ids.qr.add_widget(QRCodeWidget(data=self.address))
|
self.ids.qr.add_widget(QRCodeWidget(data=self.address))
|
||||||
self.ids.qr.children[0].show_border = False
|
self.ids.qr.children[0].show_border = False
|
||||||
|
@ -115,11 +115,11 @@
|
|||||||
name: "identity_dropdown"
|
name: "identity_dropdown"
|
||||||
option_cls: Factory.get("MySpinnerOption")
|
option_cls: Factory.get("MySpinnerOption")
|
||||||
font_size: '12.5sp'
|
font_size: '12.5sp'
|
||||||
text: app.getDefaultAccData(self)
|
text: app.get_default_account_data(self)
|
||||||
color: color_font
|
color: color_font
|
||||||
background_normal: ''
|
background_normal: ''
|
||||||
background_color: app.theme_cls.primary_color
|
background_color: app.theme_cls.primary_color
|
||||||
on_text: app.getCurrentAccountData(self.text)
|
on_text: app.get_current_account_data(self.text)
|
||||||
ArrowImg:
|
ArrowImg:
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
id: inbox_cnt
|
id: inbox_cnt
|
||||||
@ -141,14 +141,14 @@
|
|||||||
text: app.tr._('Draft')
|
text: app.tr._('Draft')
|
||||||
icon: 'message-draw'
|
icon: 'message-draw'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'draft'
|
on_release: app.set_screen('draft')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
id: trash_cnt
|
id: trash_cnt
|
||||||
text: app.tr._('Trash')
|
text: app.tr._('Trash')
|
||||||
icon: 'delete'
|
icon: 'delete'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'trash'
|
on_release: app.set_screen('trash')
|
||||||
on_press: root.parent.set_state()
|
on_press: root.parent.set_state()
|
||||||
on_press: app.load_screen(self)
|
on_press: app.load_screen(self)
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
@ -156,7 +156,7 @@
|
|||||||
text: app.tr._('All Mails')
|
text: app.tr._('All Mails')
|
||||||
icon: 'mailbox'
|
icon: 'mailbox'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'allmails'
|
on_release: app.set_screen('allmails')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
on_press: app.load_screen(self)
|
on_press: app.load_screen(self)
|
||||||
NavigationDrawerDivider:
|
NavigationDrawerDivider:
|
||||||
@ -167,7 +167,7 @@
|
|||||||
text: app.tr._('Chat')
|
text: app.tr._('Chat')
|
||||||
icon: 'chat'
|
icon: 'chat'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'chat'
|
on_release: app.set_screen('chat')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationDrawerDivider:
|
NavigationDrawerDivider:
|
||||||
NavigationDrawerSubheader:
|
NavigationDrawerSubheader:
|
||||||
@ -176,38 +176,38 @@
|
|||||||
text: app.tr._('Address Book')
|
text: app.tr._('Address Book')
|
||||||
icon: 'book-multiple'
|
icon: 'book-multiple'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'addressbook'
|
on_release: app.set_screen('addressbook')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
text: app.tr._('Settings')
|
text: app.tr._('Settings')
|
||||||
icon: 'application-settings'
|
icon: 'application-settings'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'set'
|
on_release: app.set_screen('set')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
text: app.tr._('Payment plan')
|
text: app.tr._('Payment plan')
|
||||||
icon: 'shopping'
|
icon: 'shopping'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'payment'
|
on_release: app.set_screen('payment')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
text: app.tr._('New address')
|
text: app.tr._('New address')
|
||||||
icon: 'account-plus'
|
icon: 'account-plus'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'login'
|
on_release: app.set_screen('login')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
on_press: app.reset_login_screen()
|
on_press: app.reset_login_screen()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
text: app.tr._('Network status')
|
text: app.tr._('Network status')
|
||||||
icon: 'server-network'
|
icon: 'server-network'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'networkstat'
|
on_release: app.set_screen('networkstat')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
NavigationItem:
|
NavigationItem:
|
||||||
text: app.tr._('My addresses')
|
text: app.tr._('My addresses')
|
||||||
icon: 'account-multiple'
|
icon: 'account-multiple'
|
||||||
divider: None
|
divider: None
|
||||||
on_release: app.root.ids.scr_mngr.current = 'myaddress'
|
on_release: app.set_screen('myaddress')
|
||||||
on_release: root.parent.set_state()
|
on_release: root.parent.set_state()
|
||||||
|
|
||||||
MDNavigationLayout:
|
MDNavigationLayout:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# pylint: disable=too-many-public-methods, unused-variable, too-many-ancestors
|
# pylint: disable=too-many-public-methods, unused-variable, too-many-ancestors
|
||||||
# pylint: disable=no-name-in-module, too-few-public-methods, unused-argument
|
# pylint: disable=too-few-public-methods, unused-argument
|
||||||
# pylint: disable=attribute-defined-outside-init, too-many-instance-attributes
|
# pylint: disable=attribute-defined-outside-init, too-many-instance-attributes
|
||||||
|
# pylint: disable=broad-exception-caught, no-self-use
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Bitmessage android(mobile) interface
|
Bitmessage android(mobile) interface
|
||||||
@ -16,6 +17,7 @@ from kivy.clock import Clock
|
|||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.core.clipboard import Clipboard
|
||||||
|
|
||||||
from kivymd.app import MDApp
|
from kivymd.app import MDApp
|
||||||
from kivymd.uix.label import MDLabel
|
from kivymd.uix.label import MDLabel
|
||||||
@ -42,7 +44,6 @@ from pybitmessage.bitmessagekivy.load_kivy_screens_data import load_screen_json
|
|||||||
from pybitmessage.bitmessagekivy.baseclass.popup import (
|
from pybitmessage.bitmessagekivy.baseclass.popup import (
|
||||||
AddAddressPopup, AppClosingPopup, AddressChangingLoader
|
AddAddressPopup, AppClosingPopup, AddressChangingLoader
|
||||||
)
|
)
|
||||||
from pybitmessage.bitmessagekivy.baseclass.login import * # noqa: F401, F403
|
|
||||||
from pybitmessage.bitmessagekivy.uikivysignaler import UIkivySignaler
|
from pybitmessage.bitmessagekivy.uikivysignaler import UIkivySignaler
|
||||||
|
|
||||||
from pybitmessage.mockbm.helper_startup import loadConfig, total_encrypted_messages_per_month
|
from pybitmessage.mockbm.helper_startup import loadConfig, total_encrypted_messages_per_month
|
||||||
@ -166,7 +167,9 @@ class NavigateApp(MDApp):
|
|||||||
self.root.ids.scr_mngr.current = 'scanscreen'
|
self.root.ids.scr_mngr.current = 'scanscreen'
|
||||||
else:
|
else:
|
||||||
alert_text = (
|
alert_text = (
|
||||||
'Currently this feature is not avaialbe!' if platform == 'android' else 'Camera is not available!')
|
'Currently this feature is not avaialbe!'
|
||||||
|
if platform == 'android'
|
||||||
|
else 'Camera is not available!')
|
||||||
self.add_popup.dismiss()
|
self.add_popup.dismiss()
|
||||||
toast(alert_text)
|
toast(alert_text)
|
||||||
|
|
||||||
@ -190,8 +193,8 @@ class NavigateApp(MDApp):
|
|||||||
self.add_popup.dismiss()
|
self.add_popup.dismiss()
|
||||||
toast('Canceled')
|
toast('Canceled')
|
||||||
|
|
||||||
def loadMyAddressScreen(self, action):
|
def load_my_address_screen(self, action):
|
||||||
"""loadMyAddressScreen method spin the loader"""
|
"""load_my_address_screen method spin the loader"""
|
||||||
if len(self.root.ids.id_myaddress.children) <= 2:
|
if len(self.root.ids.id_myaddress.children) <= 2:
|
||||||
self.root.ids.id_myaddress.children[0].active = action
|
self.root.ids.id_myaddress.children[0].active = action
|
||||||
else:
|
else:
|
||||||
@ -261,20 +264,20 @@ class NavigateApp(MDApp):
|
|||||||
NavigateApp.format_address(address)
|
NavigateApp.format_address(address)
|
||||||
)
|
)
|
||||||
|
|
||||||
def getDefaultAccData(self, instance):
|
def get_default_account_data(self, instance):
|
||||||
"""Getting Default Account Data"""
|
"""Getting Default Account Data"""
|
||||||
if self.identity_list:
|
if self.identity_list:
|
||||||
self.kivy_state_obj.selected_address = first_addr = self.identity_list[0]
|
self.kivy_state_obj.selected_address = first_addr = self.identity_list[0]
|
||||||
return first_addr
|
return first_addr
|
||||||
return 'Select Address'
|
return 'Select Address'
|
||||||
|
|
||||||
def getCurrentAccountData(self, text):
|
def get_current_account_data(self, text):
|
||||||
"""Get Current Address Account Data"""
|
"""Get Current Address Account Data"""
|
||||||
if text != '':
|
if text != '':
|
||||||
if os.path.exists(os.path.join(
|
if os.path.exists(os.path.join(
|
||||||
self.image_dir, 'default_identicon', '{}.png'.format(text))
|
self.image_dir, 'default_identicon', '{}.png'.format(text))
|
||||||
):
|
):
|
||||||
self.load_selected_Image(text)
|
self.load_selected_image(text)
|
||||||
else:
|
else:
|
||||||
self.set_identicon(text)
|
self.set_identicon(text)
|
||||||
self.root.ids.content_drawer.ids.reset_image.opacity = 0
|
self.root.ids.content_drawer.ids.reset_image.opacity = 0
|
||||||
@ -286,10 +289,10 @@ class NavigateApp(MDApp):
|
|||||||
for nav_obj in self.root.ids.content_drawer.children[
|
for nav_obj in self.root.ids.content_drawer.children[
|
||||||
0].children[0].children[0].children:
|
0].children[0].children[0].children:
|
||||||
nav_obj.active = True if nav_obj.text == 'Inbox' else False
|
nav_obj.active = True if nav_obj.text == 'Inbox' else False
|
||||||
self.fileManagerSetting()
|
self.file_manager_setting()
|
||||||
Clock.schedule_once(self.setCurrentAccountData, 0.5)
|
Clock.schedule_once(self.set_current_account_data, 0.5)
|
||||||
|
|
||||||
def setCurrentAccountData(self, dt=0):
|
def set_current_account_data(self, dt=0):
|
||||||
"""This method set the current accout data on all the screens"""
|
"""This method set the current accout data on all the screens"""
|
||||||
self.root.ids.id_inbox.ids.ml.clear_widgets()
|
self.root.ids.id_inbox.ids.ml.clear_widgets()
|
||||||
self.root.ids.id_inbox.loadMessagelist(self.kivy_state_obj.selected_address)
|
self.root.ids.id_inbox.loadMessagelist(self.kivy_state_obj.selected_address)
|
||||||
@ -298,7 +301,7 @@ class NavigateApp(MDApp):
|
|||||||
self.root.ids.id_sent.children[2].children[2].ids.search_field.text = ''
|
self.root.ids.id_sent.children[2].children[2].ids.search_field.text = ''
|
||||||
self.root.ids.id_sent.loadSent(self.kivy_state_obj.selected_address)
|
self.root.ids.id_sent.loadSent(self.kivy_state_obj.selected_address)
|
||||||
|
|
||||||
def fileManagerSetting(self):
|
def file_manager_setting(self):
|
||||||
"""This method is for file manager setting"""
|
"""This method is for file manager setting"""
|
||||||
if not self.root.ids.content_drawer.ids.file_manager.opacity and \
|
if not self.root.ids.content_drawer.ids.file_manager.opacity and \
|
||||||
self.root.ids.content_drawer.ids.file_manager.disabled:
|
self.root.ids.content_drawer.ids.file_manager.disabled:
|
||||||
@ -335,7 +338,7 @@ class NavigateApp(MDApp):
|
|||||||
def set_identicon(self, text):
|
def set_identicon(self, text):
|
||||||
"""Show identicon in address spinner"""
|
"""Show identicon in address spinner"""
|
||||||
img = identiconGeneration.generate(text)
|
img = identiconGeneration.generate(text)
|
||||||
self.root.ids.content_drawer.ids.top_box.children[0].texture = (img.texture)
|
self.root.ids.content_drawer.ids.top_box.children[0].texture = img.texture
|
||||||
|
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
def file_manager_open(self):
|
def file_manager_open(self):
|
||||||
@ -356,7 +359,9 @@ class NavigateApp(MDApp):
|
|||||||
self.file_manager.show(os.getenv('EXTERNAL_STORAGE'))
|
self.file_manager.show(os.getenv('EXTERNAL_STORAGE'))
|
||||||
self.kivy_state_obj.manager_open = True
|
self.kivy_state_obj.manager_open = True
|
||||||
else:
|
else:
|
||||||
request_permissions([Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE])
|
request_permissions(
|
||||||
|
[Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.file_manager.show(os.environ["HOME"])
|
self.file_manager.show(os.environ["HOME"])
|
||||||
self.kivy_state_obj.manager_open = True
|
self.kivy_state_obj.manager_open = True
|
||||||
@ -364,23 +369,23 @@ class NavigateApp(MDApp):
|
|||||||
def select_path(self, path):
|
def select_path(self, path):
|
||||||
"""This method is used to set the select image"""
|
"""This method is used to set the select image"""
|
||||||
try:
|
try:
|
||||||
newImg = PilImage.open(path).resize((300, 300))
|
new_image = PilImage.open(path).resize((300, 300))
|
||||||
if platform == 'android':
|
if platform == 'android':
|
||||||
android_path = os.path.join(
|
android_path = os.path.join(
|
||||||
os.path.join(os.environ['ANDROID_PRIVATE'], 'app', 'images', 'kivy')
|
os.path.join(os.environ['ANDROID_PRIVATE'], 'app', 'images', 'kivy')
|
||||||
)
|
)
|
||||||
if not os.path.exists(os.path.join(android_path, 'default_identicon')):
|
if not os.path.exists(os.path.join(android_path, 'default_identicon')):
|
||||||
os.makedirs(os.path.join(android_path, 'default_identicon'))
|
os.makedirs(os.path.join(android_path, 'default_identicon'))
|
||||||
newImg.save(os.path.join(android_path, 'default_identicon', '{}.png'.format(
|
new_image.save(os.path.join(android_path, 'default_identicon', '{}.png'.format(
|
||||||
self.kivy_state_obj.selected_address))
|
self.kivy_state_obj.selected_address))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not os.path.exists(os.path.join(self.image_dir, 'default_identicon')):
|
if not os.path.exists(os.path.join(self.image_dir, 'default_identicon')):
|
||||||
os.makedirs(os.path.join(self.image_dir, 'default_identicon'))
|
os.makedirs(os.path.join(self.image_dir, 'default_identicon'))
|
||||||
newImg.save(os.path.join(self.image_dir, 'default_identicon', '{0}.png'.format(
|
new_image.save(os.path.join(self.image_dir, 'default_identicon', '{0}.png'.format(
|
||||||
self.kivy_state_obj.selected_address))
|
self.kivy_state_obj.selected_address))
|
||||||
)
|
)
|
||||||
self.load_selected_Image(self.kivy_state_obj.selected_address)
|
self.load_selected_image(self.kivy_state_obj.selected_address)
|
||||||
toast('Image changed')
|
toast('Image changed')
|
||||||
except Exception:
|
except Exception:
|
||||||
toast('Exit')
|
toast('Exit')
|
||||||
@ -391,10 +396,14 @@ class NavigateApp(MDApp):
|
|||||||
self.kivy_state_obj.manager_open = False
|
self.kivy_state_obj.manager_open = False
|
||||||
self.file_manager.close()
|
self.file_manager.close()
|
||||||
|
|
||||||
def load_selected_Image(self, curerentAddr):
|
def load_selected_image(self, curerent_addr):
|
||||||
"""This method load the selected image on screen"""
|
"""This method load the selected image on screen"""
|
||||||
top_box_obj = self.root.ids.content_drawer.ids.top_box.children[0]
|
top_box_obj = self.root.ids.content_drawer.ids.top_box.children[0]
|
||||||
top_box_obj.source = os.path.join(self.image_dir, 'default_identicon', '{0}.png'.format(curerentAddr))
|
top_box_obj.source = os.path.join(
|
||||||
|
self.image_dir,
|
||||||
|
'default_identicon',
|
||||||
|
'{0}.png'.format(curerent_addr)
|
||||||
|
)
|
||||||
self.root.ids.content_drawer.ids.reset_image.opacity = 1
|
self.root.ids.content_drawer.ids.reset_image.opacity = 1
|
||||||
self.root.ids.content_drawer.ids.reset_image.disabled = False
|
self.root.ids.content_drawer.ids.reset_image.disabled = False
|
||||||
top_box_obj.reload()
|
top_box_obj.reload()
|
||||||
@ -403,7 +412,8 @@ class NavigateApp(MDApp):
|
|||||||
"""set default avatar generated image"""
|
"""set default avatar generated image"""
|
||||||
self.set_identicon(self.kivy_state_obj.selected_address)
|
self.set_identicon(self.kivy_state_obj.selected_address)
|
||||||
img_path = os.path.join(
|
img_path = os.path.join(
|
||||||
self.image_dir, 'default_identicon', '{}.png'.format(self.kivy_state_obj.selected_address)
|
self.image_dir, 'default_identicon',
|
||||||
|
'{}.png'.format(self.kivy_state_obj.selected_address)
|
||||||
)
|
)
|
||||||
if os.path.exists(img_path):
|
if os.path.exists(img_path):
|
||||||
os.remove(img_path)
|
os.remove(img_path)
|
||||||
@ -455,7 +465,7 @@ class NavigateApp(MDApp):
|
|||||||
self.root.ids.scr_mngr.transition.bind(on_complete=self.reset)
|
self.root.ids.scr_mngr.transition.bind(on_complete=self.reset)
|
||||||
self.kivy_state.in_composer = False
|
self.kivy_state.in_composer = False
|
||||||
|
|
||||||
def set_toolbar_for_QrCode(self):
|
def set_toolbar_for_qr_code(self):
|
||||||
"""This method is use for setting Qr code toolbar."""
|
"""This method is use for setting Qr code toolbar."""
|
||||||
self.root.ids.toolbar.left_action_items = [
|
self.root.ids.toolbar.left_action_items = [
|
||||||
['arrow-left', lambda x: self.back_press()]]
|
['arrow-left', lambda x: self.back_press()]]
|
||||||
@ -480,6 +490,10 @@ class NavigateApp(MDApp):
|
|||||||
"""initiate_purchase module"""
|
"""initiate_purchase module"""
|
||||||
logger.debug("Purchasing %s through %s", self.product_id, method_name)
|
logger.debug("Purchasing %s through %s", self.product_id, method_name)
|
||||||
|
|
||||||
|
def copy_composer_text(self, text):
|
||||||
|
"""Copy text to clipboard"""
|
||||||
|
Clipboard.copy(text)
|
||||||
|
|
||||||
|
|
||||||
class PaymentMethodLayout(BoxLayout):
|
class PaymentMethodLayout(BoxLayout):
|
||||||
"""PaymentMethodLayout class for kivy Ui"""
|
"""PaymentMethodLayout class for kivy Ui"""
|
||||||
|
@ -4,7 +4,10 @@ from pybitmessage.bmconfigparser import config
|
|||||||
|
|
||||||
def loadConfig():
|
def loadConfig():
|
||||||
"""Loading mock test data"""
|
"""Loading mock test data"""
|
||||||
|
try:
|
||||||
config.read(os.path.join(os.environ['BITMESSAGE_HOME'], 'keys.dat'))
|
config.read(os.path.join(os.environ['BITMESSAGE_HOME'], 'keys.dat'))
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def total_encrypted_messages_per_month():
|
def total_encrypted_messages_per_month():
|
||||||
|
Reference in New Issue
Block a user