feat: added validation for timer constructor, added function to calculate hours, minutes and seconds from entered minutes
This commit is contained in:
@@ -1,52 +1,95 @@
|
|||||||
from kivy.uix.textinput import TextInput
|
from kivy.uix.textinput import TextInput
|
||||||
|
|
||||||
|
|
||||||
|
class BaseNumBehavior:
|
||||||
class BaseNumInput(TextInput):
|
"""Псевдо-интерфейс для числового ввода"""
|
||||||
"""Базовый класс для поля числа"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.text = '0'
|
|
||||||
self.halign = 'center'
|
|
||||||
|
|
||||||
def increment(self):
|
def increment(self):
|
||||||
"""Метод для прибавки 1"""
|
raise NotImplementedError('Метод increment() должен быть реализован')
|
||||||
|
|
||||||
self.text = str(int(self.text) + 1)
|
|
||||||
|
|
||||||
def decrement(self):
|
def decrement(self):
|
||||||
"""Метод для вычитания 1"""
|
raise NotImplementedError('Метод decrement() должен быть реализован')
|
||||||
|
|
||||||
self.text = str(int(self.text) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
class TimeTomatoInput(BaseNumInput):
|
class TimeTomatoInput(TextInput, BaseNumBehavior):
|
||||||
"""Класс для поля ввода колличества помидорово"""
|
"""Класс для поля ввода колличества помидорово"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.text = '25'
|
self.text = '25'
|
||||||
|
self.halign = 'center'
|
||||||
|
|
||||||
|
def increment(self):
|
||||||
|
"""Метод для прибавки 1"""
|
||||||
|
|
||||||
|
if int(self.text) < 90:
|
||||||
|
self.text = str(int(self.text) + 1)
|
||||||
|
|
||||||
|
def decrement(self):
|
||||||
|
"""Метод для вычитания 1"""
|
||||||
|
|
||||||
|
if int(self.text) > 10:
|
||||||
|
self.text = str(int(self.text) - 1)
|
||||||
|
|
||||||
|
|
||||||
class TimeBreakInput(BaseNumInput):
|
class TimeBreakInput(TextInput, BaseNumBehavior):
|
||||||
"""Класс для поля ввода времени перерыва"""
|
"""Класс для поля ввода времени перерыва"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.text = '5'
|
self.text = '5'
|
||||||
|
self.halign = 'center'
|
||||||
|
|
||||||
class TimeLoongBreakInput(BaseNumInput):
|
def increment(self):
|
||||||
|
"""Метод для прибавки 1"""
|
||||||
|
|
||||||
|
if int(self.text) < 10:
|
||||||
|
self.text = str(int(self.text) + 1)
|
||||||
|
|
||||||
|
def decrement(self):
|
||||||
|
"""Метод для вычитания 1"""
|
||||||
|
|
||||||
|
if int(self.text) > 3:
|
||||||
|
self.text = str(int(self.text) - 1)
|
||||||
|
|
||||||
|
|
||||||
|
class TimeLoongBreakInput(TextInput, BaseNumBehavior):
|
||||||
"""Класс для поля ввода времени длительного перерыва"""
|
"""Класс для поля ввода времени длительного перерыва"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.text = '15'
|
self.text = '15'
|
||||||
|
self.halign = 'center'
|
||||||
|
|
||||||
|
def increment(self):
|
||||||
|
"""Метод для прибавки 1"""
|
||||||
|
|
||||||
|
if int(self.text) < 40:
|
||||||
|
self.text = str(int(self.text) + 1)
|
||||||
|
|
||||||
|
def decrement(self):
|
||||||
|
"""Метод для вычитания 1"""
|
||||||
|
|
||||||
|
if int(self.text) > 15:
|
||||||
|
self.text = str(int(self.text) - 1)
|
||||||
|
|
||||||
|
|
||||||
class CountTomatosInput(BaseNumInput):
|
class CountTomatosInput(TextInput, BaseNumBehavior):
|
||||||
"""Класс для поля ввода количества помидоров"""
|
"""Класс для поля ввода количества помидоров"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.text = '4'
|
self.text = '4'
|
||||||
|
self.halign = 'center'
|
||||||
|
|
||||||
|
def increment(self):
|
||||||
|
"""Метод для прибавки 1"""
|
||||||
|
|
||||||
|
if int(self.text) < 8:
|
||||||
|
self.text = str(int(self.text) + 1)
|
||||||
|
|
||||||
|
def decrement(self):
|
||||||
|
"""Метод для вычитания 1"""
|
||||||
|
|
||||||
|
if int(self.text) > 2:
|
||||||
|
self.text = str(int(self.text) - 1)
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ class TimerTimeModel(BaseModel):
|
|||||||
|
|
||||||
hh: int = Field(0, ge=0, le=23)
|
hh: int = Field(0, ge=0, le=23)
|
||||||
mm: int = Field(0, ge=0, le=59)
|
mm: int = Field(0, ge=0, le=59)
|
||||||
ss: int = Field(0, ge=0, le=59)
|
|
||||||
|
|
||||||
@field_validator('hh', 'mm', 'ss')
|
@field_validator('hh', 'mm')
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_all_time_fields(cls, value: int) -> int:
|
def check_all_time_fields(cls, value: int) -> int:
|
||||||
"""Метод валидирует все поля времени"""
|
"""Метод валидирует все поля времени"""
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ from kivy.uix.screenmanager import Screen
|
|||||||
from kawai_focus.custom_widgets.timer_wigets import TimeTomatoInput
|
from kawai_focus.custom_widgets.timer_wigets import TimeTomatoInput
|
||||||
from kawai_focus.schemas import TimerModel
|
from kawai_focus.schemas import TimerModel
|
||||||
from kawai_focus.database.cruds import new_timer
|
from kawai_focus.database.cruds import new_timer
|
||||||
|
from kawai_focus.utils.utils import calculate_time, custom_timer
|
||||||
|
from kawai_focus.screens.validators_fields import validate_title
|
||||||
|
|
||||||
|
|
||||||
class TimerConstructorScreen(Screen):
|
class TimerConstructorScreen(Screen):
|
||||||
@@ -14,6 +16,12 @@ class TimerConstructorScreen(Screen):
|
|||||||
def create_timer(self, instance):
|
def create_timer(self, instance):
|
||||||
"""Метод для создания таймера"""
|
"""Метод для создания таймера"""
|
||||||
|
|
||||||
|
validate_title(self, self.ids.title.text)
|
||||||
|
|
||||||
|
# прекратить создание таймера если поле пустое
|
||||||
|
if not self.ids.title.text:
|
||||||
|
return
|
||||||
|
|
||||||
timer = new_timer(
|
timer = new_timer(
|
||||||
data=TimerModel(
|
data=TimerModel(
|
||||||
title=self.ids.title.text,
|
title=self.ids.title.text,
|
||||||
@@ -27,12 +35,10 @@ class TimerConstructorScreen(Screen):
|
|||||||
if timer:
|
if timer:
|
||||||
screen_timer = self.manager.get_screen('timers_screen')
|
screen_timer = self.manager.get_screen('timers_screen')
|
||||||
screen_timer.timer = timer
|
screen_timer.timer = timer
|
||||||
# Todo: временное решение: нужно сделать механизм для
|
time_culc = calculate_time(mm_user=timer.pomodoro_time)
|
||||||
# автоматического рассчёта часов, минут и секунд из
|
screen_timer.timer_start_time = time_culc
|
||||||
# колличества минут, введённого пользователем
|
screen_timer.ids.time_label.text = time_culc
|
||||||
screen_timer.ids.time_label.text = f'00:{
|
screen_timer.timer_generator = custom_timer(mm_user=timer.pomodoro_time)
|
||||||
"0" + str(timer.pomodoro_time) if timer.pomodoro_time <= 9 else timer.pomodoro_time
|
|
||||||
}:00'
|
|
||||||
self.manager.current = 'timers_screen'
|
self.manager.current = 'timers_screen'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ from kivy.uix.screenmanager import Screen
|
|||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.core.audio import SoundLoader
|
from kivy.core.audio import SoundLoader
|
||||||
|
|
||||||
from kawai_focus.utils.utils import custom_timer, data_json
|
from kawai_focus.utils.utils import data_json
|
||||||
from kawai_focus.schemas import TimerTimeModel
|
|
||||||
|
|
||||||
|
|
||||||
class TimerScreen(Screen):
|
class TimerScreen(Screen):
|
||||||
@@ -22,6 +21,7 @@ class TimerScreen(Screen):
|
|||||||
self.remaining_time = None
|
self.remaining_time = None
|
||||||
self.sound_stop_event = None
|
self.sound_stop_event = None
|
||||||
self.timer = None
|
self.timer = None
|
||||||
|
self.timer_start_time = None
|
||||||
|
|
||||||
def start_timer(self, instance) -> None:
|
def start_timer(self, instance) -> None:
|
||||||
"""Метод для запуска таймера"""
|
"""Метод для запуска таймера"""
|
||||||
@@ -30,8 +30,6 @@ class TimerScreen(Screen):
|
|||||||
self.paused = False
|
self.paused = False
|
||||||
else:
|
else:
|
||||||
# Инициализация генератора таймера
|
# Инициализация генератора таймера
|
||||||
self.valid_timer_data = TimerTimeModel(mm=self.timer.pomodoro_time)
|
|
||||||
self.timer_generator = custom_timer(valid_data=self.valid_timer_data)
|
|
||||||
self.remaining_time = next(self.timer_generator, self.zero_time)
|
self.remaining_time = next(self.timer_generator, self.zero_time)
|
||||||
|
|
||||||
# Запуск обновления времени каждую секунду
|
# Запуск обновления времени каждую секунду
|
||||||
@@ -51,14 +49,8 @@ class TimerScreen(Screen):
|
|||||||
# Остановка обновления времени
|
# Остановка обновления времени
|
||||||
Clock.unschedule(self.update_time)
|
Clock.unschedule(self.update_time)
|
||||||
self.paused = False
|
self.paused = False
|
||||||
self.remaining_time = TimerTimeModel(mm=self.timer.pomodoro_time).mm
|
self.remaining_time = next(self.timer_generator, self.zero_time)
|
||||||
# Todo: временное решение: нужно сделать механизм для
|
self.ids.time_label.text = self.timer_start_time
|
||||||
# автоматического рассчёта часов, минут и секунд из
|
|
||||||
# колличества минут, введённого пользователем
|
|
||||||
self.ids.time_label.text = f'00:{
|
|
||||||
"0" + str(self.remaining_time) if self.remaining_time <= 9 else self.remaining_time
|
|
||||||
}:00'
|
|
||||||
|
|
||||||
self.sound.stop()
|
self.sound.stop()
|
||||||
|
|
||||||
if self.sound_stop_event:
|
if self.sound_stop_event:
|
||||||
|
|||||||
5
kawai_focus/screens/validators_fields.py
Normal file
5
kawai_focus/screens/validators_fields.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
def validate_title(obj, text):
|
||||||
|
"""Валидатор поля title"""
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
obj.ids.title_error.text = 'Введите название!'
|
||||||
@@ -2,7 +2,6 @@ from typing import Generator
|
|||||||
import json
|
import json
|
||||||
from os import path, listdir
|
from os import path, listdir
|
||||||
|
|
||||||
from kawai_focus.main import Logger
|
|
||||||
from kawai_focus.schemas import TimerTimeModel
|
from kawai_focus.schemas import TimerTimeModel
|
||||||
from kawai_focus.utils.errors import ErrorMessage
|
from kawai_focus.utils.errors import ErrorMessage
|
||||||
|
|
||||||
@@ -45,16 +44,30 @@ class ReadJson:
|
|||||||
data_json = ReadJson(folder_json='json')
|
data_json = ReadJson(folder_json='json')
|
||||||
|
|
||||||
|
|
||||||
def custom_timer(valid_data: TimerTimeModel) -> Generator[str, None, None]:
|
def custom_timer(mm_user: int) -> Generator[str, None, None]:
|
||||||
"""Функция отсчитывает время, установленное для таймера в формате
|
"""Функция отсчитывает время, установленное для таймера в формате
|
||||||
'hh:mm:ss'. Возвращает генератор, который возвращает текущее время
|
'hh:mm:ss'. Возвращает генератор, который возвращает текущее время
|
||||||
в формате 'hh:mm:ss'."""
|
в формате 'hh:mm:ss'."""
|
||||||
|
|
||||||
try:
|
total_seconds = mm_user * 60
|
||||||
total_seconds = (int(valid_data.hh) * 3600) + (int(valid_data.mm) * 60) + (int(valid_data.ss))
|
|
||||||
|
|
||||||
for remaining in range(total_seconds, -1, -1):
|
for remaining in range(total_seconds, -1, -1):
|
||||||
yield f"{remaining // 3600:02d}:{(remaining % 3600) // 60:02d}:{remaining % 60:02d}"
|
yield f"{remaining // 3600:02d}:{(remaining % 3600) // 60:02d}:{remaining % 60:02d}"
|
||||||
except (TypeError, ValueError) as err:
|
|
||||||
Logger.error(f'Logger: {err.__class__.__name__}: {err}')
|
|
||||||
|
def calculate_time(mm_user: int) -> str:
|
||||||
|
"""Функция для подсчёта часов, минут и секунд из минут"""
|
||||||
|
|
||||||
|
valid_data = None
|
||||||
|
hh = mm_user // 60
|
||||||
|
mm = mm_user % 60
|
||||||
|
|
||||||
|
if hh == 0:
|
||||||
|
valid_data = TimerTimeModel(mm=mm)
|
||||||
|
else:
|
||||||
|
valid_data = TimerTimeModel(hh=hh, mm=mm)
|
||||||
|
|
||||||
|
return (
|
||||||
|
f"{'0' + str(valid_data.hh) if valid_data.hh <= 9 else valid_data.hh}:"
|
||||||
|
f"{'0' + str(valid_data.mm) if valid_data.mm <= 9 else valid_data.mm}:00"
|
||||||
|
)
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
pos_hint: {"center_x": 0.5, "center_y": 0.9}
|
pos_hint: {"center_x": 0.5, "center_y": 0.9}
|
||||||
hint_text: "название"
|
hint_text: "название"
|
||||||
|
|
||||||
|
Label:
|
||||||
|
id: title_error
|
||||||
|
text: ""
|
||||||
|
color: (1, 0.3, 0.3, 1)
|
||||||
|
font_size: 14
|
||||||
|
size_hint_y: None
|
||||||
|
height: 20
|
||||||
|
pos_hint: {"center_x": 0.5, "center_y": 0.8}
|
||||||
|
|
||||||
# числовой счётчик "время помидора"
|
# числовой счётчик "время помидора"
|
||||||
Label:
|
Label:
|
||||||
text: "помидор"
|
text: "помидор"
|
||||||
@@ -25,6 +34,7 @@
|
|||||||
|
|
||||||
TimeTomatoInput:
|
TimeTomatoInput:
|
||||||
id: time_tomato_input
|
id: time_tomato_input
|
||||||
|
disabled: True
|
||||||
size_hint: None, None
|
size_hint: None, None
|
||||||
size: 40, 30
|
size: 40, 30
|
||||||
pos_hint: {"center_x": 0.6, "center_y": 0.7}
|
pos_hint: {"center_x": 0.6, "center_y": 0.7}
|
||||||
@@ -51,6 +61,7 @@
|
|||||||
|
|
||||||
TimeBreakInput:
|
TimeBreakInput:
|
||||||
id: time_break_input
|
id: time_break_input
|
||||||
|
disabled: True
|
||||||
size_hint: None, None
|
size_hint: None, None
|
||||||
size: 40, 30
|
size: 40, 30
|
||||||
pos_hint: {"center_x": 0.6, "center_y": 0.6}
|
pos_hint: {"center_x": 0.6, "center_y": 0.6}
|
||||||
@@ -77,6 +88,7 @@
|
|||||||
|
|
||||||
TimeLoongBreakInput:
|
TimeLoongBreakInput:
|
||||||
id: time_long_break_input
|
id: time_long_break_input
|
||||||
|
disabled: True
|
||||||
size_hint: None, None
|
size_hint: None, None
|
||||||
size: 40, 30
|
size: 40, 30
|
||||||
pos_hint: {"center_x": 0.6, "center_y": 0.5}
|
pos_hint: {"center_x": 0.6, "center_y": 0.5}
|
||||||
@@ -103,6 +115,7 @@
|
|||||||
|
|
||||||
CountTomatosInput:
|
CountTomatosInput:
|
||||||
id: count_tomatos_input
|
id: count_tomatos_input
|
||||||
|
disabled: True
|
||||||
size_hint: None, None
|
size_hint: None, None
|
||||||
size: 40, 30
|
size: 40, 30
|
||||||
pos_hint: {"center_x": 0.6, "center_y": 0.4}
|
pos_hint: {"center_x": 0.6, "center_y": 0.4}
|
||||||
|
|||||||
Reference in New Issue
Block a user