feat: added functional for new disign for timers_screen

This commit is contained in:
Arduinum628
2025-10-02 11:35:42 +03:00
parent c196e02314
commit 0a6814372d
5 changed files with 267 additions and 80 deletions

View File

@@ -42,10 +42,10 @@ def list_timers() -> list[dict[str, int | str]]:
return [
{
'timer_id': timer.id,
'text': (
f'{timer.title}\n'
'title': timer.title,
'info': (
f'Помидоров: {timer.count_pomodoro}, '
f'размер помидора: {timer.pomodoro_time}'
f'Размер помидора: {timer.pomodoro_time}'
)
}
for timer in timers

View File

@@ -1,42 +1,67 @@
import kivy
kivy.require('2.3.1')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.metrics import dp
from kivy.uix.behaviors import ButtonBehavior
from kivy.logger import Logger
import logging
from kawai_focus.screens.timer_screen import TimerScreen
from kawai_focus.screens.timer_constructor_screen import TimerConstructorScreen
from kivymd.app import MDApp
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.list import MDListItemTrailingIcon
from kawai_focus.menu_app import MenuApp
from kawai_focus.screens.timers_screen import TimersScreen
from kawai_focus.database.cruds import list_timers
Logger.setLevel(logging.DEBUG)
class KawaiFocusApp(App):
"""Класс для создания приложения"""
class TrailingPressedIconButton(
ButtonBehavior, RotateBehavior, MDListItemTrailingIcon
):
"""Кнопка-иконка в конце элемента списка с поддержкой анимации"""
...
title = 'Kawai.Focus'
def build(self):
class KawaiFocusApp(MDApp, MenuApp):
"""Главный класс приложения"""
def build(self) -> MDScreenManager:
"""Создаёт и возвращает менеджер экранов приложения"""
self.theme_cls.theme_style = 'Dark'
# Загрузка kv файла
Builder.load_file('kv/timer_screen.kv')
Builder.load_file('kv/timer_constructor_screen.kv')
Builder.load_file('kv/timers_screen.kv')
screen_manager = ScreenManager()
timers = list_timers()
timers_screen = TimersScreen(name='timers_screen')
timers_screen.ids.timers_view.data = timers
self.screen_manager = MDScreenManager()
self.timers_screen = TimersScreen(name='timers_screen')
self.screen_manager.add_widget(self.timers_screen)
return self.screen_manager
def tap_expansion_chevron(
self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton
) -> None:
"""Анимация и переключение состояния раскрытия панели"""
screen_manager.add_widget(timers_screen)
screen_manager.add_widget(TimerConstructorScreen(name='timer_constructor_screen'))
screen_manager.add_widget(TimerScreen(name='timer_screen'))
return screen_manager
Animation(
padding=(
[0, dp(12), 0, dp(12)] if not panel.is_open else [0, 0, 0, 0]
),
d=0.2,
).start(panel)
panel.open() if not panel.is_open else panel.close()
(
panel.set_chevron_down(chevron)
if not panel.is_open
else panel.set_chevron_up(chevron)
)
def main() -> None:

115
kawai_focus/menu_app.py Normal file
View File

@@ -0,0 +1,115 @@
from kivy.utils import hex_colormap
from kivy.uix.widget import Widget
from materialyoucolor.utils.platform_utils import SCHEMES
from kivymd.uix.menu import MDDropdownMenu
class MenuApp:
"""Класс для меню приложения"""
menu: MDDropdownMenu = None
def open_menu(self, menu_button) -> None:
"""Открывает выпадающее меню"""
menu_items = []
for item, method in {
'Цвет темы': lambda: self.set_palette(),
'Стиль темы': lambda: self.switch_theme(),
'Тип схемы': lambda: self.set_scheme_type(),
'Новый таймер': None
}.items():
menu_items.append(
{
'text': item,
'on_release': method,
}
)
self.menu = MDDropdownMenu(
caller=menu_button,
items=menu_items,
)
self.menu.open()
def switch_palette(self, selected_palette: str) -> None:
"""Переключает основной цвет темы"""
self.theme_cls.primary_palette = selected_palette
def switch_theme(self) -> None:
"""Переключает светлую/тёмную тему"""
self.theme_cls.switch_theme()
def set_palette(self) -> None:
"""Формирует и открывает меню выбора палитры"""
instance_from_menu = self.get_instance_from_menu('Set palette')
available_palettes = [
name_color.capitalize() for name_color in hex_colormap.keys()
]
menu_items = []
for name_palette in available_palettes:
menu_items.append(
{
'text': name_palette,
'on_release': lambda x=name_palette: self.switch_palette(x),
}
)
MDDropdownMenu(
caller=instance_from_menu,
items=menu_items,
).open()
def set_scheme_type(self) -> None:
"""Формирует и открывает меню выбора типа цветовой схемы"""
instance_from_menu = self.get_instance_from_menu("Switch scheme type")
menu_items = []
for scheme_name in SCHEMES.keys():
menu_items.append(
{
'text': scheme_name,
'on_release': lambda x=scheme_name: self.update_scheme_name(x),
}
)
MDDropdownMenu(
caller=instance_from_menu,
items=menu_items,
).open()
def update_scheme_name(self, scheme_name: str) -> None:
"""Обновляет тип цветовой схемы"""
self.theme_cls.dynamic_scheme_name = scheme_name
def get_instance_from_menu(self, name_item: str) -> Widget:
"""Возвращает экземпляр элемента меню по его названию"""
index = 0
rv = self.menu.ids.md_menu
opts = rv.layout_manager.view_opts
datas = rv.data[0]
for data in rv.data:
if data.get('text') == name_item:
index = rv.data.index(data)
break
instance = rv.view_adapter.get_view(
index, datas, opts[index].get('viewclass')
)
return instance
def disabled_widgets(self) -> None:
"""Переключает активность виджетов (блокирует/разблокирует)"""
for widget in self.root.ids.widget_box.children:
widget.disabled = not widget.disabled
for widget in self.root.ids.custom_widget_box.children:
widget.disabled = not widget.disabled

View File

@@ -1,31 +1,55 @@
from kivy.uix.screenmanager import Screen
from kivy.properties import StringProperty, NumericProperty
from kivymd.uix.screen import MDScreen
from kivymd.uix.expansionpanel import MDExpansionPanel
from kawai_focus.utils.utils import calculate_time, gen_types_timers
from kawai_focus.database.cruds import get_timer
from kawai_focus.database.cruds import get_timer, list_timers
from kawai_focus.main import Logger
class TimersScreen(Screen):
class ExpansionPanelItem(MDExpansionPanel):
"""Кастомный элемент панели с данными таймера"""
timer_id = NumericProperty()
title = StringProperty()
info = StringProperty()
class TimersScreen(MDScreen):
"""Экран таймеры"""
def __init__(self, **kwargs):
super(TimersScreen, self).__init__(**kwargs)
def switch_new_timer(self, instance) -> None:
"""Метод для переключения на экран Конструктор таймера"""
def on_enter(self, *args) -> None:
"""Загружает список таймеров при входе на экран"""
self.load_timers()
self.manager.current = 'timer_constructor_screen'
def load_timers(self) -> None:
"""Загружает все таймеры и добавляет их в контейнер"""
self.ids.container.clear_widgets()
all_timers = list_timers()
for timer_data in all_timers:
panel = ExpansionPanelItem(
timer_id=timer_data.get('timer_id'),
title=timer_data.get('title'),
info=timer_data.get('info'),
)
self.ids.container.add_widget(panel)
def switch_timer(self, instance) -> None:
"""Метод для кнопки переключения на выбранный таймер"""
timer = get_timer(timer_id=instance.timer_id)
if not timer:
Logger.warning(f'Таймер с ID {instance.timer_id} не найден!')
return
screen_timer = self.manager.get_screen('timer_screen')
screen_timer.timer = timer
time_culc = calculate_time(mm_user=timer.pomodoro_time)
screen_timer.timer_start_time = time_culc
screen_timer.ids.time_label.text = time_culc
time_calc = calculate_time(mm_user=timer.pomodoro_time)
screen_timer.timer_start_time = time_calc
screen_timer.ids.time_label.text = time_calc
screen_timer.ids.title_label.text = timer.title
screen_timer.source_timer_names = gen_types_timers(count_pomodoro=timer.count_pomodoro)

View File

@@ -1,49 +1,72 @@
#:kivy 2.3.1
# Кастомная панель для каждого таймера
<ExpansionPanelItem>:
MDExpansionPanelHeader:
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
MDListItemSupportingText:
text: root.title
TrailingPressedIconButton:
id: chevron
icon: "chevron-right"
on_release: app.tap_expansion_chevron(root, chevron)
MDExpansionPanelContent:
orientation: "vertical"
padding: "12dp", 0, "12dp", "12dp"
md_bg_color: self.theme_cls.surfaceContainerLowColor
adaptive_height: True
MDLabel:
text: "Информация о таймере"
adaptive_height: True
padding_x: "16dp"
padding_y: "12dp"
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
on_release: None
MDListItemLeadingIcon:
icon: "information-outline"
MDListItemHeadlineText:
text: root.info
MDBoxLayout:
padding: [8, 8, 0, 0]
size_hint_y: None
height: self.minimum_height
MDButton:
style: "outlined"
size_hint_x: 1
MDButtonText:
text: "Открыть"
# Основной экран
<TimersScreen>:
FloatLayout:
RecycleView:
id: timers_view
size_hint: 1, 1
pos_hint: {"x": 0, "y": 0}
md_bg_color: self.theme_cls.backgroundColor
MDIconButton:
on_release: app.open_menu(self)
pos_hint: {"top": .98}
x: "12dp"
icon: "menu"
viewclass: "TimerButton"
ScrollView:
size_hint_x: .9
pos_hint: {"center_x": .5, "center_y": .5}
do_scroll_x: False
do_scroll_y: True
RecycleBoxLayout:
default_size: None, dp(50)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
spacing: dp(5)
Button:
id: new_timer
text: 'Новый таймер'
size_hint: None, None
height: 40
width: 120
pos_hint: {"center_x": 0.3, "center_y": 0.1}
on_release: root.switch_new_timer(self)
<TimerButton@Button>:
timer_id: None
text: ""
on_release: app.root.get_screen("timers_screen").switch_timer(self)
size_hint: None, None
height: dp(50)
background_normal: "" # отключаем стандартный фон
background_color: 0, 0, 0, 0 # прозрачный
canvas.before:
Color:
rgba: 1, 1, 1, 1 # белый контур
Line:
width: 1.5
rectangle: (self.x, self.y, self.width, self.height)
Color:
rgba: (0, 0.5, 1, 0.5) if self.state == "down" else (0, 0, 0, 0)
Rectangle:
pos: self.pos
size: self.size
MDList:
id: container
spacing: "8dp"
padding: [56, 8, 56, 0] # [слева, сверху, справа, снизу]