feat: added functional for new disign for timers_screen
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
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
|
||||
return self.screen_manager
|
||||
|
||||
def tap_expansion_chevron(
|
||||
self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton
|
||||
) -> None:
|
||||
"""Анимация и переключение состояния раскрытия панели"""
|
||||
|
||||
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
115
kawai_focus/menu_app.py
Normal 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
|
||||
@@ -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 on_enter(self, *args) -> None:
|
||||
"""Загружает список таймеров при входе на экран"""
|
||||
|
||||
self.load_timers()
|
||||
|
||||
def switch_new_timer(self, instance) -> None:
|
||||
"""Метод для переключения на экран Конструктор таймера"""
|
||||
def load_timers(self) -> None:
|
||||
"""Загружает все таймеры и добавляет их в контейнер"""
|
||||
|
||||
self.manager.current = 'timer_constructor_screen'
|
||||
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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
viewclass: "TimerButton"
|
||||
MDIconButton:
|
||||
on_release: app.open_menu(self)
|
||||
pos_hint: {"top": .98}
|
||||
x: "12dp"
|
||||
icon: "menu"
|
||||
|
||||
RecycleBoxLayout:
|
||||
default_size: None, dp(50)
|
||||
default_size_hint: 1, None
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
orientation: "vertical"
|
||||
spacing: dp(5)
|
||||
ScrollView:
|
||||
size_hint_x: .9
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
do_scroll_x: False
|
||||
do_scroll_y: True
|
||||
|
||||
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] # [слева, сверху, справа, снизу]
|
||||
Reference in New Issue
Block a user