import flet as ft # Глобальный масштаб интерфейса. 1.0 = 100%, 1.7 = 170%. # Меняйте только эту переменную (или через theme_manager.apply_scale), # чтобы масштабировать весь UI. SCALE: float = 1.7 def s(v: int | float) -> int: """Применяет SCALE к любому размеру: шрифтам, отступам, ицих.""" return round(v * SCALE) class colors: # Основная палитра в стиле copp74.ru primary = "#F85A40" # Основной оранжево-красный (логотип ЦОПП) primary_dark = "#D94530" # Тёмный для hover/активных состояний primary_light = "#FFEAB7" # Светлый персиковый (вторичный фон) # Фоны background = "#F4F6F8" # Светло-серый фон страницы surface = "#FFFFFF" # Белый для карточек и форм surface_alt = "#F0F2F5" # Альтернативные блоки # Акцент — жёлтый accent = "#FFC845" # Жёлтый акцент accent_lime = "#FFC845" # Алиас для совместимости secondary_light = "#FFEAB7" # Алиас для совместимости secondary_yellow = "#FFC845" # Алиас # Синий — информация, ссылки info = "#007FBD" # Синий info_light = "#D9F1F4" # Светлый голубой tertiary_light = "#D9F1F4" # Алиас для совместимости tertiary_blue = "#007FBD" # Алиас для совместимости secondary_orange = "#F85A40" # Алиас для совместимости # Зелёный — успех success = "#85C446" # Зелёный success_light = "#C0DE9E" # Светло-зелёный # Текст text_primary = "#1E2A3A" # Почти чёрный для заголовков text_secondary = "#5A6779" # Серый для второстепенного текста text_on_primary = "#FFFFFF" # Белый текст на оранжевом фоне # Граница border = "#DDE3EA" # Светло-серая граница class CastomText(ft.Text): def __init__(self, text, size=14, color=colors.text_primary, weight=ft.FontWeight.NORMAL): super().__init__( value=text, color=color, size=s(size), weight=weight, max_lines=99, ) class CastomTextField_input(ft.TextField): def __init__(self, on_change=None, on_submit=None, label="Ваше имя", hint_text="Введите текст...", prefix_icon=None, suffix_icon=None, **kwargs): super().__init__( label=label, hint_text=hint_text, filled=True, bgcolor=colors.surface, border_color=colors.border, focused_border_color=colors.primary, border_radius=s(10), label_style=ft.TextStyle( color=colors.text_secondary, size=s(13), weight=ft.FontWeight.W_500, ), hint_style=ft.TextStyle( color=colors.border, size=s(14), italic=True, ), text_style=ft.TextStyle( color=colors.text_primary, size=s(15), ), content_padding=ft.padding.symmetric(horizontal=s(14), vertical=s(14)), prefix_icon=prefix_icon, suffix_icon=suffix_icon, on_change=on_change, on_submit=on_submit, **kwargs, ) class CastomButton(ft.Button): def __init__(self, text, on_click): super().__init__( content=ft.Text( text, color=colors.text_on_primary, size=s(14), weight=ft.FontWeight.W_600, ) if isinstance(text, str) else text, style=ft.ButtonStyle( color=colors.text_on_primary, bgcolor={ ft.ControlState.DEFAULT: colors.primary, ft.ControlState.HOVERED: colors.primary_dark, }, shape=ft.RoundedRectangleBorder(radius=s(10)), padding=ft.padding.symmetric(horizontal=s(20), vertical=s(12)), ), on_click=on_click ) class CastomIconButton(ft.Button): """Кнопка с иконкой и текстом.""" def __init__(self, text, icon, on_click): super().__init__( content=ft.Row( spacing=s(8), tight=True, controls=[ ft.Icon(icon, color=colors.text_on_primary, size=s(18)), ft.Text(text, color=colors.text_on_primary, size=s(14), weight=ft.FontWeight.W_600), ], ), style=ft.ButtonStyle( bgcolor={ ft.ControlState.DEFAULT: colors.info, ft.ControlState.HOVERED: "#006AA3", }, shape=ft.RoundedRectangleBorder(radius=s(10)), padding=ft.padding.symmetric(horizontal=s(18), vertical=s(12)), ), on_click=on_click, ) class CastomDropdown(ft.Dropdown): def __init__(self, label="", hint_text="", options=None, on_change=None): super().__init__( label=label, hint_text=hint_text, options=options or [], filled=True, fill_color=colors.surface, color=colors.text_primary, border_color=colors.border, border_radius=s(10), focused_border_color=colors.primary, label_style=ft.TextStyle( color=colors.text_secondary, size=s(13), weight=ft.FontWeight.W_500, ), hint_style=ft.TextStyle( color=colors.border, size=s(14), italic=True, ), text_style=ft.TextStyle( color=colors.text_primary, size=s(15), ), menu_style=ft.MenuStyle( bgcolor=colors.surface, ), ) if on_change is not None: self.on_select = on_change class CastomSwitch(ft.Switch): def __init__(self, label, on_change): super().__init__( label=label, label_text_style=ft.TextStyle(size=s(13), color=colors.text_primary), active_color=colors.primary, active_track_color=colors.primary_light, inactive_thumb_color=colors.border, inactive_track_color=colors.surface_alt, on_change=on_change ) class AlterDiaalogApproval(ft.AlertDialog): def __init__(self, on_accept=None): self._on_accept = on_accept self.switch_approval = CastomSwitch( label="", on_change=self.switch_changed ) self.button_approval = CastomButton( text="Принять", on_click=self.accept ) self.button_approval.disabled = True super().__init__( bgcolor=colors.surface, title=ft.Text( "Пользовательское соглашение", color=colors.primary, size=s(16), weight=ft.FontWeight.BOLD, ), content=ft.Container( height=s(400), content=ft.Column( scroll=ft.ScrollMode.AUTO, expand=True, controls=[ ft.Markdown( """ # ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ ## 1. ОБЩИЕ ПОЛОЖЕНИЯ Настоящее Пользовательское соглашение (далее — «Соглашение») регулирует отношения между администрацией сайта https://copp74.ru (далее — «Сайт», «Мы», «Администрация») и пользователем (далее — «Пользователь», «Вы»). Используя Сайт, Вы автоматически соглашаетесь со всеми условиями настоящего Соглашения. Если Вы не согласны с этими условиями, пожалуйста, не используйте Сайт. ## 2. ОПИСАНИЕ САЙТА Сайт https://copp74.ru представляет собой онлайн-платформу для прохождения тестов и проверки знаний. Основная функция Сайта — предоставление Пользователям возможности проходить различные тесты и получать результаты. ## 3. РЕГИСТРАЦИЯ И ЛИЧНЫЕ ДАННЫЕ ### 3.1 Регистрация Для использования Сайта Пользователь должен зарегистрироваться и указать следующую информацию: - Фамилию - Имя - Учебное заведение (образовательную организацию) ### 3.2 Назначение личных данных Указанные фамилия, имя и учебное заведение используются исключительно для: - Идентификации Пользователя в системе - Отображения результатов тестирования - Ведения статистики прохождения тестов - Организации пользователей по учебным заведениям для аналитики - Внутреннего анализа и улучшения качества тестирования ### 3.3 Защита личных данных **Мы гарантируем, что Ваши персональные данные (фамилия, имя и информация об учебном заведении):** - Не будут переданы третьим лицам или организациям без Вашего согласия - Не будут использованы в коммерческих целях - Не будут распространяться без Вашего согласия - Хранятся в защищенной базе данных Данные будут удалены в соответствии с законодательством Российской Федерации по защите персональных данных при закрытии аккаунта или по запросу Пользователя. ## 4. ПРАВА И ОБЯЗАННОСТИ ПОЛЬЗОВАТЕЛЯ ### 4.1 Права Пользователя Пользователь имеет право: - Проходить тесты, размещенные на Сайте - Получать результаты своего тестирования - Запросить удаление своего аккаунта и данных - Обратиться в поддержку по вопросам использования Сайта - Получить информацию о том, как его данные обрабатываются ### 4.2 Обязанности Пользователя Пользователь обязуется: - Предоставлять достоверную информацию при регистрации - Указывать корректное название учебного заведения - Не использовать Сайт в противоправных целях - Не пытаться получить несанкционированный доступ к системам Сайта - Не воспроизводить, не копировать и не распространять содержимое Сайта без разрешения - Соблюдать все применимые законы Российской Федерации ## 5. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ ### 5.1 Предоставление Сайта «Как есть» Сайт предоставляется в режиме «как есть» без каких-либо явных или подразумеваемых гарантий. Администрация не гарантирует: - Непрерывную работу Сайта - Отсутствие ошибок в тестах или результатах - Соответствие Сайта конкретным целям Пользователя ### 5.2 Ограничение ответственности В максимальной степени, допускаемой законодательством Российской Федерации, Администрация не несет ответственность за: - Убытки, возникшие в результате использования или невозможности использования Сайта - Технические сбои, потерю данных - Ущерб, причиненный прямо или косвенно в связи с использованием Сайта ## 6. ИНТЕЛЛЕКТУАЛЬНАЯ СОБСТВЕННОСТЬ Все содержимое Сайта, включая тесты, вопросы, задания, дизайн, логотипы и тексты, защищено авторским правом и законами об интеллектуальной собственности Российской Федерации. Пользователь не имеет права использовать это содержимое в коммерческих целях без письменного разрешения Администрации. ## 7. ИЗМЕНЕНИЕ СОГЛАШЕНИЯ Администрация оставляет за собой право изменять условия настоящего Соглашения в любое время. Изменения вступают в силе с момента их публикации на Сайте. Продолжение использования Сайта после публикации изменений означает согласие Пользователя с новыми условиями. ## 8. ПРЕКРАЩЕНИЕ ДОСТУПА Администрация может заблокировать доступ Пользователя к Сайту без предварительного уведомления, если: - Пользователь нарушает условия настоящего Соглашения - Пользователь использует Сайт в противоправных целях - Пользователь предоставил поддельную информацию при регистрации ## 9. КОНФИДЕНЦИАЛЬНОСТЬ Пожалуйста, ознакомьтесь с нашей Политикой конфиденциальности, которая описывает, как мы обращаемся с Вашими личными данными и какие меры безопасности мы применяем. ## 10. ПРИМЕНИМОЕ ПРАВО Настоящее Соглашение регулируется законодательством Российской Федерации. Все споры, возникающие в связи с Соглашением, подлежат разрешению в судах Российской Федерации. ## 11. КОНТАКТНАЯ ИНФОРМАЦИЯ Если у Вас есть вопросы по данному Соглашению или функционированию Сайта https://copp74.ru, свяжитесь с нами через форму обратной связи на Сайте. ## 12. ЗАКЛЮЧИТЕЛЬНЫЕ ПОЛОЖЕНИЯ Если какая-либо часть настоящего Соглашения будет признана недействительной, остальные положения остаются в полной силе. Пользователь подтверждает, что прочитал, понял и согласен со всеми условиями настоящего Соглашения перед использованием Сайта. **Дата последнего обновления:** 19.03.2026 --- *Соглашение соответствует законодательству Российской Федерации, включая Федеральный закон «О защите персональных данных» и Федеральный закон «О защите прав потребителей».* """, expand=True, md_style_sheet=ft.MarkdownStyleSheet( p_text_style=ft.TextStyle(color=colors.text_primary, size=s(12)), h1_text_style=ft.TextStyle(color=colors.primary, size=s(18), weight=ft.FontWeight.BOLD), h2_text_style=ft.TextStyle(color=colors.info, size=s(15), weight=ft.FontWeight.BOLD), h3_text_style=ft.TextStyle(color=colors.text_secondary, size=s(13), weight=ft.FontWeight.BOLD), a_text_style=ft.TextStyle(color=colors.primary), ), ) ] ), ), actions=[ ft.Column( horizontal_alignment=ft.CrossAxisAlignment.CENTER, controls=[ ft.Row( expand=True, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER, controls=[ self.switch_approval, ft.Text( "Я согласен с условиями пользовательского соглашения", size=s(13), color=colors.text_primary, expand=True, no_wrap=False, ), ] ), ft.Row( expand=True, alignment=ft.MainAxisAlignment.CENTER, controls=[ self.button_approval, ] ) ] ) ], actions_alignment=ft.MainAxisAlignment.CENTER, ) def switch_changed(self, e): #self.switch_approval.value = not e.control.value self.button_approval.disabled = not e.control.value self.update() def accept(self, e): self.open = False self.page.update() if self._on_accept: self._on_accept() else: self.page.run_task(self.page.push_route, "/reg")