diff --git a/bot/callbacks/__init__.py b/bot/callbacks/__init__.py index cf87ccf..f6e0108 100644 --- a/bot/callbacks/__init__.py +++ b/bot/callbacks/__init__.py @@ -1,6 +1,8 @@ from aiogram import Router from . import ( full_menu, + on_home, + settings, ) from bot.middlewares import PrivateButtonMiddleware @@ -11,4 +13,6 @@ router.callback_query.middleware(PrivateButtonMiddleware()) router.include_routers( full_menu.router, + on_home.router, + settings.router, ) diff --git a/bot/callbacks/full_menu.py b/bot/callbacks/full_menu.py index 3164086..fcacee9 100644 --- a/bot/callbacks/full_menu.py +++ b/bot/callbacks/full_menu.py @@ -1,13 +1,19 @@ -from aiogram import Router, F +from aiogram import Router, F, Bot from aiogram.types import ( CallbackQuery ) -from .factories.full_menu import FullMenuCallback +from bot.factories.full_menu import FullMenuCallback + +from bot.keyboards.inline.settings import get_settings_kb router = Router() @router.callback_query(FullMenuCallback.filter(F.action == 'settings')) -async def on_close(callback_query: CallbackQuery): - await callback_query.answer('Settings are not available yet') +async def on_settings(callback_query: CallbackQuery, bot: Bot): + await bot.edit_message_text( + inline_message_id=callback_query.inline_message_id, + text='⚙️ Settings', + reply_markup=get_settings_kb() + ) diff --git a/bot/callbacks/on_home.py b/bot/callbacks/on_home.py new file mode 100644 index 0000000..a97ae70 --- /dev/null +++ b/bot/callbacks/on_home.py @@ -0,0 +1,19 @@ +from aiogram import Router, F, Bot +from aiogram.types import ( + CallbackQuery +) + +from bot.factories.full_menu import FullMenuCallback + +from bot.keyboards.inline.full_menu import get_full_menu_kb + +router = Router() + + +@router.callback_query(FullMenuCallback.filter(F.action == 'home')) +async def on_home(callback_query: CallbackQuery, bot: Bot): + await bot.edit_message_text( + inline_message_id=callback_query.inline_message_id, + text='⚙️ Menu', + reply_markup=get_full_menu_kb() + ) diff --git a/bot/callbacks/settings.py b/bot/callbacks/settings.py new file mode 100644 index 0000000..79004ed --- /dev/null +++ b/bot/callbacks/settings.py @@ -0,0 +1,27 @@ +from aiogram import Router, Bot +from aiogram.types import ( + CallbackQuery +) + +from bot.factories.open_setting import OpenSettingCallback + +from bot.keyboards.inline.setting import get_setting_kb +from bot.modules.settings import settings_strings + +router = Router() + + +@router.callback_query(OpenSettingCallback.filter()) +async def on_settings( + callback_query: CallbackQuery, + callback_data: OpenSettingCallback, + bot: Bot +): + await bot.edit_message_text( + inline_message_id=callback_query.inline_message_id, + text=settings_strings[callback_data.s_id].description, + reply_markup=get_setting_kb( + callback_data.s_id, + str(callback_query.from_user.id) + ) + ) diff --git a/bot/callbacks/factories/__init__.py b/bot/factories/__init__.py similarity index 100% rename from bot/callbacks/factories/__init__.py rename to bot/factories/__init__.py diff --git a/bot/callbacks/factories/full_menu.py b/bot/factories/full_menu.py similarity index 78% rename from bot/callbacks/factories/full_menu.py rename to bot/factories/full_menu.py index 6d0569d..ecb577f 100644 --- a/bot/callbacks/factories/full_menu.py +++ b/bot/factories/full_menu.py @@ -3,4 +3,4 @@ from aiogram.filters.callback_data import CallbackData class FullMenuCallback(CallbackData, prefix='full_menu'): - action: Literal['settings'] + action: Literal['home', 'settings'] diff --git a/bot/factories/open_setting.py b/bot/factories/open_setting.py new file mode 100644 index 0000000..0b3f8d6 --- /dev/null +++ b/bot/factories/open_setting.py @@ -0,0 +1,9 @@ +from aiogram.filters.callback_data import CallbackData + + +class OpenSettingCallback(CallbackData, prefix='setting'): + s_id: str + + +class SettingChoiceCallback(CallbackData, prefix='s_choice'): + choice: str diff --git a/bot/keyboards/inline/full_menu.py b/bot/keyboards/inline/full_menu.py index e6d606f..6e1a798 100644 --- a/bot/keyboards/inline/full_menu.py +++ b/bot/keyboards/inline/full_menu.py @@ -1,6 +1,6 @@ from aiogram.utils.keyboard import (InlineKeyboardMarkup, InlineKeyboardButton, InlineKeyboardBuilder) -from bot.callbacks.factories.full_menu import FullMenuCallback +from bot.factories.full_menu import FullMenuCallback def get_full_menu_kb() -> InlineKeyboardMarkup: diff --git a/bot/keyboards/inline/setting.py b/bot/keyboards/inline/setting.py new file mode 100644 index 0000000..bf57b54 --- /dev/null +++ b/bot/keyboards/inline/setting.py @@ -0,0 +1,31 @@ +from aiogram.utils.keyboard import (InlineKeyboardMarkup, InlineKeyboardButton, + InlineKeyboardBuilder) +from bot.factories.open_setting import SettingChoiceCallback +from bot.factories.full_menu import FullMenuCallback + +from bot.modules.settings import UserSettings + + +def get_setting_kb(s_id: str, user_id: str) -> InlineKeyboardMarkup: + setting = UserSettings(user_id)[s_id] + buttons = [ + [ + InlineKeyboardButton( + text=( + '✅ ' if setting.value == choice else '' + ) + setting.choices[choice], + callback_data=SettingChoiceCallback( + choice=choice, + ).pack() + ) + ] for choice in setting.choices.keys() + ] + [[ + InlineKeyboardButton( + text='🔙', + callback_data=FullMenuCallback( + action='settings' + ).pack() + ) + ]] + + return InlineKeyboardBuilder(buttons).as_markup() diff --git a/bot/keyboards/inline/settings.py b/bot/keyboards/inline/settings.py new file mode 100644 index 0000000..d643984 --- /dev/null +++ b/bot/keyboards/inline/settings.py @@ -0,0 +1,28 @@ +from aiogram.utils.keyboard import (InlineKeyboardMarkup, InlineKeyboardButton, + InlineKeyboardBuilder) +from bot.factories.open_setting import OpenSettingCallback +from bot.factories.full_menu import FullMenuCallback + +from bot.modules.settings import settings_strings + + +def get_settings_kb() -> InlineKeyboardMarkup: + buttons = [ + [ + InlineKeyboardButton( + text=settings_strings[setting_id].name, + callback_data=OpenSettingCallback( + s_id=setting_id, + ).pack() + ) + ] for setting_id in settings_strings.keys() + ] + [[ + InlineKeyboardButton( + text='🔙', + callback_data=FullMenuCallback( + action='home' + ).pack() + ) + ]] + + return InlineKeyboardBuilder(buttons).as_markup() diff --git a/bot/modules/database/db.py b/bot/modules/database/db.py index b7c2dd2..49245be 100644 --- a/bot/modules/database/db.py +++ b/bot/modules/database/db.py @@ -16,6 +16,7 @@ class Db(object): self.config = DBDict('config') self.inline = DBDict('inline') self.errors = DBDict('errors') + self.settings = DBDict('settings') self.spotify = DBDict('spotify') self.deezer = DBDict('deezer') self.youtube = DBDict('youtube') diff --git a/bot/modules/settings/__init__.py b/bot/modules/settings/__init__.py new file mode 100644 index 0000000..7201f5a --- /dev/null +++ b/bot/modules/settings/__init__.py @@ -0,0 +1 @@ +from .model import UserSettings, Setting, settings_strings diff --git a/bot/modules/settings/model.py b/bot/modules/settings/model.py new file mode 100644 index 0000000..aa4c915 --- /dev/null +++ b/bot/modules/settings/model.py @@ -0,0 +1,54 @@ +from dataclasses import dataclass +from ..database import db + + +@dataclass +class Setting: + name: str + description: str + choices: dict[str, str] + value: str | None = None + + +settings_strings: dict[str, Setting] = { + 'search_preview': Setting( + name='Search preview', + description='Show only covers (better display), ' + 'or add 30 seconds of track preview whenever possible?', + choices={ + 'cover': 'Cover picture', + 'preview': 'Audio preview' + }, + ), + 'recode_youtube': Setting( + name='Recode YouTube (and Spotify)', + description='Recode when downloading from YouTube (and Spotify) to ' + 'more compatible format (may take some time)', + choices={ + 'no': 'Send original file', + 'yes': 'Recode to libmp3lame' + }, + ) +} + + +@dataclass +class UserSettings: + user_id: str + + def __post_init__(self): + if db.settings.get(self.user_id) is None: + db.settings[self.user_id] = dict( + (setting, list(settings_strings[setting].choices)[0]) for setting in + settings_strings + ) + + def __getitem__(self, item): + s = settings_strings.get(item) + if s is None: + return None + s.value = db.settings[self.user_id][item] + return s + + def __setitem__(self, key, value): + db.settings[self.user_id][key] = value