Refactor animated Text into component

This commit is contained in:
David Rodenkirchen 2024-08-27 15:27:46 +02:00
parent 81ec29cda1
commit 259786a1d3
4 changed files with 69 additions and 130 deletions

View File

@ -0,0 +1,38 @@
from asyncio import sleep
from rio import Text, Component, TextStyle
class AnimatedText(Component):
def __post_init__(self) -> None:
self._display_printing: list[bool] = [False]
self.text_comp = Text("")
async def display_text(self, success: bool, text: str, speed: float = 0.08) -> None:
if self._display_printing[0]:
return
else:
self._display_printing[0] = True
self.text_comp.text = ""
if success:
self.text_comp.style = TextStyle(
fill=self.session.theme.success_color,
font_size=0.9
)
for c in text:
self.text_comp.text = self.text_comp.text + c
await self.text_comp.force_refresh()
await sleep(speed)
else:
self.text_comp.style = TextStyle(
fill=self.session.theme.danger_color,
font_size=0.9
)
for c in text:
self.text_comp.text = self.text_comp.text + c
await self.text_comp.force_refresh()
await sleep(speed)
self._display_printing[0] = False
def build(self) -> Component:
return self.text_comp

View File

@ -1,9 +1,9 @@
from asyncio import sleep
from datetime import datetime, timedelta from datetime import datetime, timedelta
from rio import Text, Column, TextStyle, Component, event, TextInput, MultiLineTextInput, Row, Button from rio import Text, Column, TextStyle, Component, event, TextInput, MultiLineTextInput, Row, Button
from src.ez_lan_manager import ConfigurationService, UserService, MailingService from src.ez_lan_manager import ConfigurationService, UserService, MailingService
from src.ez_lan_manager.components.AnimatedText import AnimatedText
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.SessionStorage import SessionStorage from src.ez_lan_manager.types.SessionStorage import SessionStorage
@ -19,53 +19,27 @@ class ContactPage(Component):
async def on_populate(self) -> None: async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt") await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt")
async def display_info_animation(self, success: bool, text: str) -> None:
if self.display_printing[0]:
return
else:
self.display_printing[0] = True
self.info_text.text = ""
if success:
self.info_text.style = TextStyle(
fill=self.session.theme.success_color,
font_size=0.9
)
for c in text:
self.info_text.text = self.info_text.text + c
await self.info_text.force_refresh()
await sleep(0.08)
else:
self.info_text.style = TextStyle(
fill=self.session.theme.danger_color,
font_size=0.9
)
for c in text:
self.info_text.text = self.info_text.text + c
await self.info_text.force_refresh()
await sleep(0.08)
self.display_printing[0] = False
async def on_send_pressed(self) -> None: async def on_send_pressed(self) -> None:
self.submit_button.is_loading = True self.submit_button.is_loading = True
await self.submit_button.force_refresh() await self.submit_button.force_refresh()
now = datetime.now() now = datetime.now()
if not self.email_input.text: if not self.email_input.text:
self.is_send_button_loading = False self.is_send_button_loading = False
await self.display_info_animation(False, "E-Mail darf nicht leer sein!") await self.animated_text.display_text(False, "E-Mail darf nicht leer sein!")
return return
if not self.subject_input.text: if not self.subject_input.text:
self.is_send_button_loading = False self.is_send_button_loading = False
await self.display_info_animation(False, "Betreff darf nicht leer sein!") await self.animated_text.display_text(False, "Betreff darf nicht leer sein!")
return return
if not self.message_input.text: if not self.message_input.text:
self.is_send_button_loading = False self.is_send_button_loading = False
await self.display_info_animation(False, "Nachricht darf nicht leer sein!") await self.animated_text.display_text(False, "Nachricht darf nicht leer sein!")
return return
if (now - self.last_message_sent[0]) < timedelta(minutes=1): if (now - self.last_message_sent[0]) < timedelta(minutes=1):
await self.display_info_animation(False, "Immer mit der Ruhe!") await self.animated_text.display_text(False, "Immer mit der Ruhe!")
return return
mail_recipient = self.session[ConfigurationService].get_lan_info().organizer_mail mail_recipient = self.session[ConfigurationService].get_lan_info().organizer_mail
@ -78,7 +52,7 @@ class ContactPage(Component):
await self.session[MailingService].send_email("Kontaktformular-Mitteilung", msg, mail_recipient) await self.session[MailingService].send_email("Kontaktformular-Mitteilung", msg, mail_recipient)
self.last_message_sent[0] = datetime.now() self.last_message_sent[0] = datetime.now()
self.submit_button.is_loading = False self.submit_button.is_loading = False
await self.display_info_animation(True, "Nachricht erfolgreich gesendet!") await self.animated_text.display_text(True, "Nachricht erfolgreich gesendet!")
def build(self) -> Component: def build(self) -> Component:
if self.session[SessionStorage].user_id is not None: if self.session[SessionStorage].user_id is not None:
@ -86,11 +60,10 @@ class ContactPage(Component):
else: else:
user = None user = None
self.info_text = Text( self.animated_text = AnimatedText(
"", margin_top = 2,
margin_top=2, margin_bottom = 1,
margin_bottom=1, align_x = 0.1
align_x=0.1
) )
self.email_input = TextInput( self.email_input = TextInput(
@ -152,7 +125,7 @@ class ContactPage(Component):
self.subject_input, self.subject_input,
self.message_input, self.message_input,
Row( Row(
self.info_text, self.animated_text,
self.submit_button, self.submit_button,
) )
) )
@ -161,4 +134,3 @@ class ContactPage(Component):
), ),
grow_x=True grow_x=True
) )

