diff --git a/komrade/app/main.py b/komrade/app/main.py index 342c7fe..01e0976 100644 --- a/komrade/app/main.py +++ b/komrade/app/main.py @@ -22,7 +22,7 @@ os.environ['KIVY_EVENTLOOP'] = 'asyncio' # loop.set_debug(True) # prefer experimental kivy if possible -sys.path.insert(0,os.path.join(PATH_KOMRADE_LIB,'KivyMD')) +# sys.path.insert(0,os.path.join(PATH_KOMRADE_LIB,'KivyMD')) import kivymd # print(kivymd.__file__) # exit() @@ -103,14 +103,15 @@ class MyLayout(MDBoxLayout): +from komrade.app.screens.dialog import MDDialog2 -class ProgressPopup(MDDialog): pass +class ProgressPopup(MDDialog2): pass -class MessagePopup(MDDialog): +class MessagePopup(MDDialog2): pass # def __init__(self,*x,**y): # super().__init__(*x,**y) @@ -124,9 +125,13 @@ class MessagePopup(MDDialog): pass -class MessagePopupCard(MDDialog): +class MessagePopupCard(MDDialog2): def __init__(self,*x,**y): + # y['color_bg']=rgb(*COLOR_CARD) + y['type']='custom' + y['overlay_color']=(0,0,0,0) super().__init__(*x,**y) + # self.color_bg=rgb(*COLOR_CARD) self.ok_to_continue=False #def on_dismiss(self): @@ -139,7 +144,110 @@ class MessagePopupCard(MDDialog): # logger.info(str(self.msg_dialog)) -class BooleanInputPopupCard(MDDialog): + + +class TextInputPopupCard(MDDialog2): + def say(self,x): + self.ok_to_continue=True + self.response=self.field.text + return self.response + + + def __init__(self,msg,password=False,input_name='',komrade_name='',*x,**y): + self.ok_to_continue=False + self.response=None + title=msg + from komrade.app.screens.login.login import UsernameField,PasswordField,UsernameLayout,UsernameLabel + + self.layout=MDBoxLayout() + self.layout.orientation='vertical' + self.layout.cols=1 + self.layout.size_hint=('333sp','222sp') + # self.layout.md_bg_color=(1,1,0,1) + self.layout.adaptive_height=True + self.layout.height=self.layout.minimum_height + self.layout.spacing='0sp' + self.layout.padding='0sp' + + # self.layout.size=('333sp','333sp') + + + + self.field_layout=UsernameLayout() + self.field = PasswordField() if password else UsernameField() + self.field.line_color_focus=rgb(*COLOR_TEXT) + self.field.line_color_normal=rgb(*COLOR_TEXT,a=0.25) + self.field.font_name=FONT_PATH + self.field_label = UsernameLabel(text='password:' if password else input_name) + self.field_label.font_name=FONT_PATH + if title: + self.title_label = UsernameLabel(text=title) + self.title_label.halign='center' + self.title_label.pos_hint={'center_x':0.5} + self.title_label.font_name=FONT_PATH + #self.field_layout.add_widget(self.title_label) + self.layout.add_widget(self.title_label) + + + self.field_layout.add_widget(self.field_label) + self.field_layout.add_widget(self.field) + self.layout.add_widget(self.field_layout) + # do dialog's intro + super().__init__( + type='custom', + text=msg, + content_cls=self.layout, + buttons=[ + MDFlatButton( + text="cancel", + text_color=rgb(*COLOR_TEXT), + md_bg_color = (0,0,0,1), + theme_text_color='Custom', + on_release=self.dismiss, + font_name=FONT_PATH + ), + MDFlatButton( + text="enter", + text_color=rgb(*COLOR_TEXT), + md_bg_color = (0,0,0,1), + theme_text_color='Custom', + on_release=self.say, + font_name=FONT_PATH + ), + ], + color_bg = rgb(*COLOR_CARD) + ) + self.ids.text.text_color=rgb(*COLOR_TEXT) + self.ids.text.font_name=FONT_PATH + self.size=('333sp','111sp') + self.adaptive_height=True + + # wait and show + async def open(self,maxwait=666,pulse=0.1): + super().open() + await asyncio.sleep(pulse) + waited=0 + while not self.ok_to_continue: + await asyncio.sleep(pulse) + waited+=pulse + if waited>maxwait: break + # logger.info(f'waiting for {waited} seconds... {self.ok_to_continue} {self.response}') + return self.response + + + + + + + + + + + + + + +class BooleanInputPopupCard(MDDialog2): def say_yes(self,x): # logger.info('say_yes got:',str(x)) self.ok_to_continue=True @@ -180,11 +288,8 @@ class BooleanInputPopupCard(MDDialog): color_bg = rgb(*COLOR_CARD) ) - self.md_bg_color='1,1,0,1' - #self.ids.spacer_top_box.md_bg_color=(1,1,0,1) - #self.ids.spacer_bottom_box.md_bg_color=(1,1,0,1) - #self.ids.text.text_color=rgb(*COLOR_TEXT) - #self.ids.text.font_name=FONT_PATH + self.ids.text.text_color=rgb(*COLOR_TEXT) + self.ids.text.font_name=FONT_PATH # wait and show async def open(self,maxwait=666,pulse=0.1): @@ -198,19 +303,6 @@ class BooleanInputPopupCard(MDDialog): # logger.info(f'waiting for {waited} seconds... {self.ok_to_continue} {self.response}') return self.response -# class MessageInputPopupCard(MDDialog): -# def __init__(self,*x,**y): -# super().__init__(*x,**y) -# self.ok_to_continue=False - - # def on_touch_down(self,touch): - # self.ok_to_continue=True - # logger.info('oof!') - # if hasattr(self,'msg_dialog'): - # logger.info(str(self.msg_dialog)) - - - class MyBoxLayout(MDBoxLayout): pass class MyLabel(MDLabel): pass @@ -475,60 +567,29 @@ class MainApp(MDApp, Logger): self.dialog.open() #stop - async def get_input(self,msg,komrade_name='Telephone',get_pass=False,**y): + async def get_input(self,msg,komrade_name='Telephone',get_pass=False,yesno=False,**y): from komrade.app.screens.feed.feed import PostCardInputPopup if hasattr(self,'msg_dialog') and self.msg_dialog:# and hasattr(self.msg_dialog,'card') and self.msg_dialog.card: self.msg_dialog0=self.msg_dialog + self.msg_dialog0.dismiss() + self.msg_dialog0=None - self.msg_dialog = BooleanInputPopupCard(msg) - - # self.msg_dialog.card = postcard = PostCardInputPopup({ - # 'author':komrade_name, - # 'author_prefix':'@', - # 'to_name':'me', - # 'content':msg, - # 'timestamp':time.time(), - # 'author_label_font_size':'18sp', - # **y - # }, - # msg_dialog=self.msg_dialog) - # postcard.font_size='16sp' - # postcard.size_hint=(None,None) - # postcard.size=('600sp','600sp') - # postcard.ok_to_continue=False - - # if get_pass: - # from komrade.app.screens.login.login import PasswordField - # self.msg_dialog.field = field = PasswordField() - # field.line_color_focus=rgb(*COLOR_TEXT) - # field.line_color_normal=rgb(*COLOR_TEXT,a=0.25) - # field.font_name='assets/font.otf' - # postcard.add_widget(field) - - # self.msg_dialog.add_widget(postcard) + if yesno: + self.msg_dialog = BooleanInputPopupCard(msg,komrade_name=komrade_name,**y) + else: + self.msg_dialog = TextInputPopupCard(msg,password=get_pass,komrade_name=komrade_name,**y) response = await self.msg_dialog.open() logger.info(f'get_input got user response {response}') + return response - - if hasattr(self,'msg_dialog0'): - self.msg_dialog0.remove_widget(self.msg_dialog0.card) - self.root.remove_widget(self.msg_dialog0) - - await asyncio.sleep(0.1) - while not self.msg_dialog.ok_to_continue: - await asyncio.sleep(0.1) - # logger.info(str(postcard), postcard.ok_to_continue,'??') - # self.msg_dialog.dismiss() - # self.msg_dialog.remove_widget(postcard) - # self.msg_dialog.card = postcard = self.msg_dialog = None - await asyncio.sleep(0.1) - return {'success':True, 'status':'Delivered popup message'} - + async def stat(self,msg,komrade_name='Telephone',pause=False,get_pass=False,**y): from komrade.app.screens.feed.feed import PostCard,PostCardPopup if hasattr(self,'msg_dialog') and self.msg_dialog:# and hasattr(self.msg_dialog,'card') and self.msg_dialog.card: self.msg_dialog0=self.msg_dialog + self.msg_dialog0.dismiss() + self.msg_dialog = MessagePopupCard() # self.msg_dialog.ids.msg_label.text=msg @@ -550,10 +611,9 @@ class MainApp(MDApp, Logger): self.msg_dialog.add_widget(postcard) - self.msg_dialog.open() + self.msg_dialog.open(animation=False) if hasattr(self,'msg_dialog0'): - self.msg_dialog0.remove_widget(self.msg_dialog0.card) self.root.remove_widget(self.msg_dialog0) await asyncio.sleep(0.1) diff --git a/komrade/app/screens/dialog.py b/komrade/app/screens/dialog.py new file mode 100644 index 0000000..c938ee1 --- /dev/null +++ b/komrade/app/screens/dialog.py @@ -0,0 +1,598 @@ +""" +Components/Dialog +================= + +.. seealso:: + + `Material Design spec, Dialogs `_ + + +.. rubric:: Dialogs inform users about a task and can contain critical + information, require decisions, or involve multiple tasks. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialogs.png + :align: center + +Usage +----- + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + from kivymd.uix.button import MDFlatButton + from kivymd.uix.dialog import MDDialog2 + + KV = ''' + FloatLayout: + + MDFlatButton: + text: "ALERT DIALOG" + pos_hint: {'center_x': .5, 'center_y': .5} + on_release: app.show_alert_dialog() + ''' + + + class Example(MDApp): + dialog = None + + def build(self): + return Builder.load_string(KV) + + def show_alert_dialog(self): + if not self.dialog: + self.dialog = MDDialog2( + text="Discard draft?", + buttons=[ + MDFlatButton( + text="CANCEL", text_color=self.theme_cls.primary_color + ), + MDFlatButton( + text="DISCARD", text_color=self.theme_cls.primary_color + ), + ], + ) + self.dialog.open() + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/alert-dialog.png + :align: center +""" + +__all__ = ("MDDialog2",) + +from kivy.clock import Clock +from kivy.core.window import Window +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ( + ListProperty, + NumericProperty, + ObjectProperty, + OptionProperty, + StringProperty, +) +from kivy.uix.modalview import ModalView + +from kivymd.material_resources import DEVICE_TYPE +from kivymd.theming import ThemableBehavior +from kivymd.uix.button import BaseButton +from kivymd.uix.card import MDSeparator +from kivymd.uix.list import BaseListItem + +Builder.load_string( + """ +#:import images_path kivymd.images_path + + + + background: '{}/transparent.png'.format(images_path) + canvas.before: + PushMatrix + RoundedRectangle: + pos: self.pos + size: self.size + radius: [5] + Scale: + origin: self.center + x: root._scale_x + y: root._scale_y + canvas.after: + PopMatrix + + + + MDCard: + id: container + orientation: "vertical" + size_hint_y: None + height: self.minimum_height + elevation: 4 + md_bg_color: 0, 0, 0, 0 + padding: "24dp", "24dp", "8dp", "8dp" + + canvas: + Color: + rgba: root.color_bg #root.theme_cls.bg_dark + RoundedRectangle: + pos: self.pos + size: self.size + radius: root.radius + + MDLabel: + id: title + text: root.title + font_style: "H6" + bold: True + markup: True + size_hint_y: None + height: self.texture_size[1] + valign: "top" + + BoxLayout: + id: spacer_top_box + size_hint_y: None + height: root._spacer_top + + MDLabel: + id: text + text: root.text + font_style: "Body1" + theme_text_color: "Custom" + text_color: root.theme_cls.disabled_hint_text_color + size_hint_y: None + height: self.texture_size[1] + markup: True + + ScrollView: + id: scroll + size_hint_y: None + height: root._scroll_height + + MDGridLayout: + id: box_items + adaptive_height: True + cols: 1 + + BoxLayout: + id: spacer_bottom_box + size_hint_y: None + height: self.minimum_height + + AnchorLayout: + id: root_button_box + size_hint_y: None + height: "52dp" + anchor_x: "right" + + MDBoxLayout: + id: button_box + adaptive_size: True + spacing: "8dp" +""" +) + + +class BaseDialog(ThemableBehavior, ModalView): + _scale_x = NumericProperty(1) + _scale_y = NumericProperty(1) + + +class MDDialog2(BaseDialog): + title = StringProperty() + """ + Title dialog. + + .. code-block:: python + + self.dialog = MDDialog2( + title="Reset settings?", + buttons=[ + MDFlatButton( + text="CANCEL", text_color=self.theme_cls.primary_color + ), + MDFlatButton( + text="ACCEPT", text_color=self.theme_cls.primary_color + ), + ], + ) + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-title.png + :align: center + + :attr:`title` is an :class:`~kivy.properties.StringProperty` + and defaults to `''`. + """ + + text = StringProperty() + """ + Text dialog. + + .. code-block:: python + + self.dialog = MDDialog2( + title="Reset settings?", + text="This will reset your device to its default factory settings.", + buttons=[ + MDFlatButton( + text="CANCEL", text_color=self.theme_cls.primary_color + ), + MDFlatButton( + text="ACCEPT", text_color=self.theme_cls.primary_color + ), + ], + ) + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-text.png + :align: center + + :attr:`text` is an :class:`~kivy.properties.StringProperty` + and defaults to `''`. + """ + + radius = ListProperty([7, 7, 7, 7]) + + color_bg=ListProperty([0,0,0,1]) + + """ + Dialog corners rounding value. + + .. code-block:: python + + self.dialog = MDDialog2( + text="Oops! Something seems to have gone wrong!", + radius=[20, 7, 20, 7], + ) + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-radius.png + :align: center + + :attr:`radius` is an :class:`~kivy.properties.ListProperty` + and defaults to `[7, 7, 7, 7]`. + """ + + buttons = ListProperty() + """ + List of button objects for dialog. + Objects must be inherited from :class:`~kivymd.uix.button.BaseButton` class. + + .. code-block:: python + + self.dialog = MDDialog2( + text="Discard draft?", + buttons=[ + MDFlatButton(text="CANCEL"), MDRaisedButton(text="DISCARD"), + ], + ) + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-buttons.png + :align: center + + :attr:`buttons` is an :class:`~kivy.properties.ListProperty` + and defaults to `[]`. + """ + + items = ListProperty() + """ + List of items objects for dialog. + Objects must be inherited from :class:`~kivymd.uix.list.BaseListItem` class. + + With type 'simple' + ----------------- + + .. code-block:: python + + from kivy.lang import Builder + from kivy.properties import StringProperty + + from kivymd.app import MDApp + from kivymd.uix.dialog import MDDialog2 + from kivymd.uix.list import OneLineAvatarListItem + + KV = ''' + + + ImageLeftWidget: + source: root.source + + + FloatLayout: + + MDFlatButton: + text: "ALERT DIALOG" + pos_hint: {'center_x': .5, 'center_y': .5} + on_release: app.show_simple_dialog() + ''' + + + class Item(OneLineAvatarListItem): + divider = None + source = StringProperty() + + + class Example(MDApp): + dialog = None + + def build(self): + return Builder.load_string(KV) + + def show_simple_dialog(self): + if not self.dialog: + self.dialog = MDDialog2( + title="Set backup account", + type="simple", + items=[ + Item(text="user01@gmail.com", source="user-1.png"), + Item(text="user02@gmail.com", source="user-2.png"), + Item(text="Add account", source="add-icon.png"), + ], + ) + self.dialog.open() + + + Example().run() + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-items.png + :align: center + + With type 'confirmation' + ----------------------- + + .. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + from kivymd.uix.button import MDFlatButton + from kivymd.uix.dialog import MDDialog2 + from kivymd.uix.list import OneLineAvatarIconListItem + + KV = ''' + + on_release: root.set_icon(check) + + CheckboxLeftWidget: + id: check + group: "check" + + + FloatLayout: + + MDFlatButton: + text: "ALERT DIALOG" + pos_hint: {'center_x': .5, 'center_y': .5} + on_release: app.show_confirmation_dialog() + ''' + + + class ItemConfirm(OneLineAvatarIconListItem): + divider = None + + def set_icon(self, instance_check): + instance_check.active = True + check_list = instance_check.get_widgets(instance_check.group) + for check in check_list: + if check != instance_check: + check.active = False + + + class Example(MDApp): + dialog = None + + def build(self): + return Builder.load_string(KV) + + def show_confirmation_dialog(self): + if not self.dialog: + self.dialog = MDDialog2( + title="Phone ringtone", + type="confirmation", + items=[ + ItemConfirm(text="Callisto"), + ItemConfirm(text="Luna"), + ItemConfirm(text="Night"), + ItemConfirm(text="Solo"), + ItemConfirm(text="Phobos"), + ItemConfirm(text="Diamond"), + ItemConfirm(text="Sirena"), + ItemConfirm(text="Red music"), + ItemConfirm(text="Allergio"), + ItemConfirm(text="Magic"), + ItemConfirm(text="Tic-tac"), + ], + buttons=[ + MDFlatButton( + text="CANCEL", text_color=self.theme_cls.primary_color + ), + MDFlatButton( + text="OK", text_color=self.theme_cls.primary_color + ), + ], + ) + self.dialog.open() + + + Example().run() + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-confirmation.png + :align: center + + :attr:`items` is an :class:`~kivy.properties.ListProperty` + and defaults to `[]`. + """ + + type = OptionProperty( + "alert", options=["alert", "simple", "confirmation", "custom"] + ) + """ + Dialog type. + Available option are `'alert'`, `'simple'`, `'confirmation'`, `'custom'`. + + :attr:`type` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'alert'`. + """ + + content_cls = ObjectProperty() + """ + Custom content class. + + .. code-block:: + + from kivy.lang import Builder + from kivy.uix.boxlayout import BoxLayout + + from kivymd.app import MDApp + from kivymd.uix.button import MDFlatButton + from kivymd.uix.dialog import MDDialog2 + + KV = ''' + + orientation: "vertical" + spacing: "12dp" + size_hint_y: None + height: "120dp" + + MDTextField: + hint_text: "City" + + MDTextField: + hint_text: "Street" + + + FloatLayout: + + MDFlatButton: + text: "ALERT DIALOG" + pos_hint: {'center_x': .5, 'center_y': .5} + on_release: app.show_confirmation_dialog() + ''' + + + class Content(BoxLayout): + pass + + + class Example(MDApp): + dialog = None + + def build(self): + return Builder.load_string(KV) + + def show_confirmation_dialog(self): + if not self.dialog: + self.dialog = MDDialog2( + title="Address:", + type="custom", + content_cls=Content(), + buttons=[ + MDFlatButton( + text="CANCEL", text_color=self.theme_cls.primary_color + ), + MDFlatButton( + text="OK", text_color=self.theme_cls.primary_color + ), + ], + ) + self.dialog.open() + + + Example().run() + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-custom.png + :align: center + + :attr:`content_cls` is an :class:`~kivy.properties.ObjectProperty` + and defaults to `'None'`. + """ + + _scroll_height = NumericProperty("28dp") + _spacer_top = NumericProperty("24dp") + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.color_bg = kwargs.get('color_bg',self.theme_cls.bg_dark) + if 'color_bg' in kwargs: + del kwargs['color_bg'] + + if self.size_hint == [1, 1] and DEVICE_TYPE == "mobile": + self.size_hint = (None, None) + self.width = dp(280) + elif self.size_hint == [1, 1] and DEVICE_TYPE == "desktop": + self.size_hint = (None, None) + self.width = dp(560) + + if not self.title: + self._spacer_top = 0 + + if not self.buttons: + self.ids.root_button_box.height = 0 + else: + self.create_buttons() + + update_height = False + if self.type in ("simple", "confirmation"): + if self.type == "confirmation": + self.ids.spacer_top_box.add_widget(MDSeparator()) + self.ids.spacer_bottom_box.add_widget(MDSeparator()) + self.create_items() + if self.type == "custom": + if self.content_cls: + self.ids.container.remove_widget(self.ids.scroll) + self.ids.container.remove_widget(self.ids.text) + self.ids.spacer_top_box.add_widget(self.content_cls) + self.ids.spacer_top_box.padding = (0, "24dp", "16dp", 0) + update_height = True + if self.type == "alert": + self.ids.scroll.bar_width = 0 + + if update_height: + Clock.schedule_once(self.update_height) + + def update_height(self, *_): + self._spacer_top = self.content_cls.height + dp(24) + + def on_open(self): + # TODO: Add scrolling text. + self.height = self.ids.container.height + + def set_normal_height(self): + self.size_hint_y = 0.8 + + def get_normal_height(self): + return ( + (Window.height * 80 / 100) + - self._spacer_top + - dp(52) + - self.ids.container.padding[1] + - self.ids.container.padding[-1] + - 100 + ) + + def edit_padding_for_item(self, instance_item): + instance_item.ids._left_container.x = 0 + instance_item._txt_left_pad = "56dp" + + def create_items(self): + self.ids.container.remove_widget(self.ids.text) + height = 0 + + for item in self.items: + if issubclass(item.__class__, BaseListItem): + height += item.height # calculate height contents + self.edit_padding_for_item(item) + self.ids.box_items.add_widget(item) + + if height > Window.height: + self.set_normal_height() + self.ids.scroll.height = self.get_normal_height() + else: + self.ids.scroll.height = height + + def create_buttons(self): + for button in self.buttons: + if issubclass(button.__class__, BaseButton): + self.ids.button_box.add_widget(button) diff --git a/komrade/app/screens/login/login.kv b/komrade/app/screens/login/login.kv index 080292e..098be30 100644 --- a/komrade/app/screens/login/login.kv +++ b/komrade/app/screens/login/login.kv @@ -17,7 +17,7 @@ orientation:'vertical' cols:1 size_hint:None,None - width: '300sp' + width: '333sp' pos_hint: {'center_x':0.5,'center_y':0.5} md_bg_color: rgb(*COLOR_CARD) radius:[20,] @@ -59,7 +59,7 @@ : theme_text_color: 'Custom' text_color: rgb(*COLOR_TEXT) - width:'100sp' + width:'150sp' # adaptive_width: True size_hint:None,None # md_bg_color:rgb(*COLOR_TEXT) diff --git a/komrade/app/screens/login/login.py b/komrade/app/screens/login/login.py index c3299de..bcd0cb0 100644 --- a/komrade/app/screens/login/login.py +++ b/komrade/app/screens/login/login.py @@ -23,11 +23,11 @@ class LoginButton(MDRectangleFlatButton): pass class RegisterButton(MDRectangleFlatButton,Logger): def enter(self): un=self.parent.parent.parent.username_field.text - pw=self.parent.parent.parent.password_field.text + # pw=self.parent.parent.parent.password_field.text login_screen = self.parent.parent.parent time.sleep(0.1) - asyncio.create_task(login_screen.boot(un,pw)) + asyncio.create_task(login_screen.boot(un)) # logger.info('types',type(self.parent),type(self.parent.parent.parent)) @@ -62,7 +62,7 @@ class LoginScreen(BaseScreen): self.label_title.markup=True self.label_title.color=rgb(*COLOR_TEXT) self.label_title.text='Welcome,' - # self.label_title.font_size*=1.5 + self.label_title.font_size='28sp' self.layout.add_widget(get_separator('20sp')) self.layout.add_widget(self.label_title) self.layout.add_widget(get_separator('30sp')) @@ -70,7 +70,7 @@ class LoginScreen(BaseScreen): self.layout_username = UsernameLayout() - self.label_username = UsernameLabel(text="Komrade") + self.label_username = UsernameLabel(text="Komrade @") self.username_field = UsernameField() self.username_field.line_color_focus=rgb(*COLOR_TEXT) @@ -84,20 +84,20 @@ class LoginScreen(BaseScreen): #log(self.username_field) # self.username_field.text='hello????' - self.layout_password = UsernameLayout() - self.label_password = UsernameLabel(text='password:') + # self.layout_password = UsernameLayout() + # self.label_password = UsernameLabel(text='password:') - self.label_password.font_name='assets/font.otf' + # self.label_password.font_name='assets/font.otf' self.label_username.font_name='assets/font.otf' - self.password_field = PasswordField() - self.password_field.line_color_focus=rgb(*COLOR_TEXT) - self.password_field.line_color_normal=rgb(*COLOR_TEXT,a=0.25) - self.password_field.font_name='assets/font.otf' + # self.password_field = PasswordField() + # self.password_field.line_color_focus=rgb(*COLOR_TEXT) + # self.password_field.line_color_normal=rgb(*COLOR_TEXT,a=0.25) + # self.password_field.font_name='assets/font.otf' - self.layout_password.add_widget(self.label_password) - self.layout_password.add_widget(self.password_field) - self.layout.add_widget(self.layout_password) + # self.layout_password.add_widget(self.label_password) + # self.layout_password.add_widget(self.password_field) + # self.layout.add_widget(self.layout_password) self.layout_buttons = LoginButtonLayout() self.layout.add_widget(get_separator('20sp')) @@ -117,16 +117,18 @@ class LoginScreen(BaseScreen): self.layout.add_widget(self.login_status) - self.label_title.font_size='18sp' - self.label_password.font_size='18sp' - self.label_username.font_size='20sp' + self.label_title.font_size='24sp' + # self.label_password.font_size='18sp' + self.label_username.font_size='22sp' self.login_button.font_size='12sp' self.register_button.font_size='9sp' self.register_button.text='enter' - self.username_field.font_size='20sp' + self.username_field.font_size='24sp' self.label_username.padding_x=(10,20) self.username_field.padding_x=(20,10) - self.username_field.padding_y=(25,0) + # self.username_field.padding_y=(25,0) + self.username_field.pos_hint={'center_y':0.5} + self.label_username.halign='right' @@ -164,22 +166,23 @@ class LoginScreen(BaseScreen): async def boot(self,un,pw=None): # await self.stat('hello',img_src='/home/ryan/komrade/data/contacts/marxxx.png',komrade_name='Keymaker') - await self.app.get_input('hello?',get_pass=True) - return + # await self.app.get_input('hello?',get_pass=True,title='gimme your passwrdd') + # await self.app.get_input('hello?',get_pass=False,title='gimme your fav color bitch') + # return # return name=un from komrade.backend import Komrade - kommie = Komrade(un,getpass_func=lambda why: pw) + kommie = Komrade(un) self.log('KOMMIE!?!?',kommie) logger.info(f'booted kommie: {kommie}') if kommie.exists_locally_as_account(): - await self.app.stat('You have already created this account. Logging you back in...') - + pw=await self.app.get_input('Welcome back.') + kommie=Komrade(un,getpass_func=lambda why: pw) logger.info(f'is account') - self.login_status.text='You should be able to log into this account.' + # self.login_status.text='You should be able to log into this account.' if kommie.privkey: logger.info(f'passkey login succeeded') self.login_status.text=f'Welcome back, Komrade @{un}' @@ -201,7 +204,8 @@ class LoginScreen(BaseScreen): # self.login_status.text='Komrade not known on this device. Registering...' ### REGISTER - res = await self.register(kommie,logfunc=self.app.stat,passphrase=pw) + self.remove_widget(self.layout) + res = await self.register(un) if kommie.privkey: self.login_status.text='Registered' @@ -215,9 +219,12 @@ class LoginScreen(BaseScreen): return 1 - async def register(self,kommie,logfunc=None,passphrase=None): - if not logfunc: logfunc=self.app.stat - name=kommie.name + async def register(self,name): + async def logfunc(*x,**y): + if not 'komrade_name' in y: y['komrade_name']='Keymaker' + await self.app.stat(*x,**y) + + kommie = Komrade(name) # already have it? if kommie.exists_locally_as_account(): @@ -267,6 +274,10 @@ class LoginScreen(BaseScreen): ### PRIVATE KEY await logfunc(f"(2) Your PRIVATE encryption key, on the other hand, must be stored only on your device hardware. In fact it's so sensitive we'll even encrypt the encryption key itself.",pause=True,use_prefix=False) + passphrase = await self.app.get_input('Please enter a memorable password.', + get_pass=True + ) + passhash = hasher(passphrase) privkey_decr = KomradeSymmetricKeyWithPassphrase(passhash=passhash) print() diff --git a/komrade/backend/the_telephone.py b/komrade/backend/the_telephone.py index 0e3699a..0dc805d 100644 --- a/komrade/backend/the_telephone.py +++ b/komrade/backend/the_telephone.py @@ -67,7 +67,13 @@ class TheTelephone(Operator): URL = self.api_url + msg_b64_str_esc + '/' self.log("DIALING THE OPERATOR:",URL) - phonecall=await self.komrade_request_async(URL) + # phonecall=await self.komrade_request_async(URL) + import asyncio + loop = asyncio.get_event_loop() + texec = ThreadExecutor() + + # phonecall=self.komrade_request(URL) + phonecall = await texec(self.komrade_request, URL) if phonecall.status_code!=200: self.log('!! error in request',phonecall.status_code,phonecall.text) @@ -128,19 +134,19 @@ class TheTelephone(Operator): def tor_request_in_proxy(self,url): with self.get_tor_proxy_session() as s: - return s.get(url,timeout=60) + return s.get(url,timeout=600) async def tor_request_in_python_async(self,url): - import requests_async as requests + import requests_async tor = TorClient() with tor.get_guard() as guard: adapter = TorHttpAdapter(guard, 3, retries=RETRIES) - async with requests.Session() as s: + async with requests_async.Session() as s: s.headers.update({'User-Agent': 'Mozilla/5.0'}) s.mount('http://', adapter) s.mount('https://', adapter) - r = await s.get(url, timeout=60) + r = s.get(url, timeout=600) self.log('<-- r',r) return r @@ -154,7 +160,7 @@ class TheTelephone(Operator): s.headers.update({'User-Agent': 'Mozilla/5.0'}) s.mount('http://', adapter) s.mount('https://', adapter) - r = s.get(url, timeout=60) + r = s.get(url, timeout=600) return r def get_tor_proxy_session(self): diff --git a/komrade/utils.py b/komrade/utils.py index db73b15..2f6df9f 100644 --- a/komrade/utils.py +++ b/komrade/utils.py @@ -451,4 +451,38 @@ def multiline_input(msg=None): break txt="\n".join(contents) if contents else contents - return txt \ No newline at end of file + return txt + + + +class ThreadExecutor: + """In most cases, you can just use the 'execute' instance as a + function, i.e. y = await execute(f, a, b, k=c) => run f(a, b, k=c) in + the executor, assign result to y. The defaults can be changed, though, + with your own instantiation of Executor, i.e. execute = + Executor(nthreads=4)""" + def __init__(self, loop=None, nthreads=1): + import asyncio + from concurrent.futures import ThreadPoolExecutor + + if not loop: loop=asyncio.get_event_loop() + + self._ex = ThreadPoolExecutor(nthreads) + self._loop = loop + + def __call__(self, f, *args, **kw): + from functools import partial + return self._loop.run_in_executor(self._ex, partial(f, *args, **kw)) + +# execute = Executor() + +# ... + +# def cpu_bound_operation(t, alpha=30): +# sleep(t) +# return 20*alpha + +# async def main(): +# y = await execute(cpu_bound_operation, 5, alpha=-2) + +# loop.run_until_complete(main()) \ No newline at end of file