Skip to content

Commit

Permalink
Add Kivy message composer screen UI
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhar-cis committed Oct 13, 2022
1 parent 3f56105 commit f6c7e50
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 22 deletions.
28 changes: 27 additions & 1 deletion src/bitmessagekivy/baseclass/common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pylint: disable=no-name-in-module, attribute-defined-outside-init, import-error
# pylint: disable=no-name-in-module, attribute-defined-outside-init, import-error, unused-argument
"""
All Common widgets of kivy are managed here.
"""
Expand All @@ -24,6 +24,8 @@
from kivymd.toast import kivytoast
from kivymd.uix.card import MDCardSwipe
from kivymd.uix.chip import MDChip
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton

from pybitmessage.bitmessagekivy.get_platform import platform
from pybitmessage.bmconfigparser import config
Expand Down Expand Up @@ -208,3 +210,27 @@ def msg_content_length(body, subject, max_length=50):
else:
subject = ((subject + ',' + body)[0:50] + continue_str).replace('\t', '').replace(' ', '')
return subject


def composer_common_dialog(alert_msg):
"""Common alert popup for message composer"""
is_android_width = .8
other_platform_width = .55
dialog_height = .25
width = is_android_width if platform == 'android' else other_platform_width

dialog_box = MDDialog(
text=alert_msg,
size_hint=(width, dialog_height),
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)
188 changes: 188 additions & 0 deletions src/bitmessagekivy/baseclass/msg_composer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# pylint: disable=unused-argument, consider-using-f-string, too-many-ancestors
# pylint: disable=no-member, no-name-in-module, too-few-public-methods, no-name-in-module
"""
Message composer screen UI
"""

import logging

from kivy.app import App
from kivy.properties import (
BooleanProperty,
ListProperty,
NumericProperty,
ObjectProperty,
)
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.boxlayout import BoxLayout
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 kivymd.uix.textfield import MDTextField

from pybitmessage import state
from pybitmessage.bitmessagekivy.get_platform import platform
from pybitmessage.bitmessagekivy.baseclass.common import (
toast, kivy_state_variables, composer_common_dialog
)

logger = logging.getLogger('default')


class Create(Screen):
"""Creates Screen class for kivy Ui"""

def __init__(self, **kwargs):
"""Getting Labels and address from addressbook"""
super(Create, self).__init__(**kwargs)
self.kivy_running_app = App.get_running_app()
self.kivy_state = kivy_state_variables()
self.dropdown_widget = DropDownWidget()
self.dropdown_widget.ids.txt_input.starting_no = 2
self.add_widget(self.dropdown_widget)
self.children[0].ids.id_scroll.bind(scroll_y=self.check_scroll_y)

def check_scroll_y(self, instance, somethingelse): # pylint: disable=unused-argument
"""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 __init__(self, **kwargs):
super(DropDownWidget, self).__init__(**kwargs)
self.kivy_running_app = App.get_running_app()
self.kivy_state = kivy_state_variables()

@staticmethod
def callback_for_msgsend(dt=0): # pylint: disable=unused-argument
"""Callback method for messagesend"""
state.kivyapp.root.ids.id_create.children[0].active = False
state.in_sent_method = True
state.kivyapp.back_press()
toast("sent")

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):
"""Checks the camera availability in device"""
self.parent.parent.parent.ids.id_scanscreen.check_camera()
is_available = self.parent.parent.parent.ids.id_scanscreen.camera_available
return is_available

@staticmethod
def camera_alert():
"""Show camera availability alert message"""
feature_unavailable = 'Currently this feature is not available!'
cam_not_available = 'Camera is not available!'
alert_text = feature_unavailable if platform == 'android' else cam_not_available
composer_common_dialog(alert_text)


class MyTextInput(MDTextField):
"""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): # pylint: disable=unused-argument
"""Find all the occurrence of the word"""
self.parent.parent.parent.parent.parent.ids.rv.data = []
max_recipient_len = 10
box_height = 250
box_max_height = 400

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) <= max_recipient_len:
self.parent.height = (box_height + (len(matches) * 20))
else:
self.parent.height = box_max_height

def keyboard_on_key_down(self, window, keycode, text, modifiers):
"""Keyboard on key Down"""
if self.suggestion_text and keycode[1] == 'tab' and modifiers is None:
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:
logger.debug("selection changed to %s", rv.data[index])
rv.parent.txt_input.text = rv.parent.txt_input.text.replace(
rv.parent.txt_input.text, rv.data[index]["text"]
)
24 changes: 3 additions & 21 deletions src/bitmessagekivy/kv/msg_composer.kv
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
font_size: '15sp'
multiline: False
required: True
# height: self.parent.height/2
height: 100
current_hint_text_color: 0,0,0,0.5
helper_text_mode: "on_error"
Expand All @@ -38,11 +37,8 @@
IdentitySpinner:
id: btn
background_color: app.theme_cls.primary_dark
values: app.variable_1
on_text: root.auto_fill_fromaddr() if self.text != 'Select' else ''
values: app.identity_list
option_cls: Factory.get("ComposerSpinnerOption")
#background_color: color_button if self.state == 'normal' else color_button_pressed
#background_down: 'atlas://data/images/defaulttheme/spinner'
background_normal: ''
background_color: app.theme_cls.primary_color
color: color_font
Expand All @@ -62,7 +58,6 @@
size_hint_y: None
font_size: '15sp'
color: color_font
# height: self.parent.height/2
current_hint_text_color: 0,0,0,0.5
height: 100
hint_text: app.tr._('Type or Scan QR code for recipients address')
Expand All @@ -79,7 +74,7 @@
if root.is_camara_attached(): app.set_screen('scanscreen')
else: root.camera_alert()
on_press:
app.root.ids.is_scanscreen.get_screen('composer')
app.root.ids.id_scanscreen.get_screen('composer')

MyMDTextField:
id: subject
Expand All @@ -98,17 +93,6 @@
Color:
rgba: (0,0,0,1)

# MyMDTextField:
# id: body
# multiline: True
# hint_text: 'body'
# size_hint_y: None
# font_size: '15sp'
# required: True
# helper_text_mode: "on_error"
# canvas.before:
# Color:
# rgba: (0,0,0,1)
ScrollView:
id: scrlv
MDTextField:
Expand Down Expand Up @@ -171,8 +155,6 @@

<ComposerSpinnerOption@SpinnerOption>:
font_size: '13.5sp'
#background_color: color_button if self.state == 'down' else color_button_pressed
#background_down: 'atlas://data/images/defaulttheme/button'
background_normal: 'atlas://data/images/defaulttheme/textinput_active'
background_color: app.theme_cls.primary_color
color: color_font
color: color_font
3 changes: 3 additions & 0 deletions src/bitmessagekivy/main.kv
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ MDNavigationLayout:
id:id_scanscreen
Payment:
id:id_payment
Create:
id:id_create

MDNavigationDrawer:
id: nav_drawer

Expand Down
5 changes: 5 additions & 0 deletions src/bitmessagekivy/screens_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@
"kv_string": "payment",
"name_screen": "payment",
"Import": "from pybitmessage.bitmessagekivy.baseclass.payment import Payment"
},
"Create": {
"kv_string": "msg_composer",
"name_screen": "create",
"Import": "from pybitmessage.bitmessagekivy.baseclass.msg_composer import Create"
}
}

0 comments on commit f6c7e50

Please sign in to comment.