View File

@ -1,5 +1,4 @@
from datetime import date, datetime from datetime import date, datetime
from asyncio import sleep
from hashlib import sha256 from hashlib import sha256
from typing import Optional from typing import Optional
@ -8,6 +7,7 @@ from rio import Column, Component, event, Text, TextStyle, Button, Color, Row, T
from email_validator import validate_email, EmailNotValidError from email_validator import validate_email, EmailNotValidError
from src.ez_lan_manager import ConfigurationService, UserService from src.ez_lan_manager import ConfigurationService, UserService
from src.ez_lan_manager.components.AnimatedText import AnimatedText
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.SessionStorage import SessionStorage from src.ez_lan_manager.types.SessionStorage import SessionStorage
@ -15,8 +15,6 @@ from src.ez_lan_manager.types.User import User
class EditProfilePage(Component): class EditProfilePage(Component):
display_printing: list[bool] = [False]
@staticmethod @staticmethod
def optional_date_to_str(d: Optional[date]) -> str: def optional_date_to_str(d: Optional[date]) -> str:
if not d: if not d:
@ -52,54 +50,26 @@ class EditProfilePage(Component):
try: try:
new_pfp = await self.session.file_chooser(file_extensions=("png", "jpg", "jpeg"), multiple=False) new_pfp = await self.session.file_chooser(file_extensions=("png", "jpg", "jpeg"), multiple=False)
except NoFileSelectedError: except NoFileSelectedError:
await self.display_save_result_animation(False, optional_text="Keine Datei ausgewählt!") await self.animated_text.display_text(False, "Keine Datei ausgewählt!")
return return
if new_pfp.size_in_bytes > 2 * 1_000_000: if new_pfp.size_in_bytes > 2 * 1_000_000:
await self.display_save_result_animation(False, optional_text="Bild zu groß! (> 2MB)") await self.animated_text.display_text(False, "Bild zu groß! (> 2MB)")
return return
image_data = await new_pfp.read_bytes() image_data = await new_pfp.read_bytes()
self.session[UserService].set_profile_picture(self.session[SessionStorage].user_id, image_data) self.session[UserService].set_profile_picture(self.session[SessionStorage].user_id, image_data)
self.pfp_image_container.image = image_data self.pfp_image_container.image = image_data
await self.display_save_result_animation(True) await self.animated_text.display_text(True, "Gespeichert!")
async def display_save_result_animation(self, success: bool, optional_text: Optional[str] = None) -> None:
if self.display_printing[0]:
return
else:
self.display_printing[0] = True
self.saved_text.text = ""
if success:
self.saved_text.style = TextStyle(
fill=self.session.theme.success_color,
font_size=0.9
)
t = "Gespeichert!" if not optional_text else optional_text
for c in t:
self.saved_text.text = self.saved_text.text + c
await self.saved_text.force_refresh()
await sleep(0.08)
else:
self.saved_text.style = TextStyle(
fill=self.session.theme.danger_color,
font_size=0.9
)
t = "Fehler!" if not optional_text else optional_text
for c in t:
self.saved_text.text = self.saved_text.text + c
await self.saved_text.force_refresh()
await sleep(0.08)
self.display_printing[0] = False
async def on_save_pressed(self) -> None: async def on_save_pressed(self) -> None:
if not all((self.email_input.is_valid, self.birthday_input.is_valid)): if not all((self.email_input.is_valid, self.birthday_input.is_valid)):
await self.display_save_result_animation(False, optional_text="Ungültige Werte!") await self.animated_text.display_text(False, "Ungültige Werte!")
return return
if len(self.new_pw_1_input.text.strip()) > 0: if len(self.new_pw_1_input.text.strip()) > 0:
if self.new_pw_1_input.text.strip() != self.new_pw_2_input.text.strip(): if self.new_pw_1_input.text.strip() != self.new_pw_2_input.text.strip():
await self.display_save_result_animation(False, optional_text="Passwörter nicht gleich!") await self.animated_text.display_text(False, "Passwörter nicht gleich!")
return return
user: User = self.session[UserService].get_user(self.session[SessionStorage].user_id) user: User = self.session[UserService].get_user(self.session[SessionStorage].user_id)
@ -117,16 +87,13 @@ class EditProfilePage(Component):
user.user_password = sha256(self.new_pw_1_input.text.encode(encoding="utf-8")).hexdigest() user.user_password = sha256(self.new_pw_1_input.text.encode(encoding="utf-8")).hexdigest()
self.session[UserService].update_user(user) self.session[UserService].update_user(user)
await self.display_save_result_animation(True) await self.animated_text.display_text(True, "Gespeichert!")
def build(self) -> Component: def build(self) -> Component:
user = self.session[UserService].get_user(self.session[SessionStorage].user_id) user = self.session[UserService].get_user(self.session[SessionStorage].user_id)
pfp = self.session[UserService].get_profile_picture(user.user_id) pfp = self.session[UserService].get_profile_picture(user.user_id)
self.saved_text = Text( self.animated_text = AnimatedText(
"",
margin_top=2, margin_top=2,
margin_bottom=1, margin_bottom=1,
align_x=0.1 align_x=0.1
@ -224,7 +191,7 @@ class EditProfilePage(Component):
self.new_pw_2_input, self.new_pw_2_input,
Row( Row(
self.saved_text, self.animated_text,
Button( Button(
content=Text( content=Text(
"Speichern", "Speichern",

View File

@ -1,11 +1,10 @@
import logging import logging
from asyncio import sleep
from typing import Optional
from email_validator import validate_email, EmailNotValidError from email_validator import validate_email, EmailNotValidError
from rio import Column, Component, event, Text, TextStyle, TextInput, TextInputChangeEvent, Button from rio import Column, Component, event, Text, TextStyle, TextInput, TextInputChangeEvent, Button
from src.ez_lan_manager import ConfigurationService, UserService, MailingService from src.ez_lan_manager import ConfigurationService, UserService, MailingService
from src.ez_lan_manager.components.AnimatedText import AnimatedText
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage from src.ez_lan_manager.pages import BasePage
@ -14,8 +13,6 @@ MINIMUM_PASSWORD_LENGTH = 6
logger = logging.getLogger(__name__.split(".")[-1]) logger = logging.getLogger(__name__.split(".")[-1])
class RegisterPage(Component): class RegisterPage(Component):
display_printing: list[bool] = [False]
def on_pw_change(self, _: TextInputChangeEvent) -> None: def on_pw_change(self, _: TextInputChangeEvent) -> None:
if not (self.pw_1.text == self.pw_2.text) or len(self.pw_1.text) < MINIMUM_PASSWORD_LENGTH: if not (self.pw_1.text == self.pw_2.text) or len(self.pw_1.text) < MINIMUM_PASSWORD_LENGTH:
self.pw_1.is_valid = False self.pw_1.is_valid = False
@ -37,22 +34,22 @@ class RegisterPage(Component):
await self.submit_button.force_refresh() await self.submit_button.force_refresh()
if len(self.user_name_input.text) < 1: if len(self.user_name_input.text) < 1:
await self.display_save_result_animation(False, optional_text="Nutzername darf nicht leer sein!") await self.animated_text.display_text(False, "Nutzername darf nicht leer sein!")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
if not (self.pw_1.text == self.pw_2.text): if not (self.pw_1.text == self.pw_2.text):
await self.display_save_result_animation(False, optional_text="Passwörter stimmen nicht überein!") await self.animated_text.display_text(False, "Passwörter stimmen nicht überein!")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
if len(self.pw_1.text) < MINIMUM_PASSWORD_LENGTH: if len(self.pw_1.text) < MINIMUM_PASSWORD_LENGTH:
await self.display_save_result_animation(False, optional_text=f"Passwort muss mindestens {MINIMUM_PASSWORD_LENGTH} Zeichen lang sein!") await self.animated_text.display_text(False, f"Passwort muss mindestens {MINIMUM_PASSWORD_LENGTH} Zeichen lang sein!")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
if not self.email_input.is_valid or len(self.email_input.text) < 3: if not self.email_input.is_valid or len(self.email_input.text) < 3:
await self.display_save_result_animation(False, optional_text="E-Mail Adresse ungültig!") await self.animated_text.display_text(False, "E-Mail Adresse ungültig!")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
@ -61,7 +58,7 @@ class RegisterPage(Component):
lan_info = self.session[ConfigurationService].get_lan_info() lan_info = self.session[ConfigurationService].get_lan_info()
if user_service.get_user(self.email_input.text) is not None or user_service.get_user(self.user_name_input.text) is not None: if user_service.get_user(self.email_input.text) is not None or user_service.get_user(self.user_name_input.text) is not None:
await self.display_save_result_animation(False, optional_text="Benutzername oder E-Mail bereits regestriert!") await self.animated_text.display_text(False, "Benutzername oder E-Mail bereits regestriert!")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
@ -71,7 +68,7 @@ class RegisterPage(Component):
raise RuntimeError("User could not be created") raise RuntimeError("User could not be created")
except Exception as e: except Exception as e:
logger.error(f"Unknown error during new user registration: {e}") logger.error(f"Unknown error during new user registration: {e}")
await self.display_save_result_animation(False, optional_text="Es ist ein unbekannter Fehler aufgetreten :(") await self.animated_text.display_text(False, "Es ist ein unbekannter Fehler aufgetreten :(")
self.submit_button.is_loading = False self.submit_button.is_loading = False
return return
@ -85,36 +82,7 @@ class RegisterPage(Component):
) )
self.submit_button.is_loading = False self.submit_button.is_loading = False
await self.display_save_result_animation(True, optional_text="Erfolgreich registriert!") await self.animated_text.display_text(True, "Erfolgreich registriert!")
async def display_save_result_animation(self, success: bool, optional_text: Optional[str] = None) -> None:
if self.display_printing[0]:
return
else:
self.display_printing[0] = True
self.info_text.text = ""
if success:
self.info_text.style = TextStyle(
fill=self.session.theme.success_color,
font_size=1
)
t = "Gespeichert!" if not optional_text else optional_text
for c in t:
self.info_text.text = self.info_text.text + c
await self.info_text.force_refresh()
await sleep(0.04)
else:
self.info_text.style = TextStyle(
fill=self.session.theme.danger_color,
font_size=1
)
t = "Fehler!" if not optional_text else optional_text
for c in t:
self.info_text.text = self.info_text.text + c
await self.info_text.force_refresh()
await sleep(0.04)
self.display_printing[0] = False
@event.on_populate @event.on_populate
async def on_populate(self) -> None: async def on_populate(self) -> None:
@ -174,17 +142,11 @@ class RegisterPage(Component):
color=self.session.theme.secondary_color, color=self.session.theme.secondary_color,
on_press=self.on_submit_button_pressed on_press=self.on_submit_button_pressed
) )
self.info_text = Text( self.animated_text = AnimatedText(
text="",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=2, margin_top=2,
margin_left=1, margin_left=1,
margin_right=1, margin_right=1,
margin_bottom=2, margin_bottom=2
wrap=True
) )
return BasePage( return BasePage(
content=Column( content=Column(
@ -205,7 +167,7 @@ class RegisterPage(Component):
self.pw_1, self.pw_1,
self.pw_2, self.pw_2,
self.submit_button, self.submit_button,
self.info_text self.animated_text
) )
), ),
align_y=0, align_y=0,