This repository has been archived on 2024-12-03. You can view files and clone it, but cannot push or open issues or pull requests.
PyBitmessage-2024-12-03/src/bitmessagekivy/mpybit.py

340 lines
13 KiB
Python
Raw Normal View History

2022-09-12 11:58:53 +02:00
# 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=attribute-defined-outside-init, too-many-instance-attributes
2022-08-04 18:29:02 +02:00
"""
2022-08-04 18:29:02 +02:00
Bitmessage android(mobile) interface
"""
2022-08-04 18:29:02 +02:00
import os
import logging
import sys
2022-08-23 15:41:46 +02:00
from functools import partial
2022-09-12 11:58:53 +02:00
from PIL import Image as PilImage
2022-08-04 18:29:02 +02:00
2022-08-23 15:41:46 +02:00
from kivy.clock import Clock
2022-08-05 13:08:37 +02:00
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
2022-08-04 18:29:02 +02:00
2022-08-05 13:08:37 +02:00
from kivymd.app import MDApp
2022-08-19 18:13:41 +02:00
from kivymd.uix.label import MDLabel
2022-08-22 18:14:12 +02:00
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import (
2022-08-22 10:06:40 +02:00
IRightBodyTouch
)
2022-08-22 18:14:12 +02:00
from kivymd.uix.button import MDRaisedButton
2022-08-16 17:29:37 +02:00
from kivymd.uix.bottomsheet import MDCustomBottomSheet
2022-08-24 13:23:02 +02:00
from kivymd.uix.filemanager import MDFileManager
2022-08-16 17:29:37 +02:00
2022-08-05 13:08:37 +02:00
from pybitmessage.bitmessagekivy.kivy_state import KivyStateVariables
2022-08-19 18:13:41 +02:00
from pybitmessage.bitmessagekivy.base_navigation import (
BaseLanguage, BaseNavigationItem, BaseNavigationDrawerDivider,
BaseNavigationDrawerSubheader, BaseContentNavigationDrawer,
BaseIdentitySpinner
2022-08-19 18:13:41 +02:00
)
2022-09-01 11:35:23 +02:00
from pybitmessage.bmconfigparser import config # noqa: F401
2022-08-24 13:23:02 +02:00
from pybitmessage.bitmessagekivy import identiconGeneration
2022-08-22 18:14:12 +02:00
from pybitmessage.bitmessagekivy.get_platform import platform
2022-09-01 11:35:23 +02:00
from pybitmessage.bitmessagekivy.baseclass.common import toast, load_image_path, get_identity_list
from pybitmessage.bitmessagekivy.load_kivy_screens_data import load_screen_json
2022-08-22 18:14:12 +02:00
from pybitmessage.bitmessagekivy.baseclass.popup import AddAddressPopup
2022-09-12 11:58:53 +02:00
from pybitmessage.bitmessagekivy.baseclass.login import * # noqa: F401, F403
logger = logging.getLogger('default')
2022-08-22 10:06:40 +02:00
2022-08-19 18:13:41 +02:00
class Lang(BaseLanguage):
2022-08-05 13:08:37 +02:00
"""UI Language"""
2022-08-19 18:13:41 +02:00
class NavigationItem(BaseNavigationItem):
"""NavigationItem class for kivy Ui"""
2022-08-19 18:13:41 +02:00
class NavigationDrawerDivider(BaseNavigationDrawerDivider):
"""
2022-08-19 18:13:41 +02:00
A small full-width divider that can be placed
in the :class:`MDNavigationDrawer`
"""
2022-08-19 18:13:41 +02:00
class NavigationDrawerSubheader(BaseNavigationDrawerSubheader):
"""
A subheader for separating content in :class:`MDNavigationDrawer`
2022-08-19 18:13:41 +02:00
Works well alongside :class:`NavigationDrawerDivider`
"""
2022-08-19 18:13:41 +02:00
class ContentNavigationDrawer(BaseContentNavigationDrawer):
"""ContentNavigationDrawer class for kivy Uir"""
2022-08-19 18:13:41 +02:00
class BadgeText(IRightBodyTouch, MDLabel):
"""BadgeText class for kivy Ui"""
class IdentitySpinner(BaseIdentitySpinner):
2022-08-22 10:06:40 +02:00
"""Identity Dropdown in Side Navigation bar"""
2022-08-04 18:29:02 +02:00
class NavigateApp(MDApp):
"""Navigation Layout of class"""
2022-08-10 13:44:13 +02:00
kivy_state = KivyStateVariables()
2022-08-04 18:29:02 +02:00
title = "PyBitmessage"
identity_list = get_identity_list()
2022-09-01 11:35:23 +02:00
image_path = load_image_path()
2022-09-07 15:58:23 +02:00
app_platform = platform
2022-08-04 18:29:02 +02:00
tr = Lang("en") # for changing in franch replace en with fr
2022-08-22 18:14:12 +02:00
def __init__(self):
super(NavigateApp, self).__init__()
2022-09-12 11:58:53 +02:00
# workaround for relative imports
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
2022-09-01 11:35:23 +02:00
self.data_screens, self.all_data, self.data_screen_dict, response = load_screen_json()
2022-08-22 18:14:12 +02:00
self.kivy_state_obj = KivyStateVariables()
2022-09-01 11:35:23 +02:00
self.image_dir = load_image_path()
2022-10-11 09:21:05 +02:00
self.kivy_state_obj.screen_density = Window.size
self.window_size = self.kivy_state_obj.screen_density
2022-08-22 18:14:12 +02:00
2022-08-22 10:06:40 +02:00
def build(self):
"""Method builds the widget"""
for kv in self.data_screens:
2022-08-04 18:29:02 +02:00
Builder.load_file(
os.path.join(
os.path.dirname(__file__),
'kv',
'{0}.kv'.format(self.all_data[kv]["kv_string"]),
2022-08-04 18:29:02 +02:00
)
)
2022-08-05 13:08:37 +02:00
return Builder.load_file(os.path.join(os.path.dirname(__file__), 'main.kv'))
2022-08-04 18:29:02 +02:00
def set_screen(self, screen_name):
2022-08-05 13:08:37 +02:00
"""Set the screen name when navigate to other screens"""
2022-08-04 18:29:02 +02:00
self.root.ids.scr_mngr.current = screen_name
def run(self):
"""Running the widgets"""
self.kivy_state_obj.kivyui_ready.set()
2022-08-04 18:29:02 +02:00
super(NavigateApp, self).run()
2022-08-22 18:14:12 +02:00
def addingtoaddressbook(self):
"""Dialog for saving address"""
width = .85 if platform == 'android' else .8
self.add_popup = MDDialog(
title='Add contact',
type="custom",
size_hint=(width, .23),
content_cls=AddAddressPopup(),
buttons=[
MDRaisedButton(
text="Save",
on_release=self.savecontact,
),
MDRaisedButton(
text="Cancel",
on_release=self.close_pop,
),
MDRaisedButton(
text="Scan QR code",
on_release=self.scan_qr_code,
),
],
)
self.add_popup.auto_dismiss = False
self.add_popup.open()
def scan_qr_code(self, instance):
"""this method is used for showing QR code scanner"""
if self.is_camara_attached():
self.add_popup.dismiss()
self.root.ids.id_scanscreen.get_screen(self.root.ids.scr_mngr.current, self.add_popup)
self.root.ids.scr_mngr.current = 'scanscreen'
else:
alert_text = (
'Currently this feature is not avaialbe!' if platform == 'android' else 'Camera is not available!')
self.add_popup.dismiss()
toast(alert_text)
def is_camara_attached(self):
"""This method is for checking the camera is available or not"""
self.root.ids.id_scanscreen.check_camera()
is_available = self.root.ids.id_scanscreen.camera_available
return is_available
def savecontact(self, instance):
"""Method is used for saving contacts"""
2022-09-12 11:58:53 +02:00
popup_obj = self.add_popup.content_cls
label = popup_obj.ids.label.text.strip()
address = popup_obj.ids.address.text.strip()
popup_obj.ids.label.focus = not label
# default focus on address field
popup_obj.ids.address.focus = label or not address
2022-08-22 18:14:12 +02:00
def close_pop(self, instance):
"""Close the popup"""
self.add_popup.dismiss()
toast('Canceled')
def loadMyAddressScreen(self, action):
"""loadMyAddressScreen method spin the loader"""
if len(self.root.ids.id_myaddress.children) <= 2:
self.root.ids.id_myaddress.children[0].active = action
else:
self.root.ids.id_myaddress.children[1].active = action
2022-08-10 13:44:13 +02:00
2022-08-23 15:41:46 +02:00
def load_screen(self, instance):
"""This method is used for loading screen on every click"""
if instance.text == 'Trash':
self.root.ids.scr_mngr.current = 'trash'
try:
self.root.ids.id_trash.children[1].active = True
except Exception as e:
self.root.ids.id_trash.children[0].children[1].active = True
Clock.schedule_once(partial(self.load_screen_callback, instance), 1)
def load_screen_callback(self, instance, dt=0):
"""This method is rotating loader for few seconds"""
if instance.text == 'Trash':
self.root.ids.id_trash.clear_widgets()
2022-09-01 11:35:23 +02:00
self.root.ids.id_trash.add_widget(self.data_screen_dict['Trash'].Trash())
2022-08-23 15:41:46 +02:00
try:
self.root.ids.id_trash.children[1].active = False
except Exception as e:
self.root.ids.id_trash.children[0].children[1].active = False
2022-08-24 13:23:02 +02:00
def fileManagerSetting(self):
"""This method is for file manager setting"""
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.opacity = 1
self.root.ids.content_drawer.ids.file_manager.disabled = False
def set_identicon(self, text):
"""Show identicon in address spinner"""
img = identiconGeneration.generate(text)
self.root.ids.content_drawer.ids.top_box.children[0].texture = (img.texture)
# pylint: disable=import-outside-toplevel
def file_manager_open(self):
"""This method open the file manager of local system"""
if not self.kivy_state_obj.file_manager:
self.file_manager = MDFileManager(
exit_manager=self.exit_manager,
select_path=self.select_path,
ext=['.png', '.jpg']
)
self.file_manager.previous = False
self.file_manager.current_path = '/'
if platform == 'android':
2022-09-12 11:58:53 +02:00
# pylint: disable=import-error
2022-08-24 13:23:02 +02:00
from android.permissions import request_permissions, Permission, check_permission
if check_permission(Permission.WRITE_EXTERNAL_STORAGE) and \
check_permission(Permission.READ_EXTERNAL_STORAGE):
self.file_manager.show(os.getenv('EXTERNAL_STORAGE'))
self.kivy_state_obj.manager_open = True
2022-08-24 13:23:02 +02:00
else:
request_permissions([Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE])
else:
self.file_manager.show(os.environ["HOME"])
self.kivy_state_obj.manager_open = True
2022-08-24 13:23:02 +02:00
def select_path(self, path):
"""This method is used to set the select image"""
try:
newImg = PilImage.open(path).resize((300, 300))
if platform == 'android':
android_path = os.path.join(
2022-09-12 11:58:53 +02:00
os.path.join(os.environ['ANDROID_PRIVATE'], 'app', 'images', 'kivy')
)
if not os.path.exists(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(
self.kivy_state_obj.association))
2022-08-24 13:23:02 +02:00
)
else:
2022-09-12 11:58:53 +02:00
if not os.path.exists(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(
self.kivy_state_obj.association))
2022-08-24 13:23:02 +02:00
)
self.load_selected_Image(self.kivy_state_obj.association)
toast('Image changed')
except Exception:
toast('Exit')
self.exit_manager()
def exit_manager(self, *args):
"""Called when the user reaches the root of the directory tree."""
self.kivy_state_obj.manager_open = False
2022-08-24 13:23:02 +02:00
self.file_manager.close()
def load_selected_Image(self, curerentAddr):
"""This method load the selected image on screen"""
top_box_obj = self.root.ids.content_drawer.ids.top_box.children[0]
2022-09-12 11:58:53 +02:00
top_box_obj.source = os.path.join(self.image_dir, 'default_identicon', '{0}.png'.format(curerentAddr))
2022-08-24 13:23:02 +02:00
self.root.ids.content_drawer.ids.reset_image.opacity = 1
self.root.ids.content_drawer.ids.reset_image.disabled = False
top_box_obj.reload()
def rest_default_avatar_img(self):
"""set default avatar generated image"""
self.set_identicon(self.kivy_state_obj.association)
2022-09-12 11:58:53 +02:00
img_path = os.path.join(
self.image_dir, 'default_identicon', '{}.png'.format(self.kivy_state_obj.association)
2022-08-24 13:23:02 +02:00
)
try:
if os.path.exists(img_path):
os.remove(img_path)
self.root.ids.content_drawer.ids.reset_image.opacity = 0
self.root.ids.content_drawer.ids.reset_image.disabled = True
except Exception as e:
pass
toast('Avatar reset')
2022-09-07 17:35:18 +02:00
def get_default_logo(self, instance):
"""Getting default logo image"""
if self.identity_list:
first_addr = self.identity_list[0]
if config.getboolean(str(first_addr), 'enabled'):
if os.path.exists(
2022-09-12 11:58:53 +02:00
os.path.join(
self.image_dir, 'default_identicon', '{}.png'.format(first_addr)
)
):
2022-09-12 11:58:53 +02:00
return os.path.join(
self.image_dir, 'default_identicon', '{}.png'.format(first_addr)
)
2022-09-07 17:35:18 +02:00
else:
img = identiconGeneration.generate(first_addr)
instance.texture = img.texture
return
2022-09-12 11:58:53 +02:00
return os.path.join(self.image_dir, 'drawer_logo1.png')
2022-09-07 17:35:18 +02:00
2022-08-10 13:44:13 +02:00
def reset_login_screen(self):
"""This method is used for clearing the widgets of random screen"""
if self.root.ids.id_newidentity.ids.add_random_bx.children:
self.root.ids.id_newidentity.ids.add_random_bx.clear_widgets()
2022-08-16 17:29:37 +02:00
def open_payment_layout(self, sku):
"""It basically open up a payment layout for kivy UI"""
pml = PaymentMethodLayout()
self.product_id = sku
self.custom_sheet = MDCustomBottomSheet(screen=pml)
self.custom_sheet.open()
def initiate_purchase(self, method_name):
"""initiate_purchase module"""
logger.debug("Purchasing %s through %s", self.product_id, method_name)
2022-08-16 17:29:37 +02:00
class PaymentMethodLayout(BoxLayout):
"""PaymentMethodLayout class for kivy Ui"""
if __name__ == '__main__':
NavigateApp().run()