import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
from comrad import *
from screens.base import *
from kivymd.uix.boxlayout import *
from kivymd.uix.textfield import *
from kivymd.uix.button import *
from kivymd.uix.label import *
from kivymd.uix.card import *
from kivy.uix.label import *
from kivymd.uix.dialog import *
from main import *
from misc import *
from kivy.app import *

import logging
logger = logging.getLogger(__name__)

import sys

from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp, sp
from kivy.properties import (
    BooleanProperty,
    ListProperty,
    NumericProperty,
    ObjectProperty,
    OptionProperty,
    StringProperty,
)
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput

from kivymd.font_definitions import theme_font_styles
from kivymd.material_resources import DEVICE_TYPE
from kivymd.theming import ThemableBehavior
from kivymd.uix.label import MDIcon








class LoginBoxLayout(MDBoxLayout): pass
class LoginButtonLayout(MDBoxLayout): pass
# # class UsernameField(MDTextField): pass
#     def __init__(self,*x,**y):
#         super().__init__(*x,**y)
#         self.focus=True
#     def on_text_validate(self):
#         reg_button=self.parent.parent.parent.register_button
#         reg_button.enter()



class UsernameField(ThemableBehavior, TextInput):
    helper_text = StringProperty("This field is required")
    """
    Text for ``helper_text`` mode.
    :attr:`helper_text` is an :class:`~kivy.properties.StringProperty`
    and defaults to `'This field is required'`.
    """

    helper_text_mode = OptionProperty(
        "none", options=["none", "on_error", "persistent", "on_focus"]
    )
    """
    Helper text mode. Available options are: `'on_error'`, `'persistent'`,
    `'on_focus'`.
    :attr:`helper_text_mode` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'none'`.
    """

    max_text_length = NumericProperty(None)
    """
    Maximum allowed value of characters in a text field.
    :attr:`max_text_length` is an :class:`~kivy.properties.NumericProperty`
    and defaults to `None`.
    """

    required = BooleanProperty(False)
    """
    Required text. If True then the text field requires text.
    :attr:`required` is an :class:`~kivy.properties.BooleanProperty`
    and defaults to `False`.
    """

    color_mode = OptionProperty(
        "primary", options=["primary", "accent", "custom"]
    )
    """
    Color text mode. Available options are: `'primary'`, `'accent'`,
    `'custom'`.
    :attr:`color_mode` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'primary'`.
    """

    mode = OptionProperty("line", options=["rectangle", "fill"])
    """
    Text field mode. Available options are: `'line'`, `'rectangle'`, `'fill'`.
    :attr:`mode` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'line'`.
    """

    line_color_normal = ListProperty()
    """
    Line color normal in ``rgba`` format.
    :attr:`line_color_normal` is an :class:`~kivy.properties.ListProperty`
    and defaults to `[]`.
    """

    line_color_focus = ListProperty()
    """
    Line color focus in ``rgba`` format.
    :attr:`line_color_focus` is an :class:`~kivy.properties.ListProperty`
    and defaults to `[]`.
    """

    error_color = ListProperty()
    """
    Error color in ``rgba`` format for ``required = True``.
    :attr:`error_color` is an :class:`~kivy.properties.ListProperty`
    and defaults to `[]`.
    """

    fill_color = ListProperty((0, 0, 0, 0))
    """
    The background color of the fill in rgba format when the ``mode`` parameter
    is "fill".
    :attr:`fill_color` is an :class:`~kivy.properties.ListProperty`
    and defaults to `(0, 0, 0, 0)`.
    """

    active_line = BooleanProperty(True)
    """
    Show active line or not.
    :attr:`active_line` is an :class:`~kivy.properties.BooleanProperty`
    and defaults to `True`.
    """

    error = BooleanProperty(False)
    """
    If True, then the text field goes into ``error`` mode.
    :attr:`error` is an :class:`~kivy.properties.BooleanProperty`
    and defaults to `False`.
    """

    current_hint_text_color = ListProperty()
    """
    ``hint_text`` text color.
    :attr:`current_hint_text_color` is an :class:`~kivy.properties.ListProperty`
    and defaults to `[]`.
    """

    icon_right = StringProperty()
    """Right icon.
    :attr:`icon_right` is an :class:`~kivy.properties.StringProperty`
    and defaults to `''`.
    """

    icon_right_color = ListProperty((0, 0, 0, 1))
    """Color of right icon in ``rgba`` format.
    :attr:`icon_right_color` is an :class:`~kivy.properties.ListProperty`
    and defaults to `(0, 0, 0, 1)`.
    """

    _text_len_error = BooleanProperty(False)
    _hint_lbl_font_size = NumericProperty("16sp")
    _line_blank_space_right_point = NumericProperty(0)
    _line_blank_space_left_point = NumericProperty(0)
    _hint_y = NumericProperty("38dp")
    _line_width = NumericProperty(0)
    _current_line_color = ListProperty((0, 0, 0, 0))
    _current_error_color = ListProperty((0, 0, 0, 0))
    _current_hint_text_color = ListProperty((0, 0, 0, 0))
    _current_right_lbl_color = ListProperty((0, 0, 0, 0))

    _msg_lbl = None
    _right_msg_lbl = None
    _hint_lbl = None
    _lbl_icon_right = None

    def __init__(self, **kwargs):
        self.set_objects_labels()
        super().__init__(**kwargs)
        # Sets default colors.
        self.line_color_normal = self.theme_cls.divider_color
        self.line_color_focus = self.theme_cls.primary_color
        self.error_color = self.theme_cls.error_color
        self._current_hint_text_color = self.theme_cls.disabled_hint_text_color
        self._current_line_color = self.theme_cls.primary_color

        self.bind(
            helper_text=self._set_msg,
            hint_text=self._set_hint,
            _hint_lbl_font_size=self._hint_lbl.setter("font_size"),
            helper_text_mode=self._set_message_mode,
            max_text_length=self._set_max_text_length,
            text=self.on_text,
        )
        self.theme_cls.bind(
            primary_color=self._update_primary_color,
            theme_style=self._update_theme_style,
            accent_color=self._update_accent_color,
        )
        self.has_had_text = False
        self.focus=True

    def set_objects_labels(self):
        """Creates labels objects for the parameters
        `helper_text`,`hint_text`, etc."""

        # Label object for `helper_text` parameter.
        self._msg_lbl = TextfieldLabel(
            font_style="Caption",
            halign="left",
            valign="middle",
            text=self.helper_text,
            field=self,
        )
        # Label object for `max_text_length` parameter.
        self._right_msg_lbl = TextfieldLabel(
            font_style="Caption",
            halign="right",
            valign="middle",
            text="",
            field=self,
        )
        # Label object for `hint_text` parameter.
        self._hint_lbl = TextfieldLabel(
            font_style="Subtitle1", halign="left", valign="middle", field=self
        )
        # MDIcon object for the icon on the right.
        self._lbl_icon_right = MDIcon(theme_text_color="Custom")

    def on_icon_right(self, instance, value):
        self._lbl_icon_right.icon = value

    def on_icon_right_color(self, instance, value):
        self._lbl_icon_right.text_color = value

    def on_width(self, instance, width):
        """Called when the application window is resized."""

        if (
            any((self.focus, self.error, self._text_len_error))
            and instance is not None
        ):
            # Bottom line width when active focus.
            self._line_width = width
        self._msg_lbl.width = self.width
        self._right_msg_lbl.width = self.width

    def on_focus(self, *args):
        disabled_hint_text_color = self.theme_cls.disabled_hint_text_color
        Animation.cancel_all(
            self, "_line_width", "_hint_y", "_hint_lbl_font_size"
        )
        self._set_text_len_error()

        if self.focus:
            self._line_blank_space_right_point = (
                self._get_line_blank_space_right_point()
            )
            _fill_color = self.fill_color
            _fill_color[3] = self.fill_color[3] - 0.1
            if not self._get_has_error():
                Animation(
                    _line_blank_space_right_point=self._line_blank_space_right_point,
                    _line_blank_space_left_point=self._hint_lbl.x - dp(5),
                    _current_hint_text_color=self.line_color_focus,
                    fill_color=_fill_color,
                    duration=0.2,
                    t="out_quad",
                ).start(self)
            self.has_had_text = True
            Animation.cancel_all(
                self, "_line_width", "_hint_y", "_hint_lbl_font_size"
            )
            if not self.text:
                self._anim_lbl_font_size(dp(14), sp(12))
            Animation(_line_width=self.width, duration=0.2, t="out_quad").start(
                self
            )
            if self._get_has_error():
                self._anim_current_error_color(self.error_color)
                if self.helper_text_mode == "on_error" and (
                    self.error or self._text_len_error
                ):
                    self._anim_current_error_color(self.error_color)
                elif (
                    self.helper_text_mode == "on_error"
                    and not self.error
                    and not self._text_len_error
                ):
                    self._anim_current_error_color((0, 0, 0, 0))
                elif self.helper_text_mode in ("persistent", "on_focus"):
                    self._anim_current_error_color(disabled_hint_text_color)
            else:
                self._anim_current_right_lbl_color(disabled_hint_text_color)
                Animation(
                    duration=0.2, _current_hint_text_color=self.line_color_focus
                ).start(self)
                if self.helper_text_mode == "on_error":
                    self._anim_current_error_color((0, 0, 0, 0))
                if self.helper_text_mode in ("persistent", "on_focus"):
                    self._anim_current_error_color(disabled_hint_text_color)
        else:
            _fill_color = self.fill_color
            _fill_color[3] = self.fill_color[3] + 0.1
            Animation(fill_color=_fill_color, duration=0.2, t="out_quad").start(
                self
            )
            if not self.text:
                self._anim_lbl_font_size(dp(38), sp(16))
                Animation(
                    _line_blank_space_right_point=0,
                    _line_blank_space_left_point=0,
                    duration=0.2,
                    t="out_quad",
                ).start(self)
            if self._get_has_error():
                self._anim_get_has_error_color(self.error_color)
                if self.helper_text_mode == "on_error" and (
                    self.error or self._text_len_error
                ):
                    self._anim_current_error_color(self.error_color)
                elif (
                    self.helper_text_mode == "on_error"
                    and not self.error
                    and not self._text_len_error
                ):
                    self._anim_current_error_color((0, 0, 0, 0))
                elif self.helper_text_mode == "persistent":
                    self._anim_current_error_color(disabled_hint_text_color)
                elif self.helper_text_mode == "on_focus":
                    self._anim_current_error_color((0, 0, 0, 0))
            else:
                Animation(duration=0.2, color=(1, 1, 1, 1)).start(
                    self._hint_lbl
                )
                self._anim_get_has_error_color()
                if self.helper_text_mode == "on_error":
                    self._anim_current_error_color((0, 0, 0, 0))
                elif self.helper_text_mode == "persistent":
                    self._anim_current_error_color(disabled_hint_text_color)
                elif self.helper_text_mode == "on_focus":
                    self._anim_current_error_color((0, 0, 0, 0))
                Animation(_line_width=0, duration=0.2, t="out_quad").start(self)

    def on_text(self, instance, text):
        if len(text) > 0:
            self.has_had_text = True
        if self.max_text_length is not None:
            self._right_msg_lbl.text = f"{len(text)}/{self.max_text_length}"
        self._set_text_len_error()
        if self.error or self._text_len_error:
            if self.focus:
                self._anim_current_line_color(self.error_color)
                if self.helper_text_mode == "on_error" and (
                    self.error or self._text_len_error
                ):
                    self._anim_current_error_color(self.error_color)
                if self._text_len_error:
                    self._anim_current_right_lbl_color(self.error_color)
        else:
            if self.focus:
                self._anim_current_right_lbl_color(
                    self.theme_cls.disabled_hint_text_color
                )
                self._anim_current_line_color(self.line_color_focus)
                if self.helper_text_mode == "on_error":
                    self._anim_current_error_color((0, 0, 0, 0))
        if len(self.text) != 0 and not self.focus:
            self._hint_y = dp(14)
            self._hint_lbl_font_size = sp(12)

    def on_text_validate(self):
        self.has_had_text = True
        self._set_text_len_error()

        # custom
        reg_button=self.parent.parent.parent.register_button
        reg_button.enter()

    def on_color_mode(self, instance, mode):
        if mode == "primary":
            self._update_primary_color()
        elif mode == "accent":
            self._update_accent_color()
        elif mode == "custom":
            self._update_colors(self.line_color_focus)

    def on_line_color_focus(self, *args):
        if self.color_mode == "custom":
            self._update_colors(self.line_color_focus)

    def on__hint_text(self, instance, value):
        pass

    def _anim_get_has_error_color(self, color=None):
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_get_has_error.png
        if not color:
            line_color = self.line_color_focus
            hint_text_color = self.theme_cls.disabled_hint_text_color
            right_lbl_color = (0, 0, 0, 0)
        else:
            line_color = color
            hint_text_color = color
            right_lbl_color = color
        Animation(
            duration=0.2,
            _current_line_color=line_color,
            _current_hint_text_color=hint_text_color,
            _current_right_lbl_color=right_lbl_color,
        ).start(self)

    def _anim_current_line_color(self, color):
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_anim_current_line_color.gif
        Animation(
            duration=0.2,
            _current_hint_text_color=color,
            _current_line_color=color,
        ).start(self)

    def _anim_lbl_font_size(self, hint_y, font_size):
        Animation(
            _hint_y=hint_y,
            _hint_lbl_font_size=font_size,
            duration=0.2,
            t="out_quad",
        ).start(self)

    def _anim_current_right_lbl_color(self, color, duration=0.2):
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_anim_current_right_lbl_color.png
        Animation(duration=duration, _current_right_lbl_color=color).start(self)

    def _anim_current_error_color(self, color, duration=0.2):
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_anim_current_error_color_to_disabled_color.gif
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_anim_current_error_color_to_fade.gif
        Animation(duration=duration, _current_error_color=color).start(self)

    def _update_colors(self, color):
        self.line_color_focus = color
        if not self.error and not self._text_len_error:
            self._current_line_color = color
            if self.focus:
                self._current_line_color = color

    def _update_accent_color(self, *args):
        if self.color_mode == "accent":
            self._update_colors(self.theme_cls.accent_color)

    def _update_primary_color(self, *args):
        if self.color_mode == "primary":
            self._update_colors(self.theme_cls.primary_color)

    def _update_theme_style(self, *args):
        self.line_color_normal = self.theme_cls.divider_color
        if not any([self.error, self._text_len_error]):
            if not self.focus:
                self._current_hint_text_color = (
                    self.theme_cls.disabled_hint_text_color
                )
                self._current_right_lbl_color = (
                    self.theme_cls.disabled_hint_text_color
                )
                if self.helper_text_mode == "persistent":
                    self._current_error_color = (
                        self.theme_cls.disabled_hint_text_color
                    )

    def _get_has_error(self):
        if self.error or all(
            [
                self.max_text_length is not None
                and len(self.text) > self.max_text_length
            ]
        ):
            has_error = True
        else:
            if all((self.required, len(self.text) == 0, self.has_had_text)):
                has_error = True
            else:
                has_error = False
        return has_error

    def _get_line_blank_space_right_point(self):
        # https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/_line_blank_space_right_point.png
        return (
            self._hint_lbl.texture_size[0]
            - self._hint_lbl.texture_size[0] / 100 * dp(18)
            if DEVICE_TYPE == "desktop"
            else dp(10)
        )

    def _get_max_text_length(self):
        """Returns the maximum number of characters that can be entered in a
        text field."""

        return (
            sys.maxsize
            if self.max_text_length is None
            else self.max_text_length
        )

    def _set_text_len_error(self):
        if len(self.text) > self._get_max_text_length() or all(
            (self.required, len(self.text) == 0, self.has_had_text)
        ):
            self._text_len_error = True
        else:
            self._text_len_error = False

    def _set_hint(self, instance, text):
        self._hint_lbl.text = text

    def _set_msg(self, instance, text):
        self._msg_lbl.text = text
        self.helper_text = text

    def _set_message_mode(self, instance, text):
        self.helper_text_mode = text
        if self.helper_text_mode == "persistent":
            self._anim_current_error_color(
                self.theme_cls.disabled_hint_text_color, 0.1
            )

    def _set_max_text_length(self, instance, length):
        self.max_text_length = length
        self._right_msg_lbl.text = f"{len(self.text)}/{length}"

    def _refresh_hint_text(self):
        pass



    
class PasswordField(MDTextField): pass
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
        login_screen = self.parent.parent.parent

        time.sleep(0.1)
        asyncio.create_task(login_screen.boot(un))

        # logger.info('types',type(self.parent),type(self.parent.parent.parent))
        
        # app=App.get_running_app()
        # app.boot(un)
        # app.change_screen_from_uri(f'/inbox/{un}')
    
    pass
class LoginStatus(MDLabel): pass

class UsernameLayout(MDBoxLayout): pass
class UsernameLabel(MDLabel): pass
class WelcomeLabel(MDLabel): pass

class PasswordPopup(MDDialog): pass

class LoginScreen(BaseScreen): 
    #def on_pre_enter(self):
    #    global app
    #    if app.is_logged_in():
    #        app.root.change_screen('feed')
    def on_pre_enter(self):
        #log(self.ids)
        #log('hello?')
        super().on_pre_enter()
        self.dialog=None
        self.pass_added=False
        self.layout = LoginBoxLayout()
        self.label_title = WelcomeLabel()
        self.label_title.font_name='assets/font.otf'
        # self.label_title.font_size='20sp'
        self.label_title.bold=True
        self.label_title.markup=True
        self.label_title.color=rgb(*COLOR_TEXT)
        self.label_title.text='Welcome,'
        self.layout.add_widget(get_separator('20sp'))
        self.layout.add_widget(self.label_title)
        self.layout.add_widget(get_separator('30sp'))
        # self.layout.add_widget(MySeparator())
        

        self.layout_username = UsernameLayout()
        self.label_username = UsernameLabel(text="Comrad @")

        self.username_field = UsernameField()
        self.username_field.line_color_focus=rgb(*COLOR_TEXT)
        self.username_field.line_color_normal=rgb(*COLOR_TEXT)
        self.username_field.font_name='assets/font.otf'
        self.username_field.width='10dp'

        self.layout_username.add_widget(self.label_username)
        self.layout_username.add_widget(self.username_field)

        self.layout.add_widget(self.layout_username)
        #log(self.username_field)
        # self.username_field.text='hello????'

        # self.layout_password = UsernameLayout()
        # self.label_password = UsernameLabel(text='password:')

        # 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.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'))
        self.layout.add_widget(self.layout_buttons)

        self.login_button = LoginButton()
        self.login_button.font_name='assets/font.otf'
        # self.layout_buttons.add_widget(self.login_button)

        self.register_button = RegisterButton()
        self.register_button.font_name='assets/font.otf'
        # self.register_button = 
        self.layout_buttons.add_widget(self.register_button)

        self.login_status = LoginStatus()
        self.login_status.font_name='assets/font.otf'
        
        self.layout.add_widget(self.login_status)

        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='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.pos_hint={'center_y':0.5}
        self.label_username.halign='right'
        


        ## add all
        self.add_widget(self.layout)
        #pass


    # def on_enter(self):
    #     un=self.app.get_username()
    #     if un: self.username_field.text = un

    def show_pass_opt(self):
        if not self.pass_added:
            self.layout.add_widget(self.layout_password,index=2)
            self.pass_added=True

    def show_pass_opt1(self,button_text='login'):
        if not self.dialog:
            self.dialog = PasswordPopup(
                title="password:",
                type="custom",
                content_cls=MDTextField(password=True),
                buttons=[
                    MDFlatButton(
                        text="login"
                    ),
                ],
            )
        self.dialog.open()

    def getpass_func(self,why_msg,passphrase=None):
        return self.password_field.text if not passphrase else passphrase
        
    async def boot(self,un,pw=None):
        # await self.stat('hello',img_src='/home/ryan/comrad/data/contacts/marxxx.png',comrad_name='Keymaker')

        # 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
        # self.remove_widget(self.layout)


        # from screens.map import MapWidget,default_places
        # map = MapWidget()
        # map.open()
        # map.add_point(*default_places['Cambridge'],desc='Cambridge')
        # map.draw()
        # await asyncio.sleep(1)
        # map.add_point(*default_places['San Francisco'],desc='San Francisco')
        # map.draw()
        # await asyncio.sleep(1)
        # map.add_point(*default_places['Reykjavik'],desc='Reykjavik')
        # map.draw()
        # await asyncio.sleep(1)
        # return

        # remove login layout for now
        self.remove_widget(self.layout)


        # return
        name=un
        from comrad.backend import Comrad

        
        commie = Comrad(un)
        self.log('KOMMIE!?!?',commie)
        self.log('wtf',PATH_CRYPT_CA_KEYS)

        logger.info(f'booted commie: {commie}')
        if commie.exists_locally_as_account():
            # pw='marx' # @HACK FOR NOW
            pw=await self.app.get_input('Welcome back.',get_pass=True)
            commie.keychain(passphrase=pw)
            logger.info(f'updated keychain: {dict_format(commie.keychain())}')
            logger.info(f'is account')
            # self.login_status.text='You should be able to log into this account.'
            if commie.privkey:
                logger.info(f'passkey login succeeded')
                
                # get new data
                # res = await commie.get_updates()
                # if not res.get('res_login',{}).get('success'):
                #     return {'success':False,'res_refresh':refresh}
                 
                # otherwise, ok
                self.login_status.text=f'Welcome back, Comrad @{un}'
                self.app.is_logged_in=True
                self.app.username=commie.name
                self.app.comrad=commie
                self.root.change_screen('feed')
            else:
                logger.info(f'passkey login failed')
                self.login_status.text='Login failed...'
    

        #   self.layout.add_widget(self.layout_password)
        elif commie.exists_locally_as_contact():
            await self.app.stat('This is a contact of yours')
            self.login_status.text='Comrad exists as a contact of yours.'
            # self.app.change_screen('feed')
            self.app.change_screen('login')
        else:
            # await self.app.stat('Account does not exist on hardware, maybe not on server. Try to register?')
            # self.login_status.text='Comrad not known on this device. Registering...'
            
            ### REGISTER
            self.remove_widget(self.layout)
            res = await self.register(un)
            
            if commie.privkey:
                self.login_status.text='Registered'
                self.app.is_logged_in=True
                self.app.username=commie.name
                self.app.comrad=commie
                self.remove_widget(self.layout)
                self.app.change_screen('feed')
            else:
                self.login_status.text = 'Sign up failed...'
                self.app.change_screen('login')
        return 1

    
    async def register(self,name):
        async def logfunc(*x,**y):
            if not 'comrad_name' in y: y['comrad_name']='Keymaker'
            await self.app.stat(*x,**y)
        
        commie = Comrad(name)
        self.app.comrad = commie

        # already have it?
        if commie.exists_locally_as_account():
            return {'success':False, 'status':'You have already created this account.'}        
        if commie.exists_locally_as_contact():
            return {'success':False, 'status':'This is already a contact of yours'}
            
        # 
        await logfunc(f'Hello, this is Comrad @{name}. I would like to join the socialist network.',pause=True,comrad_name=name)
        
        await logfunc(f'Welcome, Comrad @{name}. To help us communicate safely, I have cut for you a matching pair of encryption keys.',pause=True,clear=True,comrad_name='Keymaker')


        # ## 2) Make pub public/private keys
        from comrad.backend.keymaker import ComradAsymmetricKey
        from comrad.cli.artcode import ART_KEY_PAIR
        keypair = ComradAsymmetricKey()
        logger.info('cut keypair!')
        pubkey,privkey = keypair.pubkey_obj,keypair.privkey_obj
        uri_id = pubkey.data_b64
        uri_s = pubkey.data_b64_s
        fnfn = commie.save_uri_as_qrcode(uri_id=uri_id,name=name)
        
        # await logfunc(f'Here. I have cut for you a private and public asymmetric key pair, using the iron-clad Elliptic curve algorithm:',comrad_name='Keymaker')

        await logfunc(f'The first is your "public key", which you can share with anyone. With it, someone can write you an encrypted message.',comrad_name='Keymaker')
        
        

        # delete qr!
        os.remove(fnfn)

        # await logfunc(f'(1) {pubkey} -- and -- (2) {privkey}',clear=True,pause=True,comrad_name='Keymaker')

        # await logfunc(f'(1) You may store your public key both on your device hardware, as well as share it with anyone you wish: {pubkey.data_b64_s}') #\n\nIt will also be stored as a QR code on your device:\n{qr_str}',pause=True,clear=True)
        


        commie._keychain['pubkey']=pubkey
        commie._keychain['privkey']=privkey
        
        from comrad.utils import dict_format
        self.log('My keychain now looks like:' + dict_format(commie.keychain()))
        # return




        ### PRIVATE KEY
        
       

        # ### PUBLIC KEY
        await logfunc('You can now register your username and public key with Comrad @Operator on the remote server.',pause=False,clear=False)

        await logfunc('Connecting you to the @Operator...',comrad_name='Telephone')

        ## CALL OP WITH PUBKEY
        # self.app.open_dialog('Calling @Operator...')
        logger.info('got here!')
        resp_msg_d = await self.app.ring_ring(
            {
                'name':name, 
                'pubkey': pubkey.data,
            },
            route='register_new_user',
            commie=commie
        )
        
        # self.app.close_dialog()
        
        
        # print()
        await logfunc(resp_msg_d.get('status'),comrad_name='Operator',pause=True)

        if not resp_msg_d.get('success'):
            self.app.comrad=None
            self.app.is_logged_in=False
            self.app.username=''
            
            await logfunc('''That's too bad. Cancelling registration for now.''',pause=True,clear=True)
            
            # self.app.change_screen('feed')
            self.app.change_screen('login')
            return

        # we're good on public key front
        commie.name=resp_msg_d.get('name')
        pubkey_b = resp_msg_d.get('pubkey')
        assert pubkey_b == pubkey.data
        uri_id = pubkey.data_b64
        sec_login = resp_msg_d.get('secret_login')
        _fnfn=commie.save_uri_as_qrcode(uri_id)
        commie.crypt_keys.set(name, pubkey_b, prefix='/pubkey/')
        commie.crypt_keys.set(uri_id, name, prefix='/name/')
        commie.crypt_keys.set(uri_id,sec_login,prefix='/secret_login/')
        


        await logfunc('Great. Comrad @Operator now has your name and public key on file (and nothing else!).',pause=True,clear=True)

        await logfunc(f'You can share it by pasting it to someone in a secure message:\n{uri_s}',comrad_name='Keymaker')
        
        await logfunc(f'You can also share it IRL, phone to phone, as a QR code. It is saved to {fnfn} and looks like this.',img_src=fnfn,comrad_name='Keymaker')





        ## PRIVATE KEY

        await logfunc(f"Your PRIVATE encryption key, on the other hand, will be stored only on your device hardware. Do not share it with anyone or across any network whatsoever.")
        await logfunc(f"In fact this private encryption is so sensitive we'll encrypt it before storing it on your device.",pause=True,use_prefix=False)
        
        passphrase = await self.app.get_input('Please enter a memorable password.',get_pass=True)
        if not passphrase or not str(passphrase).strip():
            return {'success':False, 'status':'No password entered'}

        passhash = hasher(str(passphrase).strip())
        privkey_decr = ComradSymmetricKeyWithPassphrase(passhash=passhash)
        print()
        
        await logfunc(f'''We immediately run whatever you typed through a 1-way hashing algorithm (SHA-256), scrambling it into (redacted):\n{make_key_discreet_str(passhash)}''',pause=True,clear=False)

        privkey_encr = privkey_decr.encrypt(privkey.data)
        privkey_encr_obj = ComradEncryptedAsymmetricPrivateKey(privkey_encr)
        commie._keychain['privkey_encr']=privkey_encr_obj
        self.log('My keychain now looks like v2:',dict_format(commie.keychain()))

       
        await logfunc(f'With this scrambled password we can encrypt your super-sensitive private key to:\n(after) {privkey_encr_obj.discreet}',pause=True,clear=False)

        # store privkey pieces
        commie.crypt_keys.set(uri_id, privkey_encr_obj.data, prefix='/privkey_encr/')
        # just to show we used a passphrase -->
        commie.crypt_keys.set(uri_id, ComradSymmetricKeyWithPassphrase.__name__, prefix='/privkey_decr/')


        # save qr too:
        # await logfunc(f'Saving public key, encrypted private key, and login secret to hardware-only database. Also saving public key as QR code to: {_fnfn}.',pause=True,clear=False,use_prefix=False)

        # done!
        await logfunc(f'Congratulations. Welcome, Comrad @{commie.name}.',pause=True,clear=True)
        
        # remove all dialogs!!!!!!!!
        # last minute: get posts
        if 'res_posts' in resp_msg_d and resp_msg_d['res_posts'].get('success'):
            id2post=resp_msg_d.get('res_posts').get('posts',{})
            if id2post:
                commie.log('found starter posts:',list(id2post.keys()))
            commie.save_posts(id2post)
            resp_msg_d['status']+=f'  You\'ve got {len(id2post)} new posts and 0 new messages.'
        


        # await logfunc('Returning...')

        from comrad.app.screens.map import MapWidget
        if self.app.map:
            self.app.map.dismiss()
            self.app.map=None
        self.app.change_screen('feed')
        
        return resp_msg_d

    

















class TextfieldLabel(ThemableBehavior, Label):
    font_style = OptionProperty("Body1", options=theme_font_styles)
    # <kivymd.uix.textfield.MDTextField object>
    field = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.font_size = sp(self.theme_cls.font_styles[self.font_style][1])
