File size: 10,804 Bytes
9a1712b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
"""
keyboards/inline.py β€” All inline keyboard builders for the bot UI.

Design principles:
- Folders use a 2-column grid layout.
- Every nested menu has Back and Home buttons.
- Pagination is included for large lists (> ITEMS_PER_PAGE).
- Callback data uses a structured format: "action:param1:param2"
"""

from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder

from config import config


def _back_home_row(back_callback: str, home_callback: str = "home") -> list[InlineKeyboardButton]:
    """Returns a standard [πŸ”™ Back] [🏠 Home] button row."""
    return [
        InlineKeyboardButton(text="πŸ”™ Back", callback_data=back_callback),
        InlineKeyboardButton(text="🏠 Home", callback_data=home_callback),
    ]


# ─────────────────────────── MAIN MENUS ───────────────────────────

def main_menu_user() -> InlineKeyboardMarkup:
    """The main menu for regular users."""
    builder = InlineKeyboardBuilder()
    builder.row(InlineKeyboardButton(text="πŸ“š Browse Knowledge Base", callback_data="browse:root:0"))
    builder.row(InlineKeyboardButton(text="ℹ️ About", callback_data="about"))
    return builder.as_markup()


def main_menu_admin(view_as_user: bool = False) -> InlineKeyboardMarkup:
    """
    Admin main menu. Includes a toggle to preview as a regular user.
    When view_as_user=True, management buttons are hidden.
    """
    builder = InlineKeyboardBuilder()
    builder.row(InlineKeyboardButton(text="πŸ“š Browse Knowledge Base", callback_data="browse:root:0"))

    if not view_as_user:
        # Show full admin controls
        builder.row(InlineKeyboardButton(text="πŸ“ Manage Folders", callback_data="manage:folders:0"))
        builder.row(InlineKeyboardButton(text="πŸ“Š Admin Dashboard", callback_data="admin:dashboard"))
        builder.row(InlineKeyboardButton(text="πŸ‘οΈ View as User", callback_data="toggle:user_view"))
    else:
        # Preview mode β€” only show the return button
        builder.row(InlineKeyboardButton(text="πŸ‘οΈ Return to Admin View", callback_data="toggle:admin_view"))

    return builder.as_markup()


def main_menu_owner(view_as_user: bool = False) -> InlineKeyboardMarkup:
    """Owner main menu β€” extends admin menu with owner-only controls."""
    builder = InlineKeyboardBuilder()
    builder.row(InlineKeyboardButton(text="πŸ“š Browse Knowledge Base", callback_data="browse:root:0"))

    if not view_as_user:
        builder.row(InlineKeyboardButton(text="πŸ“ Manage Folders", callback_data="manage:folders:0"))
        builder.row(
            InlineKeyboardButton(text="πŸ“Š Admin Dashboard", callback_data="admin:dashboard"),
            InlineKeyboardButton(text="πŸ‘‘ Owner Dashboard", callback_data="owner:dashboard"),
        )
        builder.row(
            InlineKeyboardButton(text="πŸ‘₯ Manage Admins", callback_data="owner:admins"),
            InlineKeyboardButton(text="πŸ‘οΈ View as User", callback_data="toggle:user_view"),
        )
    else:
        builder.row(InlineKeyboardButton(text="πŸ‘οΈ Return to Admin View", callback_data="toggle:admin_view"))

    return builder.as_markup()


# ─────────────────────────── FOLDER BROWSING ───────────────────────────

def folder_list_keyboard(
    folders: list,
    items: list,
    parent_id: int | None,
    page: int,
    is_admin: bool = False,
    is_owner: bool = False,
) -> InlineKeyboardMarkup:
    """
    Builds a paginated keyboard for browsing folders and items inside a folder.
    Folders appear in a 2-column grid, items appear as single rows below.
    """
    builder = InlineKeyboardBuilder()
    per_page = config.ITEMS_PER_PAGE
    total_content = folders + items  # Combined for pagination
    total_pages = max(1, (len(total_content) + per_page - 1) // per_page)
    page_content = total_content[page * per_page: (page + 1) * per_page]

    # Separate paginated content back into folders and items
    page_folders = [c for c in page_content if isinstance(c, type(folders[0])) if folders] if folders else []
    page_items = [c for c in page_content if hasattr(c, 'content_type')]

    # Folders in 2-column grid
    folder_buttons = [
        InlineKeyboardButton(
            text=f"{f.emoji} {f.name}",
            callback_data=f"browse:folder:{f.id}:0"
        )
        for f in page_folders
    ]
    # Add folder buttons in pairs (2 per row)
    for i in range(0, len(folder_buttons), 2):
        row = folder_buttons[i:i+2]
        builder.row(*row)

    # Items in single rows
    content_type_emoji = {
        "photo": "πŸ–ΌοΈ", "video": "🎬", "document": "πŸ“„",
        "audio": "🎡", "link": "πŸ”—", "text": "πŸ“"
    }
    for item in page_items:
        emoji = content_type_emoji.get(item.content_type, "πŸ“„")
        builder.row(InlineKeyboardButton(
            text=f"{emoji} {item.title}",
            callback_data=f"view:item:{item.id}"
        ))

    # Admin/Owner action buttons (if not in user-view mode)
    if is_admin or is_owner:
        folder_param = parent_id if parent_id else "root"
        builder.row(
            InlineKeyboardButton(text="βž• Add New Item", callback_data=f"add:start:{folder_param}"),
            InlineKeyboardButton(text="✏️ Edit Folder", callback_data=f"edit:folder:{parent_id}" if parent_id else "home"),
        )
        if parent_id:  # Can only delete non-root folders
            builder.row(InlineKeyboardButton(
                text="πŸ—‘οΈ Delete Folder",
                callback_data=f"delete:folder:{parent_id}"
            ))

    # Pagination row
    nav_buttons = []
    if page > 0:
        nav_buttons.append(InlineKeyboardButton(text="⬅️ Prev", callback_data=f"browse:folder:{parent_id or 'root'}:{page-1}"))
    if page < total_pages - 1:
        nav_buttons.append(InlineKeyboardButton(text="➑️ Next", callback_data=f"browse:folder:{parent_id or 'root'}:{page+1}"))
    if nav_buttons:
        builder.row(*nav_buttons)

    # Back and Home navigation
    if parent_id is not None:
        builder.row(*_back_home_row(back_callback="browse:root:0"))
    else:
        builder.row(InlineKeyboardButton(text="🏠 Home", callback_data="home"))

    return builder.as_markup()


def item_view_keyboard(item_id: int, folder_id: int, is_admin: bool = False) -> InlineKeyboardMarkup:
    """Keyboard shown when a user views a specific item."""
    builder = InlineKeyboardBuilder()
    if is_admin:
        builder.row(
            InlineKeyboardButton(text="✏️ Edit", callback_data=f"edit:item:{item_id}"),
            InlineKeyboardButton(text="πŸ—‘οΈ Delete", callback_data=f"delete:item:{item_id}"),
        )
    builder.row(*_back_home_row(back_callback=f"browse:folder:{folder_id}:0"))
    return builder.as_markup()


# ─────────────────────────── ADMIN MANAGEMENT ───────────────────────────

def add_item_type_keyboard(folder_id: int | str) -> InlineKeyboardMarkup:
    """Asks whether to add a Folder or Content item."""
    builder = InlineKeyboardBuilder()
    builder.row(
        InlineKeyboardButton(text="πŸ“ New Folder", callback_data=f"add:folder:{folder_id}"),
        InlineKeyboardButton(text="πŸ“„ New Content", callback_data=f"add:content:{folder_id}"),
    )
    builder.row(InlineKeyboardButton(text="πŸ”™ Cancel", callback_data="home"))
    return builder.as_markup()


def content_type_keyboard(folder_id: int | str) -> InlineKeyboardMarkup:
    """Lets admin choose the type of content to add."""
    builder = InlineKeyboardBuilder()
    builder.row(
        InlineKeyboardButton(text="πŸ–ΌοΈ Photo", callback_data=f"ctype:photo:{folder_id}"),
        InlineKeyboardButton(text="🎬 Video", callback_data=f"ctype:video:{folder_id}"),
    )
    builder.row(
        InlineKeyboardButton(text="πŸ“„ Document", callback_data=f"ctype:document:{folder_id}"),
        InlineKeyboardButton(text="🎡 Audio", callback_data=f"ctype:audio:{folder_id}"),
    )
    builder.row(
        InlineKeyboardButton(text="πŸ”— Link", callback_data=f"ctype:link:{folder_id}"),
        InlineKeyboardButton(text="πŸ“ Text", callback_data=f"ctype:text:{folder_id}"),
    )
    builder.row(InlineKeyboardButton(text="πŸ”™ Cancel", callback_data="home"))
    return builder.as_markup()


def confirm_delete_keyboard(entity_type: str, entity_id: int) -> InlineKeyboardMarkup:
    """Confirmation dialog before deleting a folder or item."""
    builder = InlineKeyboardBuilder()
    builder.row(
        InlineKeyboardButton(
            text="βœ… Yes, Delete",
            callback_data=f"confirm_delete:{entity_type}:{entity_id}"
        ),
        InlineKeyboardButton(text="❌ Cancel", callback_data="home"),
    )
    return builder.as_markup()


def admin_list_keyboard(admins: list, page: int = 0) -> InlineKeyboardMarkup:
    """Lists all admins with a remove button for each."""
    builder = InlineKeyboardBuilder()
    per_page = 5
    total_pages = max(1, (len(admins) + per_page - 1) // per_page)
    page_admins = admins[page * per_page: (page + 1) * per_page]

    for admin in page_admins:
        name = admin.full_name or admin.username or f"ID:{admin.user_id}"
        builder.row(InlineKeyboardButton(
            text=f"πŸ‘€ {name}",
            callback_data=f"owner:admin_info:{admin.user_id}"
        ))

    # Pagination
    nav = []
    if page > 0:
        nav.append(InlineKeyboardButton(text="⬅️", callback_data=f"owner:admins_page:{page-1}"))
    if page < total_pages - 1:
        nav.append(InlineKeyboardButton(text="➑️", callback_data=f"owner:admins_page:{page+1}"))
    if nav:
        builder.row(*nav)

    builder.row(InlineKeyboardButton(text="βž• Add Admin", callback_data="owner:add_admin"))
    builder.row(InlineKeyboardButton(text="🏠 Home", callback_data="home"))
    return builder.as_markup()


def admin_info_keyboard(admin_user_id: int) -> InlineKeyboardMarkup:
    """Shows options for a specific admin."""
    builder = InlineKeyboardBuilder()
    builder.row(InlineKeyboardButton(
        text="πŸ—‘οΈ Remove Admin",
        callback_data=f"owner:remove_admin:{admin_user_id}"
    ))
    builder.row(*_back_home_row(back_callback="owner:admins"))
    return builder.as_markup()


def back_home_keyboard(back_callback: str = "home") -> InlineKeyboardMarkup:
    """Simple back + home keyboard for generic use."""
    builder = InlineKeyboardBuilder()
    builder.row(*_back_home_row(back_callback=back_callback))
    return builder.as_markup()