diff --git a/assets/fonts/BrandIcons.ttf b/assets/fonts/BrandIcons.ttf index bf40d009..4d4e0f28 100644 Binary files a/assets/fonts/BrandIcons.ttf and b/assets/fonts/BrandIcons.ttf differ diff --git a/assets/fonts/Inter-Bold.ttf b/assets/fonts/Inter-Bold.ttf new file mode 100644 index 00000000..e98b84ce Binary files /dev/null and b/assets/fonts/Inter-Bold.ttf differ diff --git a/assets/fonts/Inter-ExtraBold.ttf b/assets/fonts/Inter-ExtraBold.ttf new file mode 100644 index 00000000..7f16a0f0 Binary files /dev/null and b/assets/fonts/Inter-ExtraBold.ttf differ diff --git a/assets/fonts/Inter-Medium.ttf b/assets/fonts/Inter-Medium.ttf new file mode 100644 index 00000000..721147d8 Binary files /dev/null and b/assets/fonts/Inter-Medium.ttf differ diff --git a/assets/fonts/Inter-Regular.ttf b/assets/fonts/Inter-Regular.ttf new file mode 100644 index 00000000..96fd6a12 Binary files /dev/null and b/assets/fonts/Inter-Regular.ttf differ diff --git a/assets/fonts/Inter-SemiBold.ttf b/assets/fonts/Inter-SemiBold.ttf new file mode 100644 index 00000000..ddb27929 Binary files /dev/null and b/assets/fonts/Inter-SemiBold.ttf differ diff --git a/assets/images/onboarding/logos_line-dark.png b/assets/images/onboarding/logos_line-dark.png index 772aff40..e651ad05 100644 Binary files a/assets/images/onboarding/logos_line-dark.png and b/assets/images/onboarding/logos_line-dark.png differ diff --git a/assets/images/onboarding/logos_line-light.png b/assets/images/onboarding/logos_line-light.png index eb8ecf82..0390a08c 100644 Binary files a/assets/images/onboarding/logos_line-light.png and b/assets/images/onboarding/logos_line-light.png differ diff --git a/assets/images/onboarding/onboarding1-dark.png b/assets/images/onboarding/onboarding1-dark.png index 0244d43b..c5871dd7 100644 Binary files a/assets/images/onboarding/onboarding1-dark.png and b/assets/images/onboarding/onboarding1-dark.png differ diff --git a/assets/images/onboarding/onboarding1-light.png b/assets/images/onboarding/onboarding1-light.png index 50312094..0d361d41 100644 Binary files a/assets/images/onboarding/onboarding1-light.png and b/assets/images/onboarding/onboarding1-light.png differ diff --git a/assets/images/onboarding/onboarding2-dark.png b/assets/images/onboarding/onboarding2-dark.png index e623015a..adfb94ff 100644 Binary files a/assets/images/onboarding/onboarding2-dark.png and b/assets/images/onboarding/onboarding2-dark.png differ diff --git a/assets/images/onboarding/onboarding2-light.png b/assets/images/onboarding/onboarding2-light.png index 5786558c..480a54ad 100644 Binary files a/assets/images/onboarding/onboarding2-light.png and b/assets/images/onboarding/onboarding2-light.png differ diff --git a/assets/markdown/about-en.md b/assets/markdown/about-en.md new file mode 100644 index 00000000..3ee32766 --- /dev/null +++ b/assets/markdown/about-en.md @@ -0,0 +1,12 @@ +### О проекте + +Всё больше организаций хотят владеть нашими данными +А мы сами хотим распоряжаться своими **данными** на своем сервере. + +### Миссия проекта + +Цифровая независимость и приватность доступная каждому + +### Цель + +Развивать программу, которая позволит каждому создавать приватные сервисы для себя и своих близких \ No newline at end of file diff --git a/assets/markdown/about-ru.md b/assets/markdown/about-ru.md new file mode 100644 index 00000000..3ee32766 --- /dev/null +++ b/assets/markdown/about-ru.md @@ -0,0 +1,12 @@ +### О проекте + +Всё больше организаций хотят владеть нашими данными +А мы сами хотим распоряжаться своими **данными** на своем сервере. + +### Миссия проекта + +Цифровая независимость и приватность доступная каждому + +### Цель + +Развивать программу, которая позволит каждому создавать приватные сервисы для себя и своих близких \ No newline at end of file diff --git a/assets/markdown/how_hetzner-en.md b/assets/markdown/how_hetzner-en.md new file mode 100644 index 00000000..47042903 --- /dev/null +++ b/assets/markdown/how_hetzner-en.md @@ -0,0 +1,20 @@ +1. Visit the following [link](https://console.hetzner.cloud/) and sign + into newly created account. +2. Enter into previously created project. If you haven't created one, + then please proceed. +3. Hover side panel with mouse cursor. Panel should expand and show us + a menu. We're interested in the last one — **Security** (icon of a + key). +4. Next, in the upper part of an interface, we can see approximately + the following: **SSH Keys, API Tokens, Certificates, Members.** You + need **API Tokens**. Click on it. +5. In the right part of the interface, there should be **Generate API + token** button. If you're using mobile version og a webpage, in the + lower right corner you'll see **red cross**. Push that button. +6. In the **Description** field, give our token a name (this can be any + name that you like. It doesn't influence the essence. +7. Under the **Description** field we can see a possibility to choose + **permissions**. Pick **Read & Write**. +8. Click **Generate API Token.** +9. After that, our key will be shown. Store it in the reliable place, + or in the password manager, which is better. \ No newline at end of file diff --git a/assets/markdown/how_hetzner-ru.md b/assets/markdown/how_hetzner-ru.md new file mode 100644 index 00000000..4c0c344b --- /dev/null +++ b/assets/markdown/how_hetzner-ru.md @@ -0,0 +1,7 @@ +### Как получить Hetzner API Token +1. Переходим по ссылке https://hetzner.com +2. Заходим в созданный нами проект. Если такового - нет, значит создаём. +3. Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика). +4. Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему. +5. В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку. +6. В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет. \ No newline at end of file diff --git a/assets/translations/en.json b/assets/translations/en.json index 709704c4..254ecc15 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,3 +1,171 @@ { - "test": "en-test" + "test": "en-test", + "locale": "en", + "basis": { + "_comment": "Basic interface elements", + "providers": "Providers", + "services": "Services", + "users": "Users", + "more": "More", + "next": "Next", + "got_it": "Got it", + "settings": "Settings", + "password": "Password", + "create": "Add new", + "confirmation": "Confirmation", + "cancel": "Cancel", + "delete": "Delete", + "close": "Close", + "connect": "Connect", + "domain": "Domain", + "saving": "Saving..", + "nickname": "nickname", + "loading": "loading" + }, + "more": { + "_comment": "'More' tab", + "configuration_wizard": "Setup wizard", + "settings": "Application settings", + "about_project": "About us", + "about_app": "About application", + "onboarding": "Onboarding", + "console": "Console", + "about_app_page": { + "text": "Тут любая служебная информация, v.{}" + } + }, + "onboarding": { + "_comment": "Onboarding pages", + "page1_title": "Digital independence, available to all of us", + "page1_text": "Mail, VPN, Messenger, social network and much more on your private server, under your control.", + "page2_title": "SelfPrivacy — it's not a cloud, but your personal datacenter", + "page2_text": "SelfPrivacy works only with your provider accounts: Hetzner, Cloudflare, Backblaze. If you do not own those, we'll help you to create them" + }, + "providers": { + "_comment": "'Providers' tab", + "page_title": "Your Data Center", + "server": { + "card_title": "Server", + "bottom_sheet": { + "1": "It's a virtual computer, where all your services live.", + "2": "1 CPU, RAM 4Gb, 40Gb — $5 per month", + "3": "Status — Good" + } + }, + "domain": { + "card_title": "Domain", + "bottom_sheet": { + "1": "It's your personal internet address that will point to the server and other services of yours.", + "2": "{} — expires on {}", + "3": "Status — Good" + } + }, + "backup": { + "card_title": "Backup", + "bottom_sheet": { + "1": "Will save your day in case of incident: hackers attack, server deletion, etc.", + "2": "3Gb/10Gb, last backup was yesterday {}", + "3": "Status — Good" + } + } + }, + "not_ready_card": { + "_comment": "Card shown when user skips initial setup", + "1": "Please finish application setup using ", + "2": "@:more.configuration_wizard", + "3": " for further work" + }, + "services": { + "_comment": "Вкладка сервисы", + "title": "Your personal, private and independent services.", + "mail": { + "title": "E-Mail", + "subtitle": "E-Mail for company and family.", + "bottom_sheet": { + "1": "To connect to the mailserver, please use {} domain alongside with username and password, that you created. Also feel free to invite", + "2": "new users" + } + }, + "messenger": { + "title": "Messenger", + "subtitle": "Telegram or Signal not so private as Delta.Chat that uses your private server.", + "bottom_sheet": { + "1": "For connection, please use {} domain and credentials that you created." + } + }, + "password_manager": { + "title": "Password Manager", + "subtitle": "Base of your security. Bitwarden will help you to create, store and move passwords between devices, as well as input them, when requested using autocompletion.", + "bottom_sheet": { + "1": "You can connect to the service and create a user via this link:" + } + }, + "video": { + "title": "Videomeet", + "subtitle": "Zoom and Google Meet are good, but Jitsi Meet is a worth alternative that also gives you confidence that you're not being listened.", + "bottom_sheet": { + "1": "Using Jitsi as simple as just visiting this link:" + } + }, + "cloud": { + "title": "Cloud Storage", + "subtitle": "Do not allow cloud services to read your data by using NextCloud.", + "bottom_sheet": { + "1": "You can connect and create a new user here:" + } + }, + "social_network": { + "title": "Social Network", + "subtitle": "It's hard to believe, but it became possible to create your own social network, with your own rules and target audience.", + "bottom_sheet": { + "1": "You can connect and create new social user here:" + } + }, + "git": { + "title": "Git-server", + "subtitle": "Private alternative to the Github, that belongs to you, but not a Microsoft.", + "bottom_sheet": { + "1": "You can connect and create a new user here:" + } + } + }, + "users": { + "_comment": "'Users' tab", + "add_new_user": "Add a first user", + "new_user": "New user", + "not_ready": "Please connect server, domain and DNS in the Providers tab, to be able to add a first user", + "nobody_here": "Здесь пока никого", + "login": "Login", + "onboarding": "Onboarding", + "console": "Console", + "new_user_info_note": "New user will automatically be granted an access to all of the services", + "delete_confirm_question": "Are you sure?", + "reset_password": "Reset password", + "account": "Account", + "send_regisration_data": "Share login credentials" + }, + "initializing": { + "_comment": "initializing page", + "1": "Connect Hetzner server", + "2": "Here, your data and SelfPrivacy services wiil reside", + "how": "How to obtain API token", + "3": "Connect CloudFlare", + "4": "To manage your domain's DNS", + "5": "CloudFlare API Token", + "6": "Connect Backblaze storage", + "7": "No connected domains at the moment", + "8": "Loading domains list", + "9": "Found more than one domain. For your own security, please be asked to delete unnecessary domains", + "10": "Save domain", + "11": "Create server", + "what": "What does it mean?", + "13": "Server rebooted. Waiting for the last verification...", + "14": "Server started. It will be validated and rebooted now...", + "15": "Server created. DNS checks and server boot in progress...", + "16": "Until the next check: ", + "17": "Check", + "18": "How to obtain Hetzner API Token", + "19": "1 Go via this link ", + "20": "\n" + } } \ No newline at end of file diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 05f81893..d3b19c1b 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -1,3 +1,171 @@ { - "test": "ру-тест" + "test": "ru-test", + "locale": "ru", + "basis": { + "_comment": "базовые элементы интерфейса", + "providers": "Провайдеры", + "services": "Сервисы", + "users": "Пользователи", + "more": "Еще", + "next": "Далее", + "got_it": "Понял", + "settings": "Настройки", + "password": "Пароль", + "create": "Создать", + "confirmation": "Подтверждение", + "cancel": "Отменить", + "delete": "Удалить", + "close": "Закрыть", + "connect": "Подключить", + "domain": "Домен", + "saving": "Сохранение..", + "nickname": "Никнейм", + "loading": "Загрузка" + }, + "more": { + "_comment": "вкладка еще", + "configuration_wizard": "Мастер Подключения", + "settings": "Настройки приложения", + "about_project": "О проекте SelfPrivacy", + "about_app": "О приложении", + "onboarding": "Onboarding", + "console": "Console", + "about_app_page": { + "text": "Тут любая служебная информация, v.{}" + } + }, + "onboarding": { + "_comment": "страницы онбординга", + "page1_title": "Цифровая независимость доступна каждому", + "page1_text": "Почта, VPN, Мессенджер, социальная сеть и многое другое на вашем личном сервере, под вашим полным контролем.", + "page2_title": "SelfPrivacy — это не облако, а ваш личный дата-центр", + "page2_text": "У SelfPrivacy работает только с вашими сервис-провадерами: Hetzner, Cloudflare, Backblaze. Если у вас нет учетных записей, мы поможем их создать." + }, + "providers": { + "_comment": "вкладка провайдеры", + "page_title": "Ваш Дата-центр", + "server": { + "card_title": "Сервер", + "bottom_sheet": { + "1": "Это виртульный компьютер на котором работают все ваши сервисы.", + "2": "1 CPU, RAM 4Gb, 40Gb — $5 в месяц", + "3": "Статус — в норме" + } + }, + "domain": { + "card_title": "Домен", + "bottom_sheet": { + "1": "Это ваш личный адрес в интернете, который будет указывать на сервер и другие ваши сервисы.", + "2": "{} — продлен до {}", + "3": "Статус — в норме" + } + }, + "backup": { + "card_title": "Резервное копирование", + "bottom_sheet": { + "1": "Выручит в любой ситуации: хакерская атака, удаление сервера и т.п.", + "2": "3Gb — бестплатно до 10Gb, последний вчера в {}", + "3": "Статус — в норме" + } + } + }, + "not_ready_card": { + "_comment": "Карточка показывающая когда человек скипнул настройку, на карте текст из 3 блоков, средний содержит ссыку на мастер подключения", + "1": "Завершите настройку приложения используя ", + "2": "@:more.configuration_wizard", + "3": " для продолжения работы" + }, + "services": { + "_comment": "Вкладка сервисы", + "title": "Ваши личные приватные и независимые сервисы", + "mail": { + "title": "Почта", + "subtitle": "Электронная почта для семьи или компании", + "bottom_sheet": { + "1": "Для подключения почтового ящика используйте {} и логин пароль, который вы создали. Так же приглашайте", + "2": "новых пользователей" + } + }, + "messenger": { + "title": "Мессенджер", + "subtitle": "Telegram и Signal не так приватны, как Delta.Chat использующий ваш личный сервер.", + "bottom_sheet": { + "1": "Для подключения используйте {} и логин пароль, который вы создали" + } + }, + "password_manager": { + "title": "Менеджер паролей", + "subtitle": "Фундамент безопасности. Создавать, хранить, копировать пароли между устройствами, вбивать их в формы поможет — Bitwarden.", + "bottom_sheet": { + "1": "Подключиться к серверу и создать пользователя можно по адресу:" + } + }, + "video": { + "title": "Видеоконференция", + "subtitle": "Zoom и Google meet отличные инструменты, но Jitsi meet не хуже и дает уверенность, что вас никто не подслушивает.", + "bottom_sheet": { + "1": "Для использования просто перейдите по ссылке:" + } + }, + "cloud": { + "title": "Файловое облако", + "subtitle": "Не позволяйте облачным сервисам читать ваши данные используйте NextCloud.", + "bottom_sheet": { + "1": "Подключиться к серверу и создать пользователя можно по адресу:" + } + }, + "social_network": { + "title": "Социальная сеть", + "subtitle": "Сложно поверить, но стало возможным создать свою собственную социальную сеть, со своими правилами и аудиторией.", + "bottom_sheet": { + "1": "Подключиться к серверу и создать пользователя можно по адресу:" + } + }, + "git": { + "title": "Git-сервер", + "subtitle": "Приватная альтернатива Github, которая принадлежит вам, а не Microsoft.", + "bottom_sheet": { + "1": "Подключиться к серверу и создать пользователя можно по адресу:" + } + } + }, + "users": { + "_comment": "'Users' tab", + "add_new_user": "Добавьте первого пользователя", + "new_user": "Новый пользователь", + "not_ready": "Подключите сервер, домен и DNS в разделу Провайдеры, чтобы добавить первого пользователя", + "nobody_here": "'Здесь пока никого'", + "login": "Логин", + "onboarding": "Onboarding", + "console": "Console", + "new_user_info_note": "Новый пользователь автоматически получит доступ ко всем сервисам. Ещё какое-то описание.", + "delete_confirm_question": "удалить учетную запись?", + "reset_password": "Сбросить пароль", + "account": "Учетная запись", + "send_regisration_data": "Отправить реквизиты для входа" + }, + "initializing": { + "_comment": "initializing page", + "1": "Подключите сервер Hetzner", + "2": "Здесь будут жить наши данные и SelfPrivacy-сервисы", + "how": "Как получить API Token", + "3": "'Подключите CloudFlare'", + "4": "Для управления DNS вашего домена", + "5": "CloudFlare API Token", + "6": "Подключите облачное хранилище Backblaze", + "7": "На данный момент подлюченных доменов нет", + "8": "Загружаем список доменов", + "9": "Найдено больше одного домена, для вашей безопастности, просим вам удалить не нужные домены", + "10": "Сохранить домен", + "11": "Создать сервер", + "what": "Что это значит?", + "13": "Сервер презагружен, ждем последнюю проверку", + "14": "Cервер запушен, сейчас он будет проверен и перезагружен", + "15": "Cервер создан, идет проверка ДНС адресов и запуск сервера", + "16": "До следующей проверки: ", + "17": "Проверка", + "18": "Как получить Hetzner API Token'", + "19": "1 Переходим по ссылке ", + "20": "\n2 Заходим в созданный нами проект. Если такового - нет, значит создаём.\n3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).\n4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.\n5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.\n6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет." + } } \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 075d04f6..40f32d30 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -39,13 +39,13 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef - wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 + wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/ios/build/XCBuildData/e199fc491e5bb495a66f74a37ab3662f-desc.xcbuild b/ios/build/XCBuildData/96ca1c4c467384d05ed244fd468486cb-desc.xcbuild similarity index 99% rename from ios/build/XCBuildData/e199fc491e5bb495a66f74a37ab3662f-desc.xcbuild rename to ios/build/XCBuildData/96ca1c4c467384d05ed244fd468486cb-desc.xcbuild index f7a6342b..8970bb55 100644 Binary files a/ios/build/XCBuildData/e199fc491e5bb495a66f74a37ab3662f-desc.xcbuild and b/ios/build/XCBuildData/96ca1c4c467384d05ed244fd468486cb-desc.xcbuild differ diff --git a/ios/build/XCBuildData/e199fc491e5bb495a66f74a37ab3662f-manifest.xcbuild b/ios/build/XCBuildData/96ca1c4c467384d05ed244fd468486cb-manifest.xcbuild similarity index 100% rename from ios/build/XCBuildData/e199fc491e5bb495a66f74a37ab3662f-manifest.xcbuild rename to ios/build/XCBuildData/96ca1c4c467384d05ed244fd468486cb-manifest.xcbuild diff --git a/ios/build/XCBuildData/BuildDescriptionCacheIndex-8d11405da631cc0b123a3a1283c8088a b/ios/build/XCBuildData/BuildDescriptionCacheIndex-8d11405da631cc0b123a3a1283c8088a index 4fe175ba..ef6b5410 100644 Binary files a/ios/build/XCBuildData/BuildDescriptionCacheIndex-8d11405da631cc0b123a3a1283c8088a and b/ios/build/XCBuildData/BuildDescriptionCacheIndex-8d11405da631cc0b123a3a1283c8088a differ diff --git a/ios/build/XCBuildData/94e4d8c67912337ee212f892ab2b8faa-desc.xcbuild b/ios/build/XCBuildData/bc25e7b85ed10bc8d71fbc6f28d8094e-desc.xcbuild similarity index 99% rename from ios/build/XCBuildData/94e4d8c67912337ee212f892ab2b8faa-desc.xcbuild rename to ios/build/XCBuildData/bc25e7b85ed10bc8d71fbc6f28d8094e-desc.xcbuild index eb9cc275..6a7bab59 100644 Binary files a/ios/build/XCBuildData/94e4d8c67912337ee212f892ab2b8faa-desc.xcbuild and b/ios/build/XCBuildData/bc25e7b85ed10bc8d71fbc6f28d8094e-desc.xcbuild differ diff --git a/ios/build/XCBuildData/94e4d8c67912337ee212f892ab2b8faa-manifest.xcbuild b/ios/build/XCBuildData/bc25e7b85ed10bc8d71fbc6f28d8094e-manifest.xcbuild similarity index 100% rename from ios/build/XCBuildData/94e4d8c67912337ee212f892ab2b8faa-manifest.xcbuild rename to ios/build/XCBuildData/bc25e7b85ed10bc8d71fbc6f28d8094e-manifest.xcbuild diff --git a/ios/build/XCBuildData/build.db b/ios/build/XCBuildData/build.db index 8ed42a0f..8369c8fd 100644 Binary files a/ios/build/XCBuildData/build.db and b/ios/build/XCBuildData/build.db differ diff --git a/lib/config/bloc_config.dart b/lib/config/bloc_config.dart index 97ca6866..af289892 100644 --- a/lib/config/bloc_config.dart +++ b/lib/config/bloc_config.dart @@ -3,13 +3,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; import 'package:selfprivacy/logic/cubit/users/users_cubit.dart'; class BlocAndProviderConfig extends StatelessWidget { - const BlocAndProviderConfig({Key key, this.child}) : super(key: key); + const BlocAndProviderConfig({Key? key, this.child}) : super(key: key); - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { @@ -30,7 +29,6 @@ class BlocAndProviderConfig extends StatelessWidget { lazy: false, create: (_) => AppConfigCubit()..load(), ), - BlocProvider(create: (_) => ServicesCubit()), BlocProvider(create: (_) => ProvidersCubit()), BlocProvider(create: (_) => UsersCubit()), ], diff --git a/lib/config/bloc_observer.dart b/lib/config/bloc_observer.dart index f19a42af..e54b399b 100644 --- a/lib/config/bloc_observer.dart +++ b/lib/config/bloc_observer.dart @@ -2,14 +2,14 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/ui/components/error/error.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; -import 'get_it_config.dart'; +import './get_it_config.dart'; class SimpleBlocObserver extends BlocObserver { SimpleBlocObserver(); @override - void onError(Cubit cubit, Object error, StackTrace stackTrace) { - final navigator = getIt.get().navigator; + void onError(BlocBase cubit, Object error, StackTrace stackTrace) { + final navigator = getIt.get().navigator!; navigator.push( materialRoute( diff --git a/lib/config/brand_theme.dart b/lib/config/brand_theme.dart index c8fd246e..9f76cc0c 100644 --- a/lib/config/brand_theme.dart +++ b/lib/config/brand_theme.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:selfprivacy/config/text_themes.dart'; import 'brand_colors.dart'; final ligtTheme = ThemeData( primaryColor: BrandColors.primary, + fontFamily: 'Inter', brightness: Brightness.light, scaffoldBackgroundColor: BrandColors.scaffoldBackground, inputDecorationTheme: InputDecorationTheme( @@ -33,21 +33,17 @@ final ligtTheme = ThemeData( color: BrandColors.red1, ), ), - errorStyle: GoogleFonts.inter( - textStyle: TextStyle( - fontSize: 12, - color: BrandColors.red1, - ), + errorStyle: TextStyle( + fontSize: 12, + color: BrandColors.red1, ), ), - textTheme: GoogleFonts.interTextTheme( - TextTheme( - headline1: headline1Style, - headline2: headline2Style, - caption: headline4Style, - bodyText1: body1Style, - subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style - ), + textTheme: TextTheme( + headline1: headline1Style, + headline2: headline2Style, + caption: headline4Style, + bodyText1: body1Style, + subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style ), ); @@ -57,14 +53,12 @@ var darkTheme = ligtTheme.copyWith( iconTheme: IconThemeData(color: BrandColors.gray3), cardColor: BrandColors.gray1, dialogBackgroundColor: Color(0xFF202120), - textTheme: GoogleFonts.interTextTheme( - TextTheme( - headline1: headline1Style.copyWith(color: BrandColors.white), - headline2: headline2Style.copyWith(color: BrandColors.white), - caption: headline4Style.copyWith(color: BrandColors.white), - bodyText1: body1Style.copyWith(color: BrandColors.white), - subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style - ), + textTheme: TextTheme( + headline1: headline1Style.copyWith(color: BrandColors.white), + headline2: headline2Style.copyWith(color: BrandColors.white), + caption: headline4Style.copyWith(color: BrandColors.white), + bodyText1: body1Style.copyWith(color: BrandColors.white), + subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style ), inputDecorationTheme: InputDecorationTheme( labelStyle: TextStyle(color: BrandColors.white), diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index cf050972..17a10fb3 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -32,7 +32,8 @@ class HiveConfig { await secureStorage.write(key: BNames.key, value: base64UrlEncode(key)); } - return base64Url.decode(await secureStorage.read(key: BNames.key)); + String? string = await secureStorage.read(key: BNames.key); + return base64Url.decode(string!); } } diff --git a/lib/config/localization.dart b/lib/config/localization.dart index b8e33be3..abaa2463 100644 --- a/lib/config/localization.dart +++ b/lib/config/localization.dart @@ -3,20 +3,20 @@ import 'package:flutter/material.dart'; class Localization extends StatelessWidget { const Localization({ - Key key, + Key? key, this.child, }) : super(key: key); - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { return EasyLocalization( - preloaderColor: Colors.black, supportedLocales: [Locale('ru'), Locale('en')], path: 'assets/translations', - fallbackLocale: Locale('en'), + fallbackLocale: Locale('ru'), + saveLocale: false, useOnlyLangCode: true, - child: child, + child: child!, ); } } diff --git a/lib/config/md_files.dart b/lib/config/md_files.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/config/text_themes.dart b/lib/config/text_themes.dart index 1c8c0fbf..b64ab1a2 100644 --- a/lib/config/text_themes.dart +++ b/lib/config/text_themes.dart @@ -1,41 +1,38 @@ import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:selfprivacy/utils/named_font_weight.dart'; import 'brand_colors.dart'; -final defaultTextStyle = GoogleFonts.inter( - textStyle: TextStyle( - fontSize: 15, - color: BrandColors.textColor1, - ), +final defaultTextStyle = TextStyle( + fontSize: 15, + color: BrandColors.textColor1, ); -final headline1Style = GoogleFonts.inter( +final headline1Style = defaultTextStyle.copyWith( fontSize: 40, fontWeight: NamedFontWeight.extraBold, color: BrandColors.headlineColor, ); -final headline2Style = GoogleFonts.inter( +final headline2Style = defaultTextStyle.copyWith( fontSize: 24, fontWeight: NamedFontWeight.extraBold, color: BrandColors.headlineColor, ); -final onboardingTitle = GoogleFonts.inter( +final onboardingTitle = defaultTextStyle.copyWith( fontSize: 30, fontWeight: NamedFontWeight.extraBold, color: BrandColors.headlineColor, ); -final headline3Style = GoogleFonts.inter( +final headline3Style = defaultTextStyle.copyWith( fontSize: 20, fontWeight: NamedFontWeight.extraBold, color: BrandColors.headlineColor, ); -final headline4Style = GoogleFonts.inter( +final headline4Style = defaultTextStyle.copyWith( fontSize: 18, fontWeight: NamedFontWeight.medium, color: BrandColors.headlineColor, @@ -59,16 +56,12 @@ final smallStyle = defaultTextStyle.copyWith(fontSize: 11, height: 1.45); final linkStyle = defaultTextStyle.copyWith(color: BrandColors.blue); -final progressTextStyleLight = GoogleFonts.inter( - textStyle: TextStyle( - fontSize: 11, - color: BrandColors.textColor1, - ), +final progressTextStyleLight = TextStyle( + fontSize: 11, + color: BrandColors.textColor1, ); -final progressTextStyleDark = GoogleFonts.inter( - textStyle: TextStyle( - fontSize: 11, - color: BrandColors.white, - ), +final progressTextStyleDark = TextStyle( + fontSize: 11, + color: BrandColors.white, ); diff --git a/lib/logic/api_maps/api_map.dart b/lib/logic/api_maps/api_map.dart index a7c8949f..505ec178 100644 --- a/lib/logic/api_maps/api_map.dart +++ b/lib/logic/api_maps/api_map.dart @@ -18,9 +18,9 @@ abstract class ApiMap { }; loggedClient = client; } - String rootAddress; + String? rootAddress; - Dio loggedClient; + late Dio loggedClient; void close() { loggedClient.close(); @@ -33,37 +33,46 @@ class ConsoleInterceptor extends InterceptorsWrapper { } @override - Future onRequest(RequestOptions options) async { + Future onRequest( + RequestOptions options, + RequestInterceptorHandler requestInterceptorHandler, + ) async { addMessage( Message( text: 'request-uri: ${options.uri}\nheaders: ${options.headers}\ndata: ${options.data}', ), ); - return super.onRequest(options); + return super.onRequest(options, requestInterceptorHandler); } @override - Future onResponse(Response response) async { + Future onResponse( + Response response, + ResponseInterceptorHandler requestInterceptorHandler, + ) async { addMessage( Message( text: - 'response-uri: ${response.request.uri}\ncode: ${response.statusCode}\ndata: ${response.toString()}\n', + 'response-uri: ${response.realUri}\ncode: ${response.statusCode}\ndata: ${response.toString()}\n', ), ); - return super.onResponse(response); + return super.onResponse( + response, + requestInterceptorHandler, + ); } @override - Future onError(DioError err) async { + Future onError(DioError err, ErrorInterceptorHandler handler) async { var response = err.response; log(err.toString()); addMessage( Message.warn( text: - 'response-uri: ${response?.request?.uri}\ncode: ${response?.statusCode}\ndata: ${response?.toString()}\n', + 'response-uri: ${response?.realUri}\ncode: ${response?.statusCode}\ndata: ${response?.toString()}\n', ), ); - return super.onError(err); + return super.onError(err, handler); } } diff --git a/lib/logic/api_maps/backblaze.dart b/lib/logic/api_maps/backblaze.dart index 35782fc7..5bf84863 100644 --- a/lib/logic/api_maps/backblaze.dart +++ b/lib/logic/api_maps/backblaze.dart @@ -3,17 +3,17 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/logic/api_maps/api_map.dart'; class BackblazeApi extends ApiMap { - BackblazeApi([String token]) { + BackblazeApi([String? token]) { if (token != null) { loggedClient.options = BaseOptions( headers: {'Authorization': 'Basic $token'}, - baseUrl: rootAddress, + baseUrl: rootAddress!, ); } } @override - String rootAddress = + String? rootAddress = 'https://api.backblazeb2.com/b2api/v2/b2_authorize_account'; Future isValid(String token) async { @@ -24,7 +24,7 @@ class BackblazeApi extends ApiMap { }, ); - Response response = await loggedClient.get(rootAddress, options: options); + Response response = await loggedClient.get(rootAddress!, options: options); if (response.statusCode == HttpStatus.ok) { return true; diff --git a/lib/logic/api_maps/cloudflare.dart b/lib/logic/api_maps/cloudflare.dart index cb69cdc3..b78b8ee6 100644 --- a/lib/logic/api_maps/cloudflare.dart +++ b/lib/logic/api_maps/cloudflare.dart @@ -5,7 +5,7 @@ import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; import 'package:selfprivacy/logic/models/dns_records.dart'; class CloudflareApi extends ApiMap { - CloudflareApi([String token]) { + CloudflareApi([String? token]) { if (token != null) { loggedClient.options = BaseOptions(headers: {'Authorization': 'Bearer $token'}); @@ -13,7 +13,7 @@ class CloudflareApi extends ApiMap { } @override - String rootAddress = 'https://api.cloudflare.com/client/v4'; + String? rootAddress = 'https://api.cloudflare.com/client/v4'; Future isValid(String token) async { var url = '$rootAddress/user/tokens/verify'; @@ -35,7 +35,7 @@ class CloudflareApi extends ApiMap { } } - Future getZoneId(String token, String domain) async { + Future getZoneId(String? token, String domain) async { var url = '$rootAddress/zones'; var options = Options( @@ -59,8 +59,8 @@ class CloudflareApi extends ApiMap { } Future removeSimilarRecords({ - String ip4, - CloudFlareDomain cloudFlareDomain, + String? ip4, + required CloudFlareDomain cloudFlareDomain, }) async { var domainName = cloudFlareDomain.domainName; var domainZoneId = cloudFlareDomain.zoneId; @@ -82,8 +82,8 @@ class CloudflareApi extends ApiMap { } Future createMultipleDnsRecords({ - String ip4, - CloudFlareDomain cloudFlareDomain, + String? ip4, + required CloudFlareDomain cloudFlareDomain, }) async { var domainName = cloudFlareDomain.domainName; var domainZoneId = cloudFlareDomain.zoneId; @@ -120,7 +120,7 @@ class CloudflareApi extends ApiMap { // ); // } - List projectDnsRecords(String domainName, String ip4) { + List projectDnsRecords(String? domainName, String? ip4) { var domainA = DnsRecords(type: 'A', name: domainName, content: ip4); var mx = DnsRecords(type: 'MX', name: '@', content: domainName); @@ -161,7 +161,7 @@ class CloudflareApi extends ApiMap { ]; } - Future> domainList() async { + Future?> domainList() async { var url = '$rootAddress/zones?per_page=50'; var response = await loggedClient.get( url, @@ -169,7 +169,7 @@ class CloudflareApi extends ApiMap { ); return response.data['result'] - .map((el) => el['name'] as String) + .map((el) => el['name'] as String?) .toList(); } } diff --git a/lib/logic/api_maps/hetzner.dart b/lib/logic/api_maps/hetzner.dart index ebff314c..8459d315 100644 --- a/lib/logic/api_maps/hetzner.dart +++ b/lib/logic/api_maps/hetzner.dart @@ -2,24 +2,23 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; import 'package:selfprivacy/logic/api_maps/api_map.dart'; import 'package:selfprivacy/logic/models/server_details.dart'; import 'package:selfprivacy/logic/models/user.dart'; import 'package:selfprivacy/utils/password_generator2.dart'; class HetznerApi extends ApiMap { - HetznerApi([String token]) { + HetznerApi([String? token]) { if (token != null) { loggedClient.options = BaseOptions( headers: {'Authorization': 'Bearer $token'}, - baseUrl: rootAddress, + baseUrl: rootAddress!, ); } } @override - String rootAddress = 'https://api.hetzner.cloud/v1/servers'; + String? rootAddress = 'https://api.hetzner.cloud/v1/servers'; Future isValid(String token) async { var options = Options( @@ -29,7 +28,7 @@ class HetznerApi extends ApiMap { }, ); - Response response = await loggedClient.get(rootAddress, options: options); + Response response = await loggedClient.get(rootAddress!, options: options); if (response.statusCode == HttpStatus.ok) { return true; @@ -41,9 +40,9 @@ class HetznerApi extends ApiMap { } Future createServer({ - @required String cloudFlareKey, - @required User rootUser, - @required String domainName, + required String? cloudFlareKey, + required User rootUser, + required String? domainName, }) async { var dbPassword = getRandomString(40); @@ -52,7 +51,7 @@ class HetznerApi extends ApiMap { ); Response response = await loggedClient.post( - rootAddress, + rootAddress!, data: data, ); @@ -64,17 +63,17 @@ class HetznerApi extends ApiMap { } Future deleteSelfprivacyServer({ - @required String cloudFlareKey, + required String? cloudFlareKey, }) async { - Response response = await loggedClient.get(rootAddress); + Response response = await loggedClient.get(rootAddress!); List list = response.data['servers']; var server = list.firstWhere((el) => el['name'] == 'selfprivacy-server'); - return await loggedClient.delete('$rootAddress/${server['id']}'); + await loggedClient.delete('$rootAddress/${server['id']}'); } Future startServer({ - HetznerServerDetails server, + required HetznerServerDetails server, }) async { await loggedClient.post('/${server.id}/actions/poweron'); @@ -84,7 +83,7 @@ class HetznerApi extends ApiMap { } Future restart({ - HetznerServerDetails server, + required HetznerServerDetails server, }) async { await loggedClient.post('/${server.id}/actions/poweron'); diff --git a/lib/logic/api_maps/server.dart b/lib/logic/api_maps/server.dart index c5db1576..5f5abda4 100644 --- a/lib/logic/api_maps/server.dart +++ b/lib/logic/api_maps/server.dart @@ -5,7 +5,7 @@ import 'package:dio/dio.dart'; import 'api_map.dart'; class ServerApi extends ApiMap { - ServerApi(String domainName) { + ServerApi(String? domainName) { loggedClient.options = BaseOptions( baseUrl: 'https://api.$domainName', ); diff --git a/lib/logic/cubit/app_config/app_config_cubit.dart b/lib/logic/cubit/app_config/app_config_cubit.dart index bc42f4e0..4d8dd8a5 100644 --- a/lib/logic/cubit/app_config/app_config_cubit.dart +++ b/lib/logic/cubit/app_config/app_config_cubit.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:flutter/foundation.dart'; import 'package:selfprivacy/logic/models/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; @@ -10,6 +9,7 @@ import 'package:selfprivacy/logic/models/server_details.dart'; import 'package:selfprivacy/logic/models/user.dart'; import 'app_config_repository.dart'; +export 'package:provider/provider.dart'; part 'app_config_state.dart'; @@ -64,23 +64,23 @@ class AppConfigCubit extends Cubit { } void startServerIfDnsIsOkay({ - AppConfigState state, + AppConfigState? state, bool isImmediate = false, }) async { state = state ?? this.state; final work = () async { - emit(TimerState(dataState: state, isLoading: true)); + emit(TimerState(dataState: state!, isLoading: true)); - var ip4 = state.hetznerServer.ip4; - var domainName = state.cloudFlareDomain.domainName; + var ip4 = state.hetznerServer!.ip4; + var domainName = state.cloudFlareDomain!.domainName; var isMatch = await repository.isDnsAddressesMatch(domainName, ip4); if (isMatch) { var server = await repository.startServer( state.hetznerKey, - state.hetznerServer, + state.hetznerServer!, ); repository.saveServerDetails(server); emit( @@ -111,16 +111,16 @@ class AppConfigCubit extends Cubit { } void resetServerIfServerIsOkay({ - AppConfigState state, + AppConfigState? state, bool isImmediate = false, }) async { state = state ?? this.state; var work = () async { - emit(TimerState(dataState: state, isLoading: true)); + emit(TimerState(dataState: state!, isLoading: true)); var isServerWorking = await repository.isHttpServerWorking( - state.cloudFlareDomain.domainName, + state.cloudFlareDomain!.domainName, ); if (isServerWorking) { @@ -133,8 +133,8 @@ class AppConfigCubit extends Cubit { )); timer = Timer(pauseDuration, () async { var hetznerServerDetails = await repository.restart( - state.hetznerKey, - state.hetznerServer, + state!.hetznerKey, + state.hetznerServer!, ); emit( state.copyWith( @@ -165,19 +165,19 @@ class AppConfigCubit extends Cubit { } } - Timer timer; + Timer? timer; void finishCheckIfServerIsOkay({ - AppConfigState state, + AppConfigState? state, bool isImmediate = false, }) async { state = state ?? this.state; var work = () async { - emit(TimerState(dataState: state, isLoading: true)); + emit(TimerState(dataState: state!, isLoading: true)); var isServerWorking = await repository.isHttpServerWorking( - state.cloudFlareDomain.domainName, + state.cloudFlareDomain!.domainName, ); if (isServerWorking) { @@ -238,12 +238,12 @@ class AppConfigCubit extends Cubit { } void createServerAndSetDnsRecords() async { - var _stateCopy = state; + AppConfigState _stateCopy = state; var onSuccess = (serverDetails) async { await repository.createDnsRecords( state.cloudFlareKey, serverDetails.ip4, - state.cloudFlareDomain, + state.cloudFlareDomain!, ); emit(state.copyWith( @@ -259,8 +259,8 @@ class AppConfigCubit extends Cubit { emit(state.copyWith(isLoading: true)); await repository.createServer( state.hetznerKey, - state.rootUser, - state.cloudFlareDomain.domainName, + state.rootUser!, + state.cloudFlareDomain!.domainName, state.cloudFlareKey, onCancel: onCancel, onSuccess: onSuccess, @@ -277,54 +277,8 @@ class AppConfigCubit extends Cubit { } void _closeTimer() { - if (timer != null && timer.isActive) { - timer.cancel(); + if (timer != null && timer!.isActive) { + timer!.cancel(); } } } - -// void checkDnsAndStartServer() async { -// var ip4 = state.hetznerServer.ip4; -// var domainName = state.cloudFlareDomain.domainName; - -// var isMatch = await repository.isDnsAddressesMatch(domainName, ip4); - -// if (isMatch) { -// var server = await repository.startServer( -// state.hetznerKey, -// state.hetznerServer, -// ); -// repository.saveServerDetails(server); -// emit( -// state.copyWith( -// hasFinalChecked: true, -// isServerStarted: true, -// isLoading: false, -// hetznerServer: server, -// ), -// ); -// } else { -// emit(state.copyWith(lastDnsCheckTime: DateTime.now())); -// } -// } - -// void serverReset() async { -// var callBack = () async { -// var isServerWorking = await repository.isHttpServerWorking( -// state.cloudFlareDomain.domainName, -// ); -// if (!isServerWorking) { -// var last = DateTime.now(); -// // emit(state.copyWith(lastServerStatusCheckTime: last)); -// return; -// } - -// var hetznerServerDetails = await repository.restart( -// state.hetznerKey, -// state.hetznerServer, -// ); -// emit(state.copyWith(hetznerServer: hetznerServerDetails)); -// }; - -// _tryOrAddError(state, callBack); -// } diff --git a/lib/logic/cubit/app_config/app_config_repository.dart b/lib/logic/cubit/app_config/app_config_repository.dart index 23709097..1a9f9d2b 100644 --- a/lib/logic/cubit/app_config/app_config_repository.dart +++ b/lib/logic/cubit/app_config/app_config_repository.dart @@ -60,7 +60,7 @@ class AppConfigRepository { } Future startServer( - String hetznerKey, + String? hetznerKey, HetznerServerDetails hetznerServer, ) async { var hetznerApi = HetznerApi(hetznerKey); @@ -75,7 +75,7 @@ class AppConfigRepository { await box.put(BNames.hetznerServer, serverDetails); } - Future isDnsAddressesMatch(String domainName, String ip4) async { + Future isDnsAddressesMatch(String? domainName, String? ip4) async { print(domainName); var addresses = [ '$domainName', @@ -116,12 +116,12 @@ class AppConfigRepository { } Future createServer( - String hetznerKey, + String? hetznerKey, User rootUser, - String domainName, - String cloudFlareKey, { - void Function() onCancel, - Future Function(HetznerServerDetails serverDetails) onSuccess, + String? domainName, + String? cloudFlareKey, { + void Function()? onCancel, + required Future Function(HetznerServerDetails serverDetails) onSuccess, }) async { var hetznerApi = HetznerApi(hetznerKey); @@ -135,7 +135,7 @@ class AppConfigRepository { hetznerApi.close(); onSuccess(serverDetails); } on DioError catch (e) { - if (e.response.data['error']['code'] == 'uniqueness_error') { + if (e.response!.data['error']['code'] == 'uniqueness_error') { var nav = getIt.get(); nav.showPopUpDialog( BrandAlert( @@ -165,7 +165,7 @@ class AppConfigRepository { text: 'Отменить', onPressed: () { hetznerApi.close(); - onCancel(); + onCancel!(); }, ), ], @@ -176,8 +176,8 @@ class AppConfigRepository { } Future createDnsRecords( - String cloudFlareKey, - String ip4, + String? cloudFlareKey, + String? ip4, CloudFlareDomain cloudFlareDomain, ) async { var cloudflareApi = CloudflareApi(cloudFlareKey); @@ -195,7 +195,7 @@ class AppConfigRepository { cloudflareApi.close(); } - Future isHttpServerWorking(String domainName) async { + Future isHttpServerWorking(String? domainName) async { var api = ServerApi(domainName); var isHttpServerWorking = await api.isHttpServerWorking(); api.close(); @@ -203,7 +203,7 @@ class AppConfigRepository { } Future restart( - String hetznerKey, + String? hetznerKey, HetznerServerDetails server, ) async { var hetznerApi = HetznerApi(hetznerKey); diff --git a/lib/logic/cubit/app_config/app_config_state.dart b/lib/logic/cubit/app_config/app_config_state.dart index caedcc2c..d49c3382 100644 --- a/lib/logic/cubit/app_config/app_config_state.dart +++ b/lib/logic/cubit/app_config/app_config_state.dart @@ -2,21 +2,21 @@ part of 'app_config_cubit.dart'; class AppConfigState extends Equatable { const AppConfigState({ - @required this.hetznerKey, - @required this.cloudFlareKey, - @required this.backblazeCredential, - @required this.cloudFlareDomain, - @required this.rootUser, - @required this.hetznerServer, - @required this.isServerStarted, - @required this.isServerReseted, - @required this.hasFinalChecked, - @required this.isLoading, - @required this.error, + required this.hetznerKey, + required this.cloudFlareKey, + required this.backblazeCredential, + required this.cloudFlareDomain, + required this.rootUser, + required this.hetznerServer, + required this.isServerStarted, + required this.isServerReseted, + required this.hasFinalChecked, + required this.isLoading, + required this.error, }); @override - List get props => [ + List get props => [ hetznerKey, cloudFlareKey, backblazeCredential, @@ -30,31 +30,31 @@ class AppConfigState extends Equatable { error, ]; - final String hetznerKey; - final String cloudFlareKey; - final BackblazeCredential backblazeCredential; - final CloudFlareDomain cloudFlareDomain; - final User rootUser; - final HetznerServerDetails hetznerServer; - final bool isServerStarted; - final bool isServerReseted; - final bool hasFinalChecked; + final String? hetznerKey; + final String? cloudFlareKey; + final BackblazeCredential? backblazeCredential; + final CloudFlareDomain? cloudFlareDomain; + final User? rootUser; + final HetznerServerDetails? hetznerServer; + final bool? isServerStarted; + final bool? isServerReseted; + final bool? hasFinalChecked; - final bool isLoading; - final Exception error; + final bool? isLoading; + final Exception? error; AppConfigState copyWith({ - String hetznerKey, - String cloudFlareKey, - BackblazeCredential backblazeCredential, - CloudFlareDomain cloudFlareDomain, - User rootUser, - HetznerServerDetails hetznerServer, - bool isServerStarted, - bool isServerReseted, - bool hasFinalChecked, - bool isLoading, - Exception error, + String? hetznerKey, + String? cloudFlareKey, + BackblazeCredential? backblazeCredential, + CloudFlareDomain? cloudFlareDomain, + User? rootUser, + HetznerServerDetails? hetznerServer, + bool? isServerStarted, + bool? isServerReseted, + bool? hasFinalChecked, + bool? isLoading, + Exception? error, }) => AppConfigState( hetznerKey: hetznerKey ?? this.hetznerKey, @@ -77,10 +77,10 @@ class AppConfigState extends Equatable { bool get isUserFilled => rootUser != null; bool get isServerCreated => hetznerServer != null; - bool get isFullyInitilized => _fulfilementList.every((el) => el); - int get progress => _fulfilementList.where((el) => el).length; + bool get isFullyInitilized => _fulfilementList.every((el) => el!); + int get progress => _fulfilementList.where((el) => el!).length; - List get _fulfilementList => [ + List get _fulfilementList => [ isHetznerFilled, isCloudFlareFilled, isBackblazeFilled, @@ -112,10 +112,10 @@ class InitialAppConfigState extends AppConfigState { class TimerState extends AppConfigState { TimerState({ - @required this.dataState, + required this.dataState, this.timerStart, this.duration, - @required bool isLoading, + required bool isLoading, }) : super( hetznerKey: dataState.hetznerKey, cloudFlareKey: dataState.cloudFlareKey, @@ -131,11 +131,11 @@ class TimerState extends AppConfigState { ); final AppConfigState dataState; - final DateTime timerStart; - final Duration duration; + final DateTime? timerStart; + final Duration? duration; @override - List get props => [ + List get props => [ dataState, timerStart, duration, diff --git a/lib/logic/cubit/app_settings/app_settings_cubit.dart b/lib/logic/cubit/app_settings/app_settings_cubit.dart index 93f79fe1..5dcf348e 100644 --- a/lib/logic/cubit/app_settings/app_settings_cubit.dart +++ b/lib/logic/cubit/app_settings/app_settings_cubit.dart @@ -1,6 +1,5 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:flutter/widgets.dart'; import 'package:hive/hive.dart'; import 'package:selfprivacy/config/hive_config.dart'; export 'package:provider/provider.dart'; @@ -9,8 +8,8 @@ part 'app_settings_state.dart'; class AppSettingsCubit extends Cubit { AppSettingsCubit({ - @required bool isDarkModeOn, - @required bool isOnbordingShowing, + required bool isDarkModeOn, + required bool isOnbordingShowing, }) : super( AppSettingsState( isDarkModeOn: isDarkModeOn, @@ -21,15 +20,15 @@ class AppSettingsCubit extends Cubit { Box box = Hive.box(BNames.appSettings); void load() { - bool isDarkModeOn = box.get(BNames.isDarkModeOn); - bool isOnbordingShowing = box.get(BNames.isOnbordingShowing); + bool? isDarkModeOn = box.get(BNames.isDarkModeOn); + bool? isOnbordingShowing = box.get(BNames.isOnbordingShowing); emit(state.copyWith( isDarkModeOn: isDarkModeOn, isOnbordingShowing: isOnbordingShowing, )); } - void updateDarkMode({@required bool isDarkModeOn}) { + void updateDarkMode({required bool isDarkModeOn}) { box.put(BNames.isDarkModeOn, isDarkModeOn); emit(state.copyWith(isDarkModeOn: isDarkModeOn)); } diff --git a/lib/logic/cubit/app_settings/app_settings_state.dart b/lib/logic/cubit/app_settings/app_settings_state.dart index 023ad2d0..e1dae427 100644 --- a/lib/logic/cubit/app_settings/app_settings_state.dart +++ b/lib/logic/cubit/app_settings/app_settings_state.dart @@ -2,8 +2,8 @@ part of 'app_settings_cubit.dart'; class AppSettingsState extends Equatable { const AppSettingsState({ - @required this.isDarkModeOn, - @required this.isOnbordingShowing, + required this.isDarkModeOn, + required this.isOnbordingShowing, }); final bool isDarkModeOn; diff --git a/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart b/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart index 0f202584..386882a9 100644 --- a/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart @@ -42,13 +42,14 @@ class BackblazeFormCubit extends FormCubit { final AppConfigCubit initializingCubit; - FieldCubit keyId; - - FieldCubit applicationKey; + // ignore: close_sinks + late final FieldCubit keyId; + // ignore: close_sinks + late final FieldCubit applicationKey; @override FutureOr asyncValidation() async { - bool isKeyValid; + late bool isKeyValid; try { String encodedApiKey = encodedBackblazeKey( keyId.state.value, diff --git a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart index ff51401c..2f885436 100644 --- a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart @@ -30,11 +30,11 @@ class CloudFlareFormCubit extends FormCubit { final AppConfigCubit initializingCubit; - FieldCubit apiKey; + late final FieldCubit apiKey; @override FutureOr asyncValidation() async { - bool isKeyValid; + late bool isKeyValid; try { isKeyValid = await apiClient.isValid(apiKey.state.value); diff --git a/lib/logic/cubit/forms/initializing/domain_cloudflare.dart b/lib/logic/cubit/forms/initializing/domain_cloudflare.dart index b526b0ce..07616b0a 100644 --- a/lib/logic/cubit/forms/initializing/domain_cloudflare.dart +++ b/lib/logic/cubit/forms/initializing/domain_cloudflare.dart @@ -5,7 +5,7 @@ import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; class DomainSetupCubit extends Cubit { DomainSetupCubit(this.initializingCubit) : super(Initial()) { - var token = (initializingCubit.state.cloudFlareKey); + var token = initializingCubit.state.cloudFlareKey; assert(token != null, 'no cloudflare token'); @@ -13,11 +13,11 @@ class DomainSetupCubit extends Cubit { } AppConfigCubit initializingCubit; - CloudflareApi api; + late CloudflareApi api; Future load() async { emit(Loading(LoadingTypes.loadingDomain)); - var list = await api.domainList(); + var list = await (api.domainList() as Future>); if (list.isEmpty) { emit(Empty()); } else if (list.length == 1) { diff --git a/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart b/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart index 8be71e65..2383a986 100644 --- a/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart @@ -30,11 +30,12 @@ class HetznerFormCubit extends FormCubit { final AppConfigCubit initializingCubit; - FieldCubit apiKey; + // ignore: close_sinks + late final FieldCubit apiKey; @override FutureOr asyncValidation() async { - bool isKeyValid; + late bool isKeyValid; try { isKeyValid = await apiClient.isValid(apiKey.state.value); } catch (e) { diff --git a/lib/logic/cubit/forms/initializing/root_user_form_cubit.dart b/lib/logic/cubit/forms/initializing/root_user_form_cubit.dart index 2fdc6e8a..f651c251 100644 --- a/lib/logic/cubit/forms/initializing/root_user_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/root_user_form_cubit.dart @@ -46,9 +46,12 @@ class RootUserFormCubit extends FormCubit { final AppConfigCubit initializingCubit; - FieldCubit userName; - FieldCubit password; - FieldCubit isVisible; + // ignore: close_sinks + late final FieldCubit userName; + // ignore: close_sinks + late final FieldCubit password; + // ignore: close_sinks + late final FieldCubit isVisible; @override Future close() async { diff --git a/lib/logic/cubit/forms/user/user_form_cubit.dart b/lib/logic/cubit/forms/user/user_form_cubit.dart index c75e760d..59bd50d3 100644 --- a/lib/logic/cubit/forms/user/user_form_cubit.dart +++ b/lib/logic/cubit/forms/user/user_form_cubit.dart @@ -7,8 +7,8 @@ import 'package:selfprivacy/utils/password_generator.dart'; class UserFormCubit extends FormCubit { UserFormCubit({ - this.usersCubit, - User user, + required this.usersCubit, + User? user, }) { var isEdit = user != null; @@ -16,7 +16,7 @@ class UserFormCubit extends FormCubit { var passwordRegExp = RegExp(r"[\n\r\s]+"); login = FieldCubit( - initalValue: isEdit ? user.login : '', + initalValue: isEdit ? user!.login : '', validations: [ RequiredStringValidation('required'), ValidationModel( @@ -25,7 +25,7 @@ class UserFormCubit extends FormCubit { ); password = FieldCubit( - initalValue: isEdit ? user.password : genPass(), + initalValue: isEdit ? user!.password : genPass(), validations: [ RequiredStringValidation('required'), ValidationModel( @@ -42,15 +42,16 @@ class UserFormCubit extends FormCubit { login: login.state.value, password: password.state.value, ); - usersCubit.add(user); + usersCubit.addUser(user); } - FieldCubit login; - FieldCubit password; + // ignore: close_sinks + late FieldCubit login; + late FieldCubit password; void genNewPassword() { password.externalSetValue(genPass()); } - UsersCubit usersCubit; + late UsersCubit usersCubit; } diff --git a/lib/logic/cubit/forms/validations/validations.dart b/lib/logic/cubit/forms/validations/validations.dart index bf39f787..0c4fe493 100644 --- a/lib/logic/cubit/forms/validations/validations.dart +++ b/lib/logic/cubit/forms/validations/validations.dart @@ -5,7 +5,7 @@ class LegnthStringValidationWithLenghShowing extends ValidationModel { : super((n) => n.length != length, errorText); @override - String check(String val) { + String? check(String val) { var length = val.length; var errorMassage = this.errorMassage.replaceAll("[]", length.toString()); return test(val) ? errorMassage : null; diff --git a/lib/logic/cubit/services/services_cubit.dart b/lib/logic/cubit/services/services_cubit.dart index 96e76686..a23b70e7 100644 --- a/lib/logic/cubit/services/services_cubit.dart +++ b/lib/logic/cubit/services/services_cubit.dart @@ -1,28 +1,28 @@ -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:meta/meta.dart'; -import 'package:selfprivacy/logic/models/service.dart'; -import 'package:selfprivacy/logic/models/state_types.dart'; +// import 'package:bloc/bloc.dart'; +// import 'package:equatable/equatable.dart'; +// import 'package:meta/meta.dart'; +// import 'package:selfprivacy/logic/models/service.dart'; +// import 'package:selfprivacy/logic/models/state_types.dart'; -export 'package:provider/provider.dart'; -export 'package:selfprivacy/logic/models/state_types.dart'; +// export 'package:provider/provider.dart'; +// export 'package:selfprivacy/logic/models/state_types.dart'; -part 'services_state.dart'; +// part 'services_state.dart'; -class ServicesCubit extends Cubit { - ServicesCubit() : super(ServicesState(all)); +// class ServicesCubit extends Cubit { +// ServicesCubit() : super(ServicesState(all)); - void connect(Service service) { - var newState = state.updateElement(service, StateType.stable); - emit(newState); - } -} +// void connect(Service service) { +// var newState = state.updateElement(service, StateType.stable); +// emit(newState); +// } +// } -final all = ServiceTypes.values - .map( - (type) => Service( - state: StateType.uninitialized, - type: type, - ), - ) - .toList(); +// final all = ServiceTypes.values +// .map( +// (type) => Service( +// state: StateType.uninitialized, +// type: type, +// ), +// ) +// .toList(); diff --git a/lib/logic/cubit/services/services_state.dart b/lib/logic/cubit/services/services_state.dart index 0cc0fb96..d20a63a8 100644 --- a/lib/logic/cubit/services/services_state.dart +++ b/lib/logic/cubit/services/services_state.dart @@ -1,26 +1,26 @@ -part of 'services_cubit.dart'; +// part of 'services_cubit.dart'; -@immutable -class ServicesState extends Equatable{ - ServicesState(this.all); +// @immutable +// class ServicesState extends Equatable{ +// ServicesState(this.all); - final List all; +// final List all; - ServicesState updateElement(Service service, StateType newState) { - var newList = [...all]; - var index = newList.indexOf(service); - newList[index] = service.updateState(newState); - return ServicesState(newList); - } +// ServicesState updateElement(Service service, StateType newState) { +// var newList = [...all]; +// var index = newList.indexOf(service); +// newList[index] = service.updateState(newState); +// return ServicesState(newList); +// } - List get connected => all - .where((service) => service.state != StateType.uninitialized) - .toList(); +// List get connected => all +// .where((service) => service.state != StateType.uninitialized) +// .toList(); - List get uninitialized => all - .where((service) => service.state == StateType.uninitialized) - .toList(); +// List get uninitialized => all +// .where((service) => service.state == StateType.uninitialized) +// .toList(); - @override - List get props => all; -} +// @override +// List get props => all; +// } diff --git a/lib/logic/cubit/users/users_cubit.dart b/lib/logic/cubit/users/users_cubit.dart index cf296f31..6e00f7e9 100644 --- a/lib/logic/cubit/users/users_cubit.dart +++ b/lib/logic/cubit/users/users_cubit.dart @@ -8,14 +8,14 @@ part 'users_state.dart'; class UsersCubit extends Cubit { UsersCubit() : super(UsersState([])); - void add(User user) { + void addUser(User user) { var users = [...state.users]; users.add(user); emit(UsersState(users)); } - void remove(User user) { + void remove(User? user) { var users = [...state.users]; users.remove(user); diff --git a/lib/logic/get_it/navigation.dart b/lib/logic/get_it/navigation.dart index cf5dc8ff..92074c93 100644 --- a/lib/logic/get_it/navigation.dart +++ b/lib/logic/get_it/navigation.dart @@ -3,10 +3,10 @@ import 'package:flutter/widgets.dart'; class NavigationService { final GlobalKey navigatorKey = GlobalKey(); - NavigatorState get navigator => navigatorKey.currentState; + NavigatorState? get navigator => navigatorKey.currentState; void showPopUpDialog(AlertDialog dialog) { - final context = navigatorKey.currentState.overlay.context; + final context = navigatorKey.currentState!.overlay!.context; showDialog( context: context, diff --git a/lib/logic/models/backblaze_credential.dart b/lib/logic/models/backblaze_credential.dart index 28d146fe..3496f4ce 100644 --- a/lib/logic/models/backblaze_credential.dart +++ b/lib/logic/models/backblaze_credential.dart @@ -9,10 +9,10 @@ class BackblazeCredential { BackblazeCredential({this.keyId, this.applicationKey}); @HiveField(0) - final String keyId; + final String? keyId; @HiveField(1) - final String applicationKey; + final String? applicationKey; get encodedApiKey => encodedBackblazeKey(keyId, applicationKey); @@ -22,7 +22,7 @@ class BackblazeCredential { } } -String encodedBackblazeKey(String keyId, String applicationKey) { +String encodedBackblazeKey(String? keyId, String? applicationKey) { String _apiKey = '$keyId:$applicationKey'; String encodedApiKey = base64.encode(utf8.encode(_apiKey)); return encodedApiKey; diff --git a/lib/logic/models/backblaze_credential.g.dart b/lib/logic/models/backblaze_credential.g.dart index c6ad373e..305b3386 100644 --- a/lib/logic/models/backblaze_credential.g.dart +++ b/lib/logic/models/backblaze_credential.g.dart @@ -17,8 +17,8 @@ class BackblazeCredentialAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return BackblazeCredential( - keyId: fields[0] as String, - applicationKey: fields[1] as String, + keyId: fields[0] as String?, + applicationKey: fields[1] as String?, ); } diff --git a/lib/logic/models/cloudflare_domain.dart b/lib/logic/models/cloudflare_domain.dart index b050a92c..d66e9a04 100644 --- a/lib/logic/models/cloudflare_domain.dart +++ b/lib/logic/models/cloudflare_domain.dart @@ -7,10 +7,10 @@ class CloudFlareDomain { CloudFlareDomain({this.domainName, this.zoneId}); @HiveField(0) - final String domainName; + final String? domainName; @HiveField(1) - final String zoneId; + final String? zoneId; @override String toString() { diff --git a/lib/logic/models/cloudflare_domain.g.dart b/lib/logic/models/cloudflare_domain.g.dart index dcd95317..d96cf9bc 100644 --- a/lib/logic/models/cloudflare_domain.g.dart +++ b/lib/logic/models/cloudflare_domain.g.dart @@ -17,8 +17,8 @@ class CloudFlareDomainAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return CloudFlareDomain( - domainName: fields[0] as String, - zoneId: fields[1] as String, + domainName: fields[0] as String?, + zoneId: fields[1] as String?, ); } diff --git a/lib/logic/models/dns_records.dart b/lib/logic/models/dns_records.dart index 748ec763..80f1335e 100644 --- a/lib/logic/models/dns_records.dart +++ b/lib/logic/models/dns_records.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; part 'dns_records.g.dart'; @@ -6,17 +5,17 @@ part 'dns_records.g.dart'; @JsonSerializable(createToJson: true, createFactory: false) class DnsRecords { DnsRecords({ - @required this.type, - @required this.name, - @required this.content, + required this.type, + required this.name, + required this.content, this.ttl = 3600, this.priority = 10, this.proxied = false, }); final String type; - final String name; - final String content; + final String? name; + final String? content; final int ttl; final int priority; final bool proxied; diff --git a/lib/logic/models/message.dart b/lib/logic/models/message.dart index 5ec302ba..5ae0465e 100644 --- a/lib/logic/models/message.dart +++ b/lib/logic/models/message.dart @@ -5,12 +5,12 @@ final formater = new DateFormat('hh:mm'); class Message { Message({this.text, this.type = MessageType.normal}) : time = DateTime.now(); - final String text; + final String? text; final DateTime time; final MessageType type; String get timeString => formater.format(time); - static Message warn({String text}) => Message( + static Message warn({String? text}) => Message( text: text, type: MessageType.warning, ); diff --git a/lib/logic/models/provider.dart b/lib/logic/models/provider.dart index e89e1456..82af8656 100644 --- a/lib/logic/models/provider.dart +++ b/lib/logic/models/provider.dart @@ -10,7 +10,7 @@ enum ProviderType { } class ProviderModel extends Equatable { - const ProviderModel({this.state, this.type}); + const ProviderModel({required this.state, required this.type}); final StateType state; final ProviderType type; @@ -21,7 +21,7 @@ class ProviderModel extends Equatable { ); @override - List get props => [state, type]; + List get props => [state, type]; IconData get icon { switch (type) { @@ -31,10 +31,8 @@ class ProviderModel extends Equatable { case ProviderType.domain: return BrandIcons.globe; - break; case ProviderType.backup: return BrandIcons.save; } - return null; } } diff --git a/lib/logic/models/server_details.dart b/lib/logic/models/server_details.dart index ae0ff7e3..e014de14 100644 --- a/lib/logic/models/server_details.dart +++ b/lib/logic/models/server_details.dart @@ -1,4 +1,3 @@ -import 'package:flutter/widgets.dart'; import 'package:hive/hive.dart'; part 'server_details.g.dart'; @@ -6,25 +5,25 @@ part 'server_details.g.dart'; @HiveType(typeId: 2) class HetznerServerDetails { HetznerServerDetails({ - @required this.ip4, - @required this.id, - @required this.createTime, + required this.ip4, + required this.id, + required this.createTime, this.startTime, }); @HiveField(0) - final String ip4; + final String? ip4; @HiveField(1) - final int id; + final int? id; @HiveField(3) - final DateTime createTime; + final DateTime? createTime; @HiveField(2) - final DateTime startTime; + final DateTime? startTime; - HetznerServerDetails copyWith({DateTime startTime}) { + HetznerServerDetails copyWith({DateTime? startTime}) { return HetznerServerDetails( startTime: startTime ?? this.startTime, createTime: createTime, diff --git a/lib/logic/models/server_details.g.dart b/lib/logic/models/server_details.g.dart index c5318044..0f08e2f2 100644 --- a/lib/logic/models/server_details.g.dart +++ b/lib/logic/models/server_details.g.dart @@ -17,10 +17,10 @@ class HetznerServerDetailsAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HetznerServerDetails( - ip4: fields[0] as String, - id: fields[1] as int, - createTime: fields[3] as DateTime, - startTime: fields[2] as DateTime, + ip4: fields[0] as String?, + id: fields[1] as int?, + createTime: fields[3] as DateTime?, + startTime: fields[2] as DateTime?, ); } diff --git a/lib/logic/models/server_status.dart b/lib/logic/models/server_status.dart index af1165c1..1405bde3 100644 --- a/lib/logic/models/server_status.dart +++ b/lib/logic/models/server_status.dart @@ -1,12 +1,10 @@ -import 'package:flutter/foundation.dart'; - class ServerStatus { final StatusTypes http; final StatusTypes imap; final StatusTypes smtp; ServerStatus({ - @required this.http, + required this.http, this.imap = StatusTypes.nodata, this.smtp = StatusTypes.nodata, }); @@ -20,7 +18,7 @@ class ServerStatus { } } -StatusTypes statusTypeFromNumber(int number) { +StatusTypes statusTypeFromNumber(int? number) { if (number == 0) { return StatusTypes.ok; } else if (number == 1) { diff --git a/lib/logic/models/service.dart b/lib/logic/models/service.dart index 85d38689..8ce6e310 100644 --- a/lib/logic/models/service.dart +++ b/lib/logic/models/service.dart @@ -1,25 +1,25 @@ -import 'package:equatable/equatable.dart'; -import 'package:selfprivacy/logic/models/state_types.dart'; +// import 'package:equatable/equatable.dart'; +// import 'package:selfprivacy/logic/models/state_types.dart'; -enum ServiceTypes { - messanger, - mail, - passwordManager, - github, - cloud, -} +// enum ServiceTypes { +// messanger, +// mail, +// passwordManager, +// github, +// cloud, +// } -class Service extends Equatable { - const Service({this.state, this.type}); +// class Service extends Equatable { +// const Service({required this.state, required this.type}); - final StateType state; - final ServiceTypes type; +// final StateType state; +// final ServiceTypes type; - Service updateState(StateType newState) => Service( - state: newState, - type: type, - ); +// Service updateState(StateType newState) => Service( +// state: newState, +// type: type, +// ); - @override - List get props => [state, type]; -} +// @override +// List get props => [state, type]; +// } diff --git a/lib/logic/models/user.dart b/lib/logic/models/user.dart index 3c37a356..3df879c5 100644 --- a/lib/logic/models/user.dart +++ b/lib/logic/models/user.dart @@ -1,7 +1,6 @@ import 'dart:ui'; import 'package:equatable/equatable.dart'; -import 'package:flutter/foundation.dart'; import 'package:selfprivacy/utils/color_utils.dart'; import 'package:hive/hive.dart'; import 'package:selfprivacy/utils/crypto.dart'; @@ -11,18 +10,18 @@ part 'user.g.dart'; @HiveType(typeId: 1) class User extends Equatable { User({ - @required this.login, - @required this.password, + required this.login, + required this.password, }); @HiveField(0) final String login; - + @HiveField(1) final String password; @override - List get props => [login, password]; + List get props => [login, password]; Color get color => stringToColor(login); diff --git a/lib/main.dart b/lib/main.dart index 200fd96e..4d678e31 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -22,6 +22,7 @@ void main() async { Wakelock.enable(); getItSetup(); WidgetsFlutterBinding.ensureInitialized(); + await EasyLocalization.ensureInitialized(); runApp( Localization( @@ -35,7 +36,7 @@ void main() async { class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - var appSettings = context.watch().state; + AppSettingsState appSettings = context.watch().state; return AnnotatedRegion( value: SystemUiOverlayStyle.light, // Manually changnig appbar color @@ -50,12 +51,12 @@ class MyApp extends StatelessWidget { home: appSettings.isOnbordingShowing ? OnboardingPage(nextPage: InitializingPage()) : RootPage(), - builder: (BuildContext context, Widget widget) { + builder: (BuildContext context, Widget? widget) { Widget error = Text('...rendering error...'); if (widget is Scaffold || widget is Navigator) error = Scaffold(body: Center(child: error)); ErrorWidget.builder = (FlutterErrorDetails errorDetails) => error; - return widget; + return widget!; }, ), ); diff --git a/lib/ui/components/action_button/action_button.dart b/lib/ui/components/action_button/action_button.dart index 15565e34..bc0393e7 100644 --- a/lib/ui/components/action_button/action_button.dart +++ b/lib/ui/components/action_button/action_button.dart @@ -3,14 +3,14 @@ import 'package:selfprivacy/config/brand_colors.dart'; class ActionButton extends StatelessWidget { const ActionButton({ - Key key, + Key? key, this.text, this.onPressed, this.isRed = false, }) : super(key: key); - final VoidCallback onPressed; - final String text; + final VoidCallback? onPressed; + final String? text; final bool isRed; @override @@ -19,12 +19,12 @@ class ActionButton extends StatelessWidget { return TextButton( child: Text( - text, + text!, style: isRed ? TextStyle(color: BrandColors.red1) : null, ), onPressed: () { navigator.pop(); - if (onPressed != null) onPressed(); + if (onPressed != null) onPressed!(); }, ); } diff --git a/lib/ui/components/brand_alert/brand_alert.dart b/lib/ui/components/brand_alert/brand_alert.dart index cf586061..6f1a1b0f 100644 --- a/lib/ui/components/brand_alert/brand_alert.dart +++ b/lib/ui/components/brand_alert/brand_alert.dart @@ -2,14 +2,14 @@ import 'package:flutter/material.dart'; class BrandAlert extends AlertDialog { BrandAlert({ - Key key, - String title, - String contentText, - List acitons, + Key? key, + String? title, + String? contentText, + List? acitons, }) : super( key: key, title: title != null ? Text(title) : null, - content: title != null ? Text(contentText) : null, + content: title != null ? Text(contentText!) : null, actions: acitons, ); } diff --git a/lib/ui/components/brand_button/brand_button.dart b/lib/ui/components/brand_button/brand_button.dart index d7e7fb67..192f8a8b 100644 --- a/lib/ui/components/brand_button/brand_button.dart +++ b/lib/ui/components/brand_button/brand_button.dart @@ -8,10 +8,10 @@ enum BrandButtonTypes { rised, text, iconText } class BrandButton { static rised({ - Key key, - @required VoidCallback onPressed, - String title, - Widget child, + Key? key, + required VoidCallback? onPressed, + String? title, + Widget? child, }) { assert(title == null || child == null, 'required title or child'); assert(title != null || child != null, 'required title or child'); @@ -24,9 +24,9 @@ class BrandButton { } static text({ - Key key, - @required VoidCallback onPressed, - @required String title, + Key? key, + required VoidCallback onPressed, + required String title, }) => _TextButton( key: key, @@ -35,10 +35,10 @@ class BrandButton { ); static iconText({ - Key key, - @required VoidCallback onPressed, - @required String title, - @required Icon icon, + Key? key, + required VoidCallback onPressed, + required String title, + required Icon icon, }) => _IconTextButton( key: key, @@ -50,15 +50,15 @@ class BrandButton { class _RisedButton extends StatelessWidget { const _RisedButton({ - Key key, + Key? key, this.onPressed, this.title, this.child, }) : super(key: key); - final VoidCallback onPressed; - final String title; - final Widget child; + final VoidCallback? onPressed; + final String? title; + final Widget? child; @override Widget build(BuildContext context) { @@ -88,13 +88,13 @@ class _RisedButton extends StatelessWidget { class _TextButton extends StatelessWidget { const _TextButton({ - Key key, + Key? key, this.onPressed, this.title, }) : super(key: key); - final VoidCallback onPressed; - final String title; + final VoidCallback? onPressed; + final String? title; @override Widget build(BuildContext context) { @@ -106,7 +106,7 @@ class _TextButton extends StatelessWidget { alignment: Alignment.center, padding: EdgeInsets.all(12), child: Text( - title, + title!, style: TextStyle( color: BrandColors.blue, fontSize: 16, @@ -120,12 +120,12 @@ class _TextButton extends StatelessWidget { } class _IconTextButton extends StatelessWidget { - const _IconTextButton({Key key, this.onPressed, this.title, this.icon}) + const _IconTextButton({Key? key, this.onPressed, this.title, this.icon}) : super(key: key); - final VoidCallback onPressed; - final String title; - final Icon icon; + final VoidCallback? onPressed; + final String? title; + final Icon? icon; @override Widget build(BuildContext context) { diff --git a/lib/ui/components/brand_card/brand_card.dart b/lib/ui/components/brand_card/brand_card.dart index a30ef5b1..9fcfcb6b 100644 --- a/lib/ui/components/brand_card/brand_card.dart +++ b/lib/ui/components/brand_card/brand_card.dart @@ -4,11 +4,11 @@ import 'package:selfprivacy/utils/extensions/elevation_extension.dart'; class BrandCard extends StatelessWidget { const BrandCard({ - Key key, + Key? key, this.child, }) : super(key: key); - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { diff --git a/lib/ui/components/brand_divider/brand_divider.dart b/lib/ui/components/brand_divider/brand_divider.dart index 00bd0ebf..f031254f 100644 --- a/lib/ui/components/brand_divider/brand_divider.dart +++ b/lib/ui/components/brand_divider/brand_divider.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_colors.dart'; class BrandDivider extends StatelessWidget { - const BrandDivider({Key key}) : super(key: key); + const BrandDivider({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/components/brand_header/brand_header.dart b/lib/ui/components/brand_header/brand_header.dart index cff4d41a..fcbac700 100644 --- a/lib/ui/components/brand_header/brand_header.dart +++ b/lib/ui/components/brand_header/brand_header.dart @@ -4,8 +4,8 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; class BrandHeader extends StatelessWidget { const BrandHeader({ - Key key, - @required this.title, + Key? key, + required this.title, this.hasBackButton = false, }) : super(key: key); diff --git a/lib/ui/components/brand_icons/brand_icons.dart b/lib/ui/components/brand_icons/brand_icons.dart index 06bad438..b66f8bf6 100644 --- a/lib/ui/components/brand_icons/brand_icons.dart +++ b/lib/ui/components/brand_icons/brand_icons.dart @@ -1,5 +1,5 @@ /// Flutter icons BrandIcons -/// Copyright (C) 2020 by original authors @ fluttericon.com, fontello.com +/// Copyright (C) 2021 by original authors @ fluttericon.com, fontello.com /// This font was generated by FlutterIcon.com, which is derived from Fontello. /// /// To use this font, place it in your fonts/ directory and include the @@ -19,7 +19,7 @@ class BrandIcons { BrandIcons._(); static const _kFontFam = 'BrandIcons'; - static const _kFontPkg = null; + static const String? _kFontPkg = null; static const IconData connection = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg); @@ -39,14 +39,22 @@ class BrandIcons { IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData check = IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData webcam = + IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData refresh = IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData git = + IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData social = + IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData settings = IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData share = IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData triangle = IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData engineer = + IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData server = IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData box = @@ -59,8 +67,16 @@ class BrandIcons { IconData(0xe815, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData upload = IconData(0xe816, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData github = - IconData(0xe817, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData arrow_left = IconData(0xe818, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData shape = + IconData(0xe819, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData keyhole = + IconData(0xe81a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData terminal = + IconData(0xe81b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData fire = + IconData(0xe81c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData start = + IconData(0xe81d, fontFamily: _kFontFam, fontPackage: _kFontPkg); } diff --git a/lib/ui/components/brand_md/brand_md.dart b/lib/ui/components/brand_md/brand_md.dart new file mode 100644 index 00000000..75985286 --- /dev/null +++ b/lib/ui/components/brand_md/brand_md.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:easy_localization/easy_localization.dart'; +import 'package:selfprivacy/config/brand_colors.dart'; +import 'package:selfprivacy/config/text_themes.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class BrandMarkdown extends StatefulWidget { + const BrandMarkdown({ + Key? key, + required this.fileName, + }) : super(key: key); + + final String fileName; + + @override + _BrandMarkdownState createState() => _BrandMarkdownState(); +} + +class _BrandMarkdownState extends State { + String _mdContent = ''; + + @override + void initState() { + super.initState(); + _loadMdFile(); + } + + void _loadMdFile() async { + String mdFromFile = await rootBundle + .loadString('assets/markdown/${widget.fileName}-${'locale'.tr()}.md'); + setState(() { + _mdContent = mdFromFile; + }); + } + + @override + Widget build(BuildContext context) { + var isDark = Theme.of(context).brightness == Brightness.dark; + var markdown = MarkdownStyleSheet( + p: defaultTextStyle, + h1: headline1Style.copyWith( + color: isDark ? BrandColors.white : null, + ), + h2: headline2Style.copyWith( + color: isDark ? BrandColors.white : null, + ), + h3: headline3Style.copyWith( + color: isDark ? BrandColors.white : null, + ), + h4: headline4Style.copyWith( + color: isDark ? BrandColors.white : null, + ), + ); + return Markdown( + styleSheet: markdown, + onTapLink: (String text, String? href, String title) { + if (href != null) { + canLaunch(href).then((canLaunchURL) { + if (canLaunchURL) { + launch(href); + } + }); + } + }, + data: _mdContent, + ); + } +} diff --git a/lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart b/lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart index 077fc0be..7670c94d 100644 --- a/lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart +++ b/lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart @@ -4,11 +4,11 @@ var navigatorKey = GlobalKey(); class BrandModalSheet extends StatelessWidget { const BrandModalSheet({ - Key key, + Key? key, this.child, }) : super(key: key); - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { return DraggableScrollableSheet( @@ -43,18 +43,17 @@ class BrandModalSheet extends StatelessWidget { ), ), Container( - constraints: BoxConstraints( - minHeight: MediaQuery.of(context).size.height - 32 - 4, - maxHeight: MediaQuery.of(context).size.height, - ), - decoration: BoxDecoration( - borderRadius: - BorderRadius.vertical(top: Radius.circular(20)), - color: Theme.of(context).scaffoldBackgroundColor, - ), - width: double.infinity, - child: child - ), + constraints: BoxConstraints( + minHeight: MediaQuery.of(context).size.height - 132, + maxHeight: MediaQuery.of(context).size.height - 132, + ), + decoration: BoxDecoration( + borderRadius: + BorderRadius.vertical(top: Radius.circular(20)), + color: Theme.of(context).scaffoldBackgroundColor, + ), + width: double.infinity, + child: child), ], ), ), diff --git a/lib/ui/components/brand_span_button/brand_span_button.dart b/lib/ui/components/brand_span_button/brand_span_button.dart index ac7c53db..d6cdcb02 100644 --- a/lib/ui/components/brand_span_button/brand_span_button.dart +++ b/lib/ui/components/brand_span_button/brand_span_button.dart @@ -5,21 +5,19 @@ import 'package:url_launcher/url_launcher.dart'; class BrandSpanButton extends TextSpan { BrandSpanButton({ - @required String text, - @required VoidCallback onTap, - TextStyle style, - }) : assert(text != null), - assert(onTap != null), - super( + required String text, + required VoidCallback onTap, + TextStyle? style, + }) : super( recognizer: TapGestureRecognizer()..onTap = onTap, text: text, style: (style ?? TextStyle()).copyWith(color: BrandColors.blue), ); static link({ - @required String text, - String urlString, - TextStyle style, + required String text, + String? urlString, + TextStyle? style, }) => BrandSpanButton( text: text, diff --git a/lib/ui/components/brand_tab_bar/brand_tab_bar.dart b/lib/ui/components/brand_tab_bar/brand_tab_bar.dart index 544dc6db..2df24868 100644 --- a/lib/ui/components/brand_tab_bar/brand_tab_bar.dart +++ b/lib/ui/components/brand_tab_bar/brand_tab_bar.dart @@ -1,37 +1,38 @@ import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; +import 'package:easy_localization/easy_localization.dart'; final _kBottomTabBarHeight = 51; class BrandTabBar extends StatefulWidget { - BrandTabBar({Key key, this.controller}) : super(key: key); + BrandTabBar({Key? key, this.controller}) : super(key: key); - final TabController controller; + final TabController? controller; @override _BrandTabBarState createState() => _BrandTabBarState(); } class _BrandTabBarState extends State { - int currentIndex; + int? currentIndex; @override void initState() { - currentIndex = widget.controller.index; - widget.controller.addListener(_listener); + currentIndex = widget.controller!.index; + widget.controller!.addListener(_listener); super.initState(); } _listener() { - if (currentIndex != widget.controller.index) { + if (currentIndex != widget.controller!.index) { setState(() { - currentIndex = widget.controller.index; + currentIndex = widget.controller!.index; }); } } @override void dispose() { - widget.controller ?? widget.controller.removeListener(_listener); + widget.controller ?? widget.controller!.removeListener(_listener); super.dispose(); } @@ -50,10 +51,10 @@ class _BrandTabBarState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _getIconButton('Провайдеры', BrandIcons.server, 0), - _getIconButton('Сервисы', BrandIcons.box, 1), - _getIconButton('Пользователи', BrandIcons.users, 2), - _getIconButton('Еще', BrandIcons.menu, 3), + _getIconButton('basis.providers'.tr(), BrandIcons.server, 0), + _getIconButton('basis.services'.tr(), BrandIcons.box, 1), + _getIconButton('basis.users'.tr(), BrandIcons.users, 2), + _getIconButton('basis.more'.tr(), BrandIcons.menu, 3), ], ), ), @@ -68,7 +69,7 @@ class _BrandTabBarState extends State { var isActive = currentIndex == index; var color = isActive ? acitivColor : BrandColors.inactive; return InkWell( - onTap: () => widget.controller.animateTo(index), + onTap: () => widget.controller!.animateTo(index), child: Padding( padding: EdgeInsets.all(6), child: ConstrainedBox( diff --git a/lib/ui/components/brand_text/brand_text.dart b/lib/ui/components/brand_text/brand_text.dart index 4440987b..9dda8549 100644 --- a/lib/ui/components/brand_text/brand_text.dart +++ b/lib/ui/components/brand_text/brand_text.dart @@ -17,26 +17,26 @@ enum TextType { class BrandText extends StatelessWidget { const BrandText( this.text, { - Key key, + Key? key, this.style, - @required this.type, + required this.type, this.overflow, this.softWrap, this.textAlign, }) : super(key: key); - final String text; - final TextStyle style; + final String? text; + final TextStyle? style; final TextType type; - final TextOverflow overflow; - final bool softWrap; - final TextAlign textAlign; + final TextOverflow? overflow; + final bool? softWrap; + final TextAlign? textAlign; factory BrandText.h1( - String text, { - TextStyle style, - TextOverflow overflow, - bool softWrap, + String? text, { + TextStyle? style, + TextOverflow? overflow, + bool? softWrap, }) => BrandText( text, @@ -44,18 +44,18 @@ class BrandText extends StatelessWidget { style: style, ); - factory BrandText.onboardingTitle(String text, {TextStyle style}) => + factory BrandText.onboardingTitle(String text, {TextStyle? style}) => BrandText( text, type: TextType.onboardingTitle, style: style, ); - factory BrandText.h2(String text, {TextStyle style}) => BrandText( + factory BrandText.h2(String? text, {TextStyle? style}) => BrandText( text, type: TextType.h2, style: style, ); - factory BrandText.h3(String text, {TextStyle style, TextAlign textAlign}) => + factory BrandText.h3(String text, {TextStyle? style, TextAlign? textAlign}) => BrandText( text, type: TextType.h3, @@ -63,35 +63,35 @@ class BrandText extends StatelessWidget { textAlign: textAlign, overflow: TextOverflow.ellipsis, ); - factory BrandText.h4(String text, {TextStyle style}) => BrandText( + factory BrandText.h4(String? text, {TextStyle? style}) => BrandText( text, type: TextType.h4, style: style, ); - factory BrandText.body1(String text, {TextStyle style}) => BrandText( + factory BrandText.body1(String? text, {TextStyle? style}) => BrandText( text, type: TextType.body1, style: style, ); - factory BrandText.body2(String text, {TextStyle style}) => BrandText( + factory BrandText.body2(String? text, {TextStyle? style}) => BrandText( text, type: TextType.body2, style: style, ); - factory BrandText.medium(String text, - {TextStyle style, TextAlign textAlign}) => + factory BrandText.medium(String? text, + {TextStyle? style, TextAlign? textAlign}) => BrandText( text, type: TextType.medium, style: style, textAlign: textAlign, ); - factory BrandText.small(String text, {TextStyle style}) => BrandText( + factory BrandText.small(String text, {TextStyle? style}) => BrandText( text, type: TextType.small, style: style, ); - factory BrandText.buttonTitleText(String text, {TextStyle style}) => + factory BrandText.buttonTitleText(String? text, {TextStyle? style}) => BrandText( text, type: TextType.buttonTitleText, @@ -153,7 +153,7 @@ class BrandText extends StatelessWidget { style = style.merge(this.style); } return Text( - text, + text!, style: style, overflow: overflow, softWrap: softWrap, diff --git a/lib/ui/components/brand_timer/brand_timer.dart b/lib/ui/components/brand_timer/brand_timer.dart index 17177c65..e1395ced 100644 --- a/lib/ui/components/brand_timer/brand_timer.dart +++ b/lib/ui/components/brand_timer/brand_timer.dart @@ -6,21 +6,21 @@ import 'package:selfprivacy/utils/named_font_weight.dart'; class BrandTimer extends StatefulWidget { const BrandTimer({ - Key key, - @required this.startDateTime, - @required this.duration, + Key? key, + required this.startDateTime, + required this.duration, }) : super(key: key); - final DateTime startDateTime; - final Duration duration; + final DateTime? startDateTime; + final Duration? duration; @override _BrandTimerState createState() => _BrandTimerState(); } class _BrandTimerState extends State { - String _timeString; - Timer timer; + String? _timeString; + late Timer timer; @override void initState() { @@ -31,8 +31,8 @@ class _BrandTimerState extends State { _timerStart() { _timeString = diffenceFromStart; timer = Timer.periodic(Duration(seconds: 1), (Timer t) { - var timePassed = DateTime.now().difference(widget.startDateTime); - if (timePassed > widget.duration) { + var timePassed = DateTime.now().difference(widget.startDateTime!); + if (timePassed > widget.duration!) { t.cancel(); } else { _getTime(); @@ -66,12 +66,12 @@ class _BrandTimerState extends State { } String get diffenceFromStart => - _durationToString(DateTime.now().difference(widget.startDateTime)); + _durationToString(DateTime.now().difference(widget.startDateTime!)); String _durationToString(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, "0"); String twoDigitSeconds = - twoDigits(widget.duration.inSeconds - duration.inSeconds.remainder(60)); + twoDigits(widget.duration!.inSeconds - duration.inSeconds.remainder(60)); return "$twoDigitSeconds cек"; } diff --git a/lib/ui/components/dots_indicator/dots_indicator.dart b/lib/ui/components/dots_indicator/dots_indicator.dart index e95c308f..ccf42aa5 100644 --- a/lib/ui/components/dots_indicator/dots_indicator.dart +++ b/lib/ui/components/dots_indicator/dots_indicator.dart @@ -3,9 +3,9 @@ import 'package:selfprivacy/config/brand_colors.dart'; class DotsIndicator extends StatelessWidget { const DotsIndicator({ - Key key, - @required this.activeIndex, - @required this.count, + Key? key, + required this.activeIndex, + required this.count, }) : super(key: key); final int activeIndex; diff --git a/lib/ui/components/error/error.dart b/lib/ui/components/error/error.dart index d6d75f2f..4046106e 100644 --- a/lib/ui/components/error/error.dart +++ b/lib/ui/components/error/error.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class BrandError extends StatelessWidget { - const BrandError({Key key, this.error, this.stackTrace}) : super(key: key); + const BrandError({Key? key, this.error, this.stackTrace}) : super(key: key); - final Object error; - final StackTrace stackTrace; + final Object? error; + final StackTrace? stackTrace; @override Widget build(BuildContext context) { diff --git a/lib/ui/components/icon_status_mask/icon_status_mask.dart b/lib/ui/components/icon_status_mask/icon_status_mask.dart index f02167da..cf9fd1d7 100644 --- a/lib/ui/components/icon_status_mask/icon_status_mask.dart +++ b/lib/ui/components/icon_status_mask/icon_status_mask.dart @@ -3,14 +3,14 @@ import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; class IconStatusMask extends StatelessWidget { - IconStatusMask({this.child, this.status}); + IconStatusMask({required this.child, required this.status}); final Icon child; final StateType status; @override Widget build(BuildContext context) { - List colors; + late List colors; switch (status) { case StateType.uninitialized: colors = BrandColors.uninitializedGradientColors; diff --git a/lib/ui/components/not_ready_card/not_ready_card.dart b/lib/ui/components/not_ready_card/not_ready_card.dart index 597d6031..d1db3047 100644 --- a/lib/ui/components/not_ready_card/not_ready_card.dart +++ b/lib/ui/components/not_ready_card/not_ready_card.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_colors.dart'; +import 'package:selfprivacy/config/text_themes.dart'; import 'package:selfprivacy/ui/pages/initializing/initializing.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:easy_localization/easy_localization.dart'; class NotReadyCard extends StatelessWidget { - const NotReadyCard({Key key}) : super(key: key); + const NotReadyCard({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -16,29 +18,34 @@ class NotReadyCard extends StatelessWidget { text: TextSpan( children: [ TextSpan( - text: 'Завершите настройку приложения используя ', + text: 'not_ready_card.1'.tr(), style: TextStyle(color: BrandColors.white), ), WidgetSpan( - child: GestureDetector( - child: Text( - 'Мастер подключения', - style: TextStyle( + child: Padding( + padding: const EdgeInsets.only(bottom: 0.5), + child: GestureDetector( + onTap: () => Navigator.of(context).push( + materialRoute( + InitializingPage(), + ), + ), + child: Text( + 'not_ready_card.2'.tr(), + style: body1Style.copyWith( color: Theme.of(context).brightness == Brightness.dark - ? Colors.blueAccent + ? Colors.black : BrandColors.white, fontWeight: FontWeight.bold, - decoration: TextDecoration.underline), - ), - onTap: () => Navigator.of(context).push( - materialRoute( - InitializingPage(), + decoration: TextDecoration.underline, + // height: 1.1, + ), ), ), ), ), TextSpan( - text: ' для продолжения работы', + text: 'not_ready_card.3'.tr(), style: TextStyle(color: BrandColors.white), ), ], diff --git a/lib/ui/components/progress_bar/progress_bar.dart b/lib/ui/components/progress_bar/progress_bar.dart index e7cdc524..27033239 100644 --- a/lib/ui/components/progress_bar/progress_bar.dart +++ b/lib/ui/components/progress_bar/progress_bar.dart @@ -7,9 +7,9 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; class ProgressBar extends StatefulWidget { ProgressBar({ - Key key, - @required this.steps, - @required this.activeIndex, + Key? key, + required this.steps, + required this.activeIndex, }) : super(key: key); final int activeIndex; @@ -102,14 +102,14 @@ class _ProgressBarState extends State { } Expanded _stepTitle({ - int index, - TextStyle style, - String step, + required int index, + TextStyle? style, + String? step, }) { var isActive = index == widget.activeIndex; var checked = index < widget.activeIndex; - style = isActive ? style.copyWith(fontWeight: FontWeight.w700) : style; + style = isActive ? style!.copyWith(fontWeight: FontWeight.w700) : style; return Expanded( flex: 2, child: RichText( diff --git a/lib/ui/components/switch_block/switch_bloc.dart b/lib/ui/components/switch_block/switch_bloc.dart index 57403bea..cddb2859 100644 --- a/lib/ui/components/switch_block/switch_bloc.dart +++ b/lib/ui/components/switch_block/switch_bloc.dart @@ -3,10 +3,10 @@ import 'package:selfprivacy/config/brand_colors.dart'; class SwitcherBlock extends StatelessWidget { const SwitcherBlock({ - Key key, - @required this.child, - @required this.isActive, - @required this.onChange, + Key? key, + required this.child, + required this.isActive, + required this.onChange, }) : super(key: key); final Widget child; diff --git a/lib/ui/pages/initializing/initializing.dart b/lib/ui/pages/initializing/initializing.dart index f56f56fb..0f914a6b 100644 --- a/lib/ui/pages/initializing/initializing.dart +++ b/lib/ui/pages/initializing/initializing.dart @@ -1,9 +1,7 @@ import 'package:cubit_form/cubit_form.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/config/brand_theme.dart'; -import 'package:selfprivacy/config/text_themes.dart'; import 'package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart'; import 'package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart'; import 'package:selfprivacy/logic/cubit/forms/initializing/domain_cloudflare.dart'; @@ -13,13 +11,14 @@ import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; import 'package:selfprivacy/ui/components/brand_card/brand_card.dart'; +import 'package:selfprivacy/ui/components/brand_md/brand_md.dart'; import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart'; -import 'package:selfprivacy/ui/components/brand_span_button/brand_span_button.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/brand_timer/brand_timer.dart'; import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart'; import 'package:selfprivacy/ui/pages/rootRoute.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:easy_localization/easy_localization.dart'; class InitializingPage extends StatelessWidget { @override @@ -60,9 +59,9 @@ class InitializingPage extends StatelessWidget { 'Domain', 'User', 'Server', - 'Check1', - 'Check2', - 'Check3' + ' ✅', + ' ✅', + ' ✅' ], activeIndex: cubit.state.progress, ), @@ -76,12 +75,13 @@ class InitializingPage extends StatelessWidget { ), ), BrandButton.text( - title: - cubit.state.isFullyInitilized ? 'Close' : 'Настрою потом', + title: cubit.state.isFullyInitilized + ? 'basis.close'.tr() + : 'Настрою потом', onPressed: () { Navigator.of(context).pushAndRemoveUntil( materialRoute(RootPage()), - (predicate) => predicate == null, + (predicate) => false, ); }), SizedBox(height: 30), @@ -96,7 +96,7 @@ class InitializingPage extends StatelessWidget { return BlocProvider( create: (context) => HetznerFormCubit(initializingCubit), child: Builder(builder: (context) { - var formCubit = context.watch(); + var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -105,13 +105,12 @@ class InitializingPage extends StatelessWidget { width: 150, ), SizedBox(height: 10), - BrandText.h2('Подключите сервер Hetzner'), + BrandText.h2('initializing.1'.tr()), SizedBox(height: 10), - BrandText.body2( - 'Здесь будут жить наши данные и SelfPrivacy-сервисы'), + BrandText.body2('initializing.2'.tr()), Spacer(), CubitFormTextField( - formFieldCubit: formCubit.apiKey, + formFieldCubit: context.read().apiKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( @@ -120,14 +119,15 @@ class InitializingPage extends StatelessWidget { ), Spacer(), BrandButton.rised( - onPressed: - formCubit.state.isSubmitting ? null : formCubit.trySubmit, - title: 'Подключить', + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + title: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Как получить API Token', + title: 'initializing.how'.tr(), ), ], ); @@ -150,7 +150,7 @@ class InitializingPage extends StatelessWidget { return BlocProvider( create: (context) => CloudFlareFormCubit(initializingCubit), child: Builder(builder: (context) { - var formCubit = context.watch(); + var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -160,28 +160,29 @@ class InitializingPage extends StatelessWidget { width: 150, ), SizedBox(height: 10), - BrandText.h2('Подключите CloudFlare'), + BrandText.h2('initializing.3'.tr()), SizedBox(height: 10), - BrandText.body2('Для управления DNS вашего домена'), + BrandText.body2('initializing.4'.tr()), Spacer(), CubitFormTextField( - formFieldCubit: formCubit.apiKey, + formFieldCubit: context.read().apiKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( - hintText: 'CloudFlare API Token', + hintText: 'initializing.5'.tr(), ), ), Spacer(), BrandButton.rised( - onPressed: - formCubit.state.isSubmitting ? null : formCubit.trySubmit, - title: 'Подключить', + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + title: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( - onPressed: () {}, - title: 'Как получить API Token', + onPressed: () => _showModal(context, _HowHetzner()), + title: 'initializing.how'.tr(), ), ], ); @@ -193,7 +194,7 @@ class InitializingPage extends StatelessWidget { return BlocProvider( create: (context) => BackblazeFormCubit(initializingCubit), child: Builder(builder: (context) { - var formCubit = context.watch(); + var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -202,11 +203,11 @@ class InitializingPage extends StatelessWidget { height: 50, ), SizedBox(height: 10), - BrandText.h2('Подключите облачное хранилище Backblaze'), + BrandText.h2('initializing.6'.tr()), SizedBox(height: 10), Spacer(), CubitFormTextField( - formFieldCubit: formCubit.keyId, + formFieldCubit: context.read().keyId, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( @@ -215,7 +216,7 @@ class InitializingPage extends StatelessWidget { ), Spacer(), CubitFormTextField( - formFieldCubit: formCubit.applicationKey, + formFieldCubit: context.read().applicationKey, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( @@ -224,14 +225,15 @@ class InitializingPage extends StatelessWidget { ), Spacer(), BrandButton.rised( - onPressed: - formCubit.state.isSubmitting ? null : formCubit.trySubmit, - title: 'Подключить', + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + title: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Как получить API Token', + title: 'initializing.how'.tr(), ), ], ); @@ -243,8 +245,7 @@ class InitializingPage extends StatelessWidget { return BlocProvider( create: (context) => DomainSetupCubit(initializingCubit)..load(), child: Builder(builder: (context) { - var domainSetup = context.watch(); - var state = domainSetup.state; + DomainSetupState state = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -253,19 +254,18 @@ class InitializingPage extends StatelessWidget { width: 150, ), SizedBox(height: 30), - BrandText.h2('Домен'), + BrandText.h2('basis.domain'.tr()), SizedBox(height: 10), - if (state is Empty) - BrandText.body2('На данный момент подлюченных доменов нет'), + if (state is Empty) BrandText.body2('initializing.7'.tr()), if (state is Loading) BrandText.body2( state.type == LoadingTypes.loadingDomain - ? 'Загружаем список доменов' - : 'Сохранение..', + ? 'initializing.8'.tr() + : 'basis.saving'.tr(), ), if (state is MoreThenOne) BrandText.body2( - 'Найдено больше одного домена, для вашей безопастности, просим вам удалить не нужные домены', + 'initializing.9'.tr(), ), if (state is Loaded) ...[ SizedBox(height: 10), @@ -283,7 +283,7 @@ class InitializingPage extends StatelessWidget { Container( width: 50, child: BrandButton.rised( - onPressed: () => domainSetup.load(), + onPressed: () => context.read().load(), child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, @@ -302,7 +302,7 @@ class InitializingPage extends StatelessWidget { if (state is Empty) ...[ SizedBox(height: 30), BrandButton.rised( - onPressed: () => domainSetup.load(), + onPressed: () => context.read().load(), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -319,8 +319,8 @@ class InitializingPage extends StatelessWidget { if (state is Loaded) ...[ SizedBox(height: 30), BrandButton.rised( - onPressed: () => domainSetup.saveDomain(), - title: 'Сохранить домен', + onPressed: () => context.read().saveDomain(), + title: 'initializing.10'.tr(), ), ], SizedBox(height: 10), @@ -328,7 +328,7 @@ class InitializingPage extends StatelessWidget { SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Как получить API Token', + title: 'initializing.how'.tr(), ), ], ); @@ -340,7 +340,7 @@ class InitializingPage extends StatelessWidget { return BlocProvider( create: (context) => RootUserFormCubit(initializingCubit), child: Builder(builder: (context) { - var formCubit = context.watch(); + var formCubitState = context.watch().state; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -348,30 +348,33 @@ class InitializingPage extends StatelessWidget { Spacer(), SizedBox(height: 10), CubitFormTextField( - formFieldCubit: formCubit.userName, + formFieldCubit: context.read().userName, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( - hintText: 'Никнейм', + hintText: 'basis.nickname'.tr(), ), ), SizedBox(height: 10), BlocBuilder, FieldCubitState>( - cubit: formCubit.isVisible, + bloc: context.read().isVisible, builder: (context, state) { var isVisible = state.value; return CubitFormTextField( obscureText: !isVisible, - formFieldCubit: formCubit.password, + formFieldCubit: context.read().password, textAlign: TextAlign.center, scrollPadding: EdgeInsets.only(bottom: 70), decoration: InputDecoration( - hintText: 'Пароль', + hintText: 'basis.password'.tr(), suffixIcon: IconButton( icon: Icon( isVisible ? Icons.visibility : Icons.visibility_off, ), - onPressed: () => formCubit.isVisible.setValue(!isVisible), + onPressed: () => context + .read() + .isVisible + .setValue(!isVisible), ), suffixIconConstraints: BoxConstraints(minWidth: 60), prefixIconConstraints: BoxConstraints(maxWidth: 85), @@ -382,14 +385,15 @@ class InitializingPage extends StatelessWidget { ), Spacer(), BrandButton.rised( - onPressed: - formCubit.state.isSubmitting ? null : formCubit.trySubmit, - title: 'Подключить', + onPressed: formCubitState.isSubmitting + ? null + : () => context.read().trySubmit(), + title: 'basis.connect'.tr(), ), SizedBox(height: 10), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Как получить API Token', + title: 'initializing.how'.tr(), ), ], ); @@ -404,19 +408,19 @@ class InitializingPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Spacer(flex: 2), - BrandText.h2('Создать сервер'), + BrandText.h2('initializing.how'.tr()), SizedBox(height: 10), - BrandText.body2('Создать сервер'), + BrandText.body2('initializing.11'.tr()), Spacer(), BrandButton.rised( onPressed: - isLoading ? null : appConfigCubit.createServerAndSetDnsRecords, - title: isLoading ? 'loading' : 'Создать сервер', + isLoading! ? null : appConfigCubit.createServerAndSetDnsRecords, + title: isLoading ? 'loading' : 'initializing.11'.tr(), ), Spacer(flex: 2), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Что это значит?', + title: 'initializing.what'.tr(), ), ], ); @@ -427,13 +431,13 @@ class InitializingPage extends StatelessWidget { assert(appConfigCubit.state is TimerState, 'wronge state'); var state = appConfigCubit.state as TimerState; - String text; - if (state.isServerReseted) { - text = 'Сервер презагружен, ждем последнюю проверку'; - } else if (state.isServerStarted) { - text = 'Cервер запушен, сейчас он будет проверен и перезагружен'; + String? text; + if (state.isServerReseted!) { + text = 'initializing.13'.tr(); + } else if (state.isServerStarted!) { + text = 'initializing.14'.tr(); } else if (state.isServerCreated) { - text = 'Cервер создан, идет проверка ДНС адресов и запуск сервера'; + text = 'initializing.15'.tr(); } return Builder(builder: (context) { return Column( @@ -443,23 +447,23 @@ class InitializingPage extends StatelessWidget { SizedBox(height: 10), BrandText.body2(text), SizedBox(height: 10), - if (!state.isLoading) + if (!state.isLoading!) Row( children: [ - BrandText.body2('До следующей проверки: '), + BrandText.body2('initializing.16'.tr()), BrandTimer( startDateTime: state.timerStart, duration: state.duration, ) ], ), - if (state.isLoading) BrandText.body2('Проверка'), + if (state.isLoading!) BrandText.body2('initializing.17'.tr()), Spacer( flex: 2, ), BrandButton.text( onPressed: () => _showModal(context, _HowHetzner()), - title: 'Что это значит?', + title: 'initializing.what'.tr(), ), ], ); @@ -477,58 +481,17 @@ class InitializingPage extends StatelessWidget { class _HowHetzner extends StatelessWidget { const _HowHetzner({ - Key key, + Key? key, }) : super(key: key); @override Widget build(BuildContext context) { - var isDark = Theme.of(context).brightness == Brightness.dark; - return BrandModalSheet( child: Padding( - padding: brandPagePadding2, - child: Column( - children: [ - SizedBox(height: 40), - BrandText.h2('Как получить Hetzner API Token'), - SizedBox(height: 20), - RichText( - text: TextSpan( - children: [ - TextSpan( - text: '1 Переходим по ссылке ', - style: body1Style.copyWith( - color: isDark ? BrandColors.white : BrandColors.black, - ), - ), - BrandSpanButton.link( - text: 'hetzner.com', - urlString: 'https://hetzner.com', - ), - TextSpan( - text: ''' - -2 Заходим в созданный нами проект. Если такового - нет, значит создаём. - -3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика). - -4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему. - -5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку. - -6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет. - - ''', - style: body1Style.copyWith( - color: isDark ? BrandColors.white : BrandColors.black, - ), - ), - ], - ), - ), - ], - ), - ), + padding: brandPagePadding2.copyWith(top: 25), + child: BrandMarkdown( + fileName: 'how_hetzner', + )), ); } } diff --git a/lib/ui/pages/more/about/about.dart b/lib/ui/pages/more/about/about.dart index d106f9f8..b927c785 100644 --- a/lib/ui/pages/more/about/about.dart +++ b/lib/ui/pages/more/about/about.dart @@ -1,48 +1,24 @@ import 'package:flutter/material.dart'; -import 'package:selfprivacy/config/brand_theme.dart'; -import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; -import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:selfprivacy/ui/components/brand_md/brand_md.dart'; class AboutPage extends StatelessWidget { - const AboutPage({Key key}) : super(key: key); + const AboutPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'О проекте', hasBackButton: true), + child: BrandHeader( + title: 'more.about_project'.tr(), hasBackButton: true), preferredSize: Size.fromHeight(52), ), - body: ListView( - padding: brandPagePadding2, - children: [ - BrandDivider(), - SizedBox(height: 20), - BrandText.h3('О проекте'), - SizedBox(height: 10), - BrandText.body1( - 'Всё больше организаций хотят владеть нашими данными'), - SizedBox(height: 10), - BrandText.body1( - 'А мы сами хотим распоряжаться своими данными на своем сервере.'), - SizedBox(height: 20), - BrandDivider(), - SizedBox(height: 10), - BrandText.h3('Миссия проекта'), - SizedBox(height: 10), - BrandText.body1( - 'Цифровая независимость и приватность доступная каждому'), - SizedBox(height: 20), - BrandDivider(), - SizedBox(height: 10), - BrandText.h3('Цель'), - SizedBox(height: 10), - BrandText.body1( - 'Развивать программу, которая позволит каждому создавать приватные сервисы для себя и своих близких'), - SizedBox(height: 10), - ], + body: Container( + child: BrandMarkdown( + fileName: 'about', + ), ), ), ); diff --git a/lib/ui/pages/more/app_settings/app_setting.dart b/lib/ui/pages/more/app_settings/app_setting.dart index 5063fe31..8d3d33c1 100644 --- a/lib/ui/pages/more/app_settings/app_setting.dart +++ b/lib/ui/pages/more/app_settings/app_setting.dart @@ -9,9 +9,10 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/utils/named_font_weight.dart'; +import 'package:easy_localization/easy_localization.dart'; class AppSettingsPage extends StatefulWidget { - const AppSettingsPage({Key key}) : super(key: key); + const AppSettingsPage({Key? key}) : super(key: key); @override _AppSettingsPageState createState() => _AppSettingsPageState(); @@ -20,16 +21,14 @@ class AppSettingsPage extends StatefulWidget { class _AppSettingsPageState extends State { @override Widget build(BuildContext context) { - var appSettings = context.watch(); - - var isDarkModeOn = appSettings.state.isDarkModeOn; + var isDarkModeOn = context.watch().state.isDarkModeOn; return SafeArea( child: Builder(builder: (context) { return Scaffold( appBar: PreferredSize( child: - BrandHeader(title: 'Настройки приложения', hasBackButton: true), + BrandHeader(title: 'more.settings'.tr(), hasBackButton: true), preferredSize: Size.fromHeight(52), ), body: ListView( @@ -57,8 +56,9 @@ class _AppSettingsPageState extends State { activeColor: BrandColors.green1, activeTrackColor: BrandColors.green2, value: Theme.of(context).brightness == Brightness.dark, - onChanged: (value) => appSettings.updateDarkMode( - isDarkModeOn: !isDarkModeOn), + onChanged: (value) => context + .read() + .updateDarkMode(isDarkModeOn: !isDarkModeOn), ), ], ), @@ -80,8 +80,10 @@ class _AppSettingsPageState extends State { ), ), SizedBox(width: 5), - RaisedButton( - color: BrandColors.red1, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: BrandColors.red1, + ), child: Text( 'Reset', style: TextStyle( @@ -92,24 +94,26 @@ class _AppSettingsPageState extends State { onPressed: () { showDialog( context: context, - child: BrandAlert( - title: 'Вы уверенны', - contentText: 'Сбросить все ключи?', - acitons: [ - ActionButton( - text: 'Да, сбросить', - isRed: true, - onPressed: () { - context - .read() - .clearAppConfig(); - Navigator.of(context).pop(); - }), - ActionButton( - text: 'Отмена', - ), - ], - ), + builder: (_) { + return BrandAlert( + title: 'Вы уверенны', + contentText: 'Сбросить все ключи?', + acitons: [ + ActionButton( + text: 'Да, сбросить', + isRed: true, + onPressed: () { + context + .read() + .clearAppConfig(); + Navigator.of(context).pop(); + }), + ActionButton( + text: 'Отмена', + ), + ], + ); + }, ); }, ) @@ -126,9 +130,9 @@ class _AppSettingsPageState extends State { class _TextColumn extends StatelessWidget { const _TextColumn({ - Key key, - @required this.title, - @required this.value, + Key? key, + required this.title, + required this.value, this.hasWarning = false, }) : super(key: key); diff --git a/lib/ui/pages/more/console/console.dart b/lib/ui/pages/more/console/console.dart index 257aa0f3..5b89ee87 100644 --- a/lib/ui/pages/more/console/console.dart +++ b/lib/ui/pages/more/console/console.dart @@ -9,7 +9,7 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; class Console extends StatefulWidget { - const Console({Key key}) : super(key: key); + const Console({Key? key}) : super(key: key); @override _ConsoleState createState() => _ConsoleState(); diff --git a/lib/ui/pages/more/info/info.dart b/lib/ui/pages/more/info/info.dart index 68cbd197..1ed6aea4 100644 --- a/lib/ui/pages/more/info/info.dart +++ b/lib/ui/pages/more/info/info.dart @@ -4,16 +4,17 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:package_info/package_info.dart'; +import 'package:easy_localization/easy_localization.dart'; class InfoPage extends StatelessWidget { - const InfoPage({Key key}) : super(key: key); + const InfoPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'О приложении', hasBackButton: true), + child: BrandHeader(title: 'more.about_app'.tr(), hasBackButton: true), preferredSize: Size.fromHeight(52), ), body: ListView( @@ -24,8 +25,8 @@ class InfoPage extends StatelessWidget { FutureBuilder( future: _version(), builder: (context, snapshot) { - return BrandText.body1( - 'Тут любая служебная информация, v.${snapshot.data}'); + return BrandText.body1('more.about_app_page.text' + .tr(args: [snapshot.data.toString()])); }), ], ), diff --git a/lib/ui/pages/more/more.dart b/lib/ui/pages/more/more.dart index 88f2326f..8959d87a 100644 --- a/lib/ui/pages/more/more.dart +++ b/lib/ui/pages/more/more.dart @@ -9,6 +9,7 @@ import 'package:selfprivacy/ui/pages/initializing/initializing.dart'; import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart'; import 'package:selfprivacy/ui/pages/rootRoute.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'about/about.dart'; import 'app_settings/app_setting.dart'; @@ -16,13 +17,13 @@ import 'console/console.dart'; import 'info/info.dart'; class MorePage extends StatelessWidget { - const MorePage({Key key}) : super(key: key); + const MorePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'Еще'), + child: BrandHeader(title: 'basis.more'.tr()), preferredSize: Size.fromHeight(52), ), body: ListView( @@ -33,33 +34,33 @@ class MorePage extends StatelessWidget { children: [ BrandDivider(), _NavItem( - title: 'Мастер Подключения', - iconData: BrandIcons.settings, + title: 'more.configuration_wizard'.tr(), + iconData: BrandIcons.triangle, goTo: InitializingPage(), ), _NavItem( - title: 'Настройки приложения', + title: 'more.settings'.tr(), iconData: BrandIcons.settings, goTo: AppSettingsPage(), ), _NavItem( - title: 'О проекте Selfprivacy', - iconData: BrandIcons.triangle, + title: 'more.about_project'.tr(), + iconData: BrandIcons.engineer, goTo: AboutPage(), ), _NavItem( - title: 'О приложении', - iconData: BrandIcons.help, + title: 'more.about_app'.tr(), + iconData: BrandIcons.fire, goTo: InfoPage(), ), _NavItem( - title: 'Onboarding', - iconData: BrandIcons.triangle, + title: 'more.onboarding'.tr(), + iconData: BrandIcons.start, goTo: OnboardingPage(nextPage: RootPage()), ), _NavItem( - title: 'Console', - iconData: BrandIcons.triangle, + title: 'more.console'.tr(), + iconData: BrandIcons.terminal, goTo: Console(), ), ], @@ -73,10 +74,10 @@ class MorePage extends StatelessWidget { class _NavItem extends StatelessWidget { const _NavItem({ - Key key, - @required this.iconData, - @required this.goTo, - @required this.title, + Key? key, + required this.iconData, + required this.goTo, + required this.title, }) : super(key: key); final IconData iconData; diff --git a/lib/ui/pages/onboarding/onboarding.dart b/lib/ui/pages/onboarding/onboarding.dart index 3c622156..07790f60 100644 --- a/lib/ui/pages/onboarding/onboarding.dart +++ b/lib/ui/pages/onboarding/onboarding.dart @@ -3,9 +3,10 @@ import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:easy_localization/easy_localization.dart'; class OnboardingPage extends StatefulWidget { - const OnboardingPage({Key key, @required this.nextPage}) : super(key: key); + const OnboardingPage({Key? key, required this.nextPage}) : super(key: key); final Widget nextPage; @override @@ -54,10 +55,10 @@ class _OnboardingPageState extends State { children: [ SizedBox(height: 30), BrandText.h2( - 'Цифровая независимость и приватность, доступная каждому'), + 'onboarding.page1_title'.tr(), + ), SizedBox(height: 20), - BrandText.body2( - 'Почта и мессенджер с открытым исходным кодом на вашем личном сервере под вашим полным контролем.'), + BrandText.body2('onboarding.page1_text'.tr()), Flexible( child: Center( child: Image.asset( @@ -78,7 +79,7 @@ class _OnboardingPageState extends State { curve: Curves.easeIn, ); }, - title: 'Далее', + title: 'basis.next'.tr(), ), SizedBox(height: 30), ], @@ -94,10 +95,9 @@ class _OnboardingPageState extends State { child: Column( children: [ SizedBox(height: 30), - BrandText.h2('Для работы понадобятся ваши аккаунты'), + BrandText.h2('onboarding.page2_title'.tr()), SizedBox(height: 20), - BrandText.body2( - 'Для максимальноей приватности и независимости SelfPrivacy не использует свои серверы. \n \n Если у вас нет домена, аккаунтов на Hetzner, AWS и Clouflare, мы поможем их создать и подключить.'), + BrandText.body2('onboarding.page2_text'.tr()), SizedBox(height: 20), Center( child: Image.asset( @@ -127,7 +127,7 @@ class _OnboardingPageState extends State { Navigator.of(context) .pushReplacement(materialRoute(widget.nextPage)); }, - title: 'Понял', + title: 'basis.got_it'.tr(), ), SizedBox(height: 30), ], @@ -137,10 +137,10 @@ class _OnboardingPageState extends State { } String _fileName({ - @required BuildContext context, - @required String path, - @required String fileName, - @required String fileExtention, + required BuildContext context, + required String path, + required String fileName, + required String fileExtention, }) { var theme = Theme.of(context); var isDark = theme.brightness == Brightness.dark; diff --git a/lib/ui/pages/providers/providers.dart b/lib/ui/pages/providers/providers.dart index c2869a0d..f4db4a53 100644 --- a/lib/ui/pages/providers/providers.dart +++ b/lib/ui/pages/providers/providers.dart @@ -12,9 +12,10 @@ import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; import 'package:selfprivacy/ui/pages/providers/settings/settings.dart'; import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:easy_localization/easy_localization.dart'; class ProvidersPage extends StatefulWidget { - ProvidersPage({Key key}) : super(key: key); + ProvidersPage({Key? key}) : super(key: key); @override _ProvidersPageState createState() => _ProvidersPageState(); @@ -32,7 +33,7 @@ class _ProvidersPageState extends State { .toList(); return Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'Провайдеры'), + child: BrandHeader(title: 'providers.page_title'.tr()), preferredSize: Size.fromHeight(52), ), body: ListView( @@ -50,32 +51,31 @@ class _ProvidersPageState extends State { } class _Card extends StatelessWidget { - const _Card({Key key, @required this.provider}) : super(key: key); + const _Card({Key? key, required this.provider}) : super(key: key); final ProviderModel provider; @override Widget build(BuildContext context) { - String title; - String message; - String stableText; - var appConfig = context.watch().state; + String? title; + String? message; + String? stableText; + AppConfigState appConfig = context.watch().state; var domainName = - appConfig.isDomainFilled ? appConfig.cloudFlareDomain.domainName : ''; + appConfig.isDomainFilled ? appConfig.cloudFlareDomain!.domainName : ''; switch (provider.type) { case ProviderType.server: - title = 'Сервер'; + title = 'providers.server.card_title'.tr(); stableText = 'В норме'; break; case ProviderType.domain: - title = 'Домен'; + title = 'providers.domain.card_title'.tr(); message = domainName; stableText = 'Домен настроен'; break; case ProviderType.backup: - // message = '22 янв 2021 14:30'; - title = 'Резервное копирование'; + title = 'providers.backup.card_title'.tr(); stableText = 'В норме'; break; } @@ -116,28 +116,56 @@ class _Card extends StatelessWidget { class _ProviderDetails extends StatelessWidget { const _ProviderDetails({ - Key key, - @required this.provider, - @required this.statusText, + Key? key, + required this.provider, + required this.statusText, }) : super(key: key); final ProviderModel provider; - final String statusText; + final String? statusText; @override Widget build(BuildContext context) { - String title; + late String title; + late List children; + var config = context.watch().state; + + var domainName = config.isDomainFilled + ? config.cloudFlareDomain!.domainName! + : 'example.com'; switch (provider.type) { case ProviderType.server: - title = 'Сервер'; + title = 'providers.server.card_title'.tr(); + children = [ + BrandText.body1('providers.server.bottom_sheet.1'.tr()), + SizedBox(height: 10), + BrandText.body1('providers.server.bottom_sheet.2'.tr()), + SizedBox(height: 10), + BrandText.body1('providers.server.bottom_sheet.3'.tr()), + ]; break; case ProviderType.domain: - title = 'Домен'; - + title = 'providers.domain.card_title'.tr(); + children = [ + BrandText.body1('providers.domain.bottom_sheet.1'.tr()), + SizedBox(height: 10), + BrandText.body1( + 'providers.domain.bottom_sheet.2'.tr(args: [domainName, 'Date'])), + SizedBox(height: 10), + BrandText.body1('providers.domain.bottom_sheet.3'.tr()), + ]; break; case ProviderType.backup: - title = 'Резервное копирование'; + title = 'providers.backup.card_title'.tr(); + children = [ + BrandText.body1('providers.backup.bottom_sheet.1'.tr()), + SizedBox(height: 10), + BrandText.body1( + 'providers.backup.bottom_sheet.2'.tr(args: [domainName, 'Time'])), + SizedBox(height: 10), + BrandText.body1('providers.backup.bottom_sheet.3'.tr()), + ]; break; } return BrandModalSheet( @@ -163,7 +191,7 @@ class _ProviderDetails extends StatelessWidget { onSelected: (_PopupMenuItemType result) { switch (result) { case _PopupMenuItemType.setting: - navigatorKey.currentState + navigatorKey.currentState! .push(materialRoute(SettingsPage())); break; } @@ -174,7 +202,7 @@ class _ProviderDetails extends StatelessWidget { value: _PopupMenuItemType.setting, child: Container( padding: EdgeInsets.only(left: 5), - child: Text('Настройки'), + child: Text('basis.settings'.tr()), ), ), ], @@ -182,11 +210,10 @@ class _ProviderDetails extends StatelessWidget { ), ), Padding( - padding: brandPagePadding1, + padding: brandPagePadding2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 13), IconStatusMask( status: provider.state, child: @@ -195,11 +222,7 @@ class _ProviderDetails extends StatelessWidget { SizedBox(height: 10), BrandText.h1(title), SizedBox(height: 10), - BrandText.body1(statusText), - SizedBox( - height: 20, - ), - Text('Статусы сервера и сервис провайдера и т.д.') + ...children ], ), ) diff --git a/lib/ui/pages/providers/settings/settings.dart b/lib/ui/pages/providers/settings/settings.dart index 933fff8c..e2e2294e 100644 --- a/lib/ui/pages/providers/settings/settings.dart +++ b/lib/ui/pages/providers/settings/settings.dart @@ -5,9 +5,10 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; class SettingsPage extends StatelessWidget { - const SettingsPage({Key key}) : super(key: key); + const SettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -15,7 +16,7 @@ class SettingsPage extends StatelessWidget { padding: brandPagePadding2, children: [ SizedBox(height: 10), - BrandHeader(title: 'Настройки', hasBackButton: true), + BrandHeader(title: 'basis.settings'.tr(), hasBackButton: true), BrandDivider(), SwitcherBlock( onChange: (_) {}, @@ -62,9 +63,9 @@ class SettingsPage extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onTap, - @required this.child, + Key? key, + required this.onTap, + required this.child, }) : super(key: key); final Widget child; @@ -88,9 +89,9 @@ class _Button extends StatelessWidget { class _TextColumn extends StatelessWidget { const _TextColumn({ - Key key, - @required this.title, - @required this.value, + Key? key, + required this.title, + required this.value, this.hasWarning = false, }) : super(key: key); diff --git a/lib/ui/pages/rootRoute.dart b/lib/ui/pages/rootRoute.dart index 8182a5c8..426c3627 100644 --- a/lib/ui/pages/rootRoute.dart +++ b/lib/ui/pages/rootRoute.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:selfprivacy/ui/components/brand_tab_bar/brand_tab_bar.dart'; import 'package:selfprivacy/ui/pages/more/more.dart'; import 'package:selfprivacy/ui/pages/providers/providers.dart'; @@ -7,7 +8,7 @@ import 'package:selfprivacy/ui/pages/services/services.dart'; import 'package:selfprivacy/ui/pages/users/users.dart'; class RootPage extends StatefulWidget { - const RootPage({Key key}) : super(key: key); + const RootPage({Key? key}) : super(key: key); @override _RootPageState createState() => _RootPageState(); @@ -15,7 +16,7 @@ class RootPage extends StatefulWidget { class _RootPageState extends State with SingleTickerProviderStateMixin { - TabController tabController; + late TabController tabController; @override void initState() { @@ -33,14 +34,17 @@ class _RootPageState extends State Widget build(BuildContext context) { return SafeArea( child: Scaffold( - body: TabBarView( - controller: tabController, - children: [ - ProvidersPage(), - ServicesPage(), - UsersPage(), - MorePage(), - ], + body: Provider( + create: (_) => ChangeTab(tabController.animateTo), + child: TabBarView( + controller: tabController, + children: [ + ProvidersPage(), + ServicesPage(), + UsersPage(), + MorePage(), + ], + ), ), bottomNavigationBar: BrandTabBar( controller: tabController, @@ -49,3 +53,9 @@ class _RootPageState extends State ); } } + +class ChangeTab { + final ValueChanged onPress; + + ChangeTab(this.onPress); +} diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart index 452f69a8..ef2284a8 100644 --- a/lib/ui/pages/services/services.dart +++ b/lib/ui/pages/services/services.dart @@ -1,18 +1,24 @@ import 'package:flutter/material.dart'; +import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/config/brand_theme.dart'; +import 'package:selfprivacy/config/text_themes.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; -import 'package:selfprivacy/logic/cubit/services/services_cubit.dart'; -import 'package:selfprivacy/logic/models/service.dart'; -import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; +import 'package:selfprivacy/logic/models/state_types.dart'; import 'package:selfprivacy/ui/components/brand_card/brand_card.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; +import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:selfprivacy/utils/route_transitions/basic.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../rootRoute.dart'; class ServicesPage extends StatefulWidget { - ServicesPage({Key key}) : super(key: key); + ServicesPage({Key? key}) : super(key: key); @override _ServicesPageState createState() => _ServicesPageState(); @@ -21,27 +27,20 @@ class ServicesPage extends StatefulWidget { class _ServicesPageState extends State { @override Widget build(BuildContext context) { - final serviceCubit = context.watch(); - final connected = serviceCubit.state.connected; - final uninitialized = serviceCubit.state.uninitialized; var isReady = context.watch().state.isFullyInitilized; return Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'Сервисы'), + child: BrandHeader(title: 'basis.services'.tr()), preferredSize: Size.fromHeight(52), ), body: ListView( padding: brandPagePadding2, children: [ - if (!isReady) NotReadyCard(), + BrandText.body1('services.title'.tr()), SizedBox(height: 24), - ...connected.map((service) => _Card(service: service)).toList(), - if (uninitialized.isNotEmpty) ...[ - BrandText.body1('не подключены'), - SizedBox(height: 30), - ], - ...uninitialized.map((service) => _Card(service: service)).toList() + if (!isReady) ...[NotReadyCard(), SizedBox(height: 24)], + ...ServiceTypes.values.map((t) => _Card(serviceType: t)).toList() ], ), ); @@ -49,67 +48,329 @@ class _ServicesPageState extends State { } class _Card extends StatelessWidget { - const _Card({Key key, @required this.service}) : super(key: key); + const _Card({Key? key, required this.serviceType}) : super(key: key); - final Service service; + final ServiceTypes serviceType; @override Widget build(BuildContext context) { String title; IconData iconData; - String description; + String subtitle; - switch (service.type) { - case ServiceTypes.messanger: - iconData = BrandIcons.messanger; - title = 'Мессенджер'; - description = - 'Delta Chat. Если бы мне надо было обсудить что-то от чего зависит жизнь. Я бы выбрал Delta.Chat + свой почтовый сервер.'; - break; + switch (serviceType) { case ServiceTypes.mail: iconData = BrandIcons.envelope; - title = 'Почта'; - description = 'Электронная почта для семьи или компании '; + title = 'services.mail.title'.tr(); + subtitle = 'services.mail.subtitle'.tr(); + break; + case ServiceTypes.messenger: + iconData = BrandIcons.messanger; + title = 'services.messenger.title'.tr(); + subtitle = 'services.messenger.subtitle'.tr(); break; case ServiceTypes.passwordManager: iconData = BrandIcons.key; - title = 'Менеджер паролей'; - description = 'Надёжное хранилище для ваших паролей и ключей доступа'; + title = 'services.password_manager.title'.tr(); + subtitle = 'services.password_manager.subtitle'.tr(); break; - case ServiceTypes.github: - iconData = BrandIcons.github; - title = 'Git сервер'; - description = 'Сервис для приватного хранения своих разработок'; + case ServiceTypes.video: + iconData = BrandIcons.webcam; + title = 'services.video.title'.tr(); + subtitle = 'services.video.subtitle'.tr(); break; - case ServiceTypes.cloud: iconData = BrandIcons.upload; - title = 'Файловое Облако'; - description = 'Сервис для доступа к вашим файлам в любой точке мира'; + title = 'services.cloud.title'.tr(); + subtitle = 'services.cloud.subtitle'.tr(); + break; + case ServiceTypes.socialNetwork: + iconData = BrandIcons.social; + title = 'services.social_network.title'.tr(); + subtitle = 'services.social_network.subtitle'.tr(); + break; + case ServiceTypes.git: + iconData = BrandIcons.git; + title = 'services.git.title'.tr(); + subtitle = 'services.git.subtitle'.tr(); break; } - return BrandCard( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - IconStatusMask( - status: service.state, - child: Icon(iconData, size: 30, color: Colors.white), - ), - SizedBox(height: 10), - BrandText.h2(title), - SizedBox(height: 10), - if (service.state == StateType.uninitialized) ...[ - BrandText.body1(description), + + var isReady = context.watch().state.isFullyInitilized; + var changeTab = context.read().onPress; + return GestureDetector( + onTap: () => showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (BuildContext context) { + return _ServiceDetails( + serviceType: serviceType, + status: isReady ? StateType.stable : StateType.uninitialized, + title: title, + icon: iconData, + changeTab: changeTab, + ); + }, + ), + child: BrandCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + IconStatusMask( + status: isReady ? StateType.stable : StateType.uninitialized, + child: Icon(iconData, size: 30, color: Colors.white), + ), + SizedBox(height: 10), + BrandText.h2(title), + SizedBox(height: 10), + BrandText.body2(subtitle), SizedBox(height: 10), - BrandButton.text( - title: 'Подключить', - onPressed: () { - context.read().connect(service); - }) ], - if (service.state == StateType.stable) BrandText.body2('Подключен'), - ], + ), ), ); } } + +enum ServiceTypes { + mail, + messenger, + passwordManager, + video, + cloud, + socialNetwork, + git, +} + +class _ServiceDetails extends StatelessWidget { + const _ServiceDetails({ + Key? key, + required this.serviceType, + required this.icon, + required this.status, + required this.title, + required this.changeTab, + }) : super(key: key); + + final ServiceTypes serviceType; + final IconData icon; + final StateType status; + final String title; + final ValueChanged changeTab; + + @override + Widget build(BuildContext context) { + late Widget child; + + var config = context.watch().state; + var domainName = config.isDomainFilled + ? config.cloudFlareDomain!.domainName! + : 'example.com'; + + var linksStyle = body1Style.copyWith( + fontSize: 15, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : BrandColors.black, + fontWeight: FontWeight.bold, + decoration: TextDecoration.underline, + // height: 1.1, + ); + + var textStyle = body1Style.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : BrandColors.black, + ); + switch (serviceType) { + case ServiceTypes.mail: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.mail.bottom_sheet.1'.tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + child: Text( + 'services.mail.bottom_sheet.2'.tr(), + style: linksStyle, + ), + onTap: () { + Navigator.of(context).pop(); + changeTab(2); + }, + ), + ), + ), + ], + )); + break; + case ServiceTypes.messenger: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.messenger.bottom_sheet.1'.tr(args: [domainName]), + style: textStyle, + ) + ], + )); + break; + case ServiceTypes.passwordManager: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.password_manager.bottom_sheet.1' + .tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + onTap: () => _launchURL('https://password.$domainName'), + child: Text( + 'password.$domainName', + style: linksStyle, + ), + ), + ), + ), + ], + )); + break; + case ServiceTypes.video: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.video.bottom_sheet.1'.tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + onTap: () => _launchURL('https://meet.$domainName'), + child: Text( + 'meet.$domainName', + style: linksStyle, + ), + ), + ), + ), + ], + )); + break; + case ServiceTypes.cloud: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.cloud.bottom_sheet.1'.tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + onTap: () => _launchURL('https://cloud.$domainName'), + child: Text( + 'cloud.$domainName', + style: linksStyle, + ), + ), + ), + ), + ], + )); + break; + case ServiceTypes.socialNetwork: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.social_network.bottom_sheet.1' + .tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + onTap: () => _launchURL('https://social_network.$domainName'), + child: Text( + 'social.$domainName', + style: linksStyle, + ), + ), + ), + ), + ], + )); + break; + case ServiceTypes.git: + child = RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'services.git.bottom_sheet.1'.tr(args: [domainName]), + style: textStyle, + ), + WidgetSpan( + child: Padding( + padding: EdgeInsets.only(bottom: 0.8, left: 5), + child: GestureDetector( + onTap: () => _launchURL('https://git.$domainName'), + child: Text( + 'git.$domainName', + style: linksStyle, + ), + ), + ), + ), + ], + )); + break; + } + return BrandModalSheet( + child: Navigator( + key: navigatorKey, + initialRoute: '/', + onGenerateRoute: (_) { + return materialRoute( + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: brandPagePadding1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 13), + IconStatusMask( + status: status, + child: Icon(icon, size: 40, color: Colors.white), + ), + SizedBox(height: 10), + BrandText.h1(title), + child, + ], + ), + ) + ], + ), + ); + }, + ), + ); + } + + void _launchURL(url) async => + await canLaunch(url) ? await launch(url) : throw 'Could not launch $url'; +} diff --git a/lib/ui/pages/users/empty.dart b/lib/ui/pages/users/empty.dart index 8f89cc6a..e9623403 100644 --- a/lib/ui/pages/users/empty.dart +++ b/lib/ui/pages/users/empty.dart @@ -1,9 +1,7 @@ part of 'users.dart'; class _NoUsers extends StatelessWidget { - const _NoUsers({Key key, @required this.text}) - : assert(text != null), - super(key: key); + const _NoUsers({Key? key, required this.text}) : super(key: key); final String text; @@ -17,7 +15,7 @@ class _NoUsers extends StatelessWidget { Icon(BrandIcons.users, size: 50, color: BrandColors.grey7), SizedBox(height: 20), BrandText.h2( - 'Здесь пока никого', + 'users.nobody_here'.tr(), style: TextStyle( color: BrandColors.grey7, ), diff --git a/lib/ui/pages/users/fab.dart b/lib/ui/pages/users/fab.dart index 7aa72227..9919381f 100644 --- a/lib/ui/pages/users/fab.dart +++ b/lib/ui/pages/users/fab.dart @@ -1,7 +1,7 @@ part of 'users.dart'; class _Fab extends StatelessWidget { - const _Fab({Key key}) : super(key: key); + const _Fab({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/pages/users/new_user.dart b/lib/ui/pages/users/new_user.dart index 6847bdf7..53636e74 100644 --- a/lib/ui/pages/users/new_user.dart +++ b/lib/ui/pages/users/new_user.dart @@ -3,13 +3,18 @@ part of 'users.dart'; class _NewUser extends StatelessWidget { @override Widget build(BuildContext context) { - final usersCubit = context.watch(); + var config = context.watch().state; + + var domainName = config.isDomainFilled + ? config.cloudFlareDomain!.domainName! + : 'example.com'; return BrandModalSheet( child: BlocProvider( - create: (context) => UserFormCubit(usersCubit: usersCubit), + create: (context) => + UserFormCubit(usersCubit: context.watch()), child: Builder(builder: (context) { - var formCubit = context.watch(); + var formCubitState = context.watch().state; return BlocListener( listener: (context, state) { @@ -20,25 +25,27 @@ class _NewUser extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BrandHeader(title: 'Новый пользователь'), + BrandHeader( + title: 'users.new_user'.tr(), + ), SizedBox(width: 14), Padding( padding: brandPagePadding2, child: Column( children: [ CubitFormTextField( - formFieldCubit: formCubit.login, + formFieldCubit: context.read().login, decoration: InputDecoration( - labelText: 'Логин', - suffixText: '@example', + labelText: 'users.login'.tr(), + suffixText: '@$domainName', ), ), SizedBox(height: 20), CubitFormTextField( - formFieldCubit: formCubit.password, + formFieldCubit: context.read().password, decoration: InputDecoration( alignLabelWithHint: false, - labelText: 'Пароль', + labelText: 'basis.password'.tr(), suffixIcon: Padding( padding: const EdgeInsets.only(right: 8), child: IconButton( @@ -46,23 +53,21 @@ class _NewUser extends StatelessWidget { BrandIcons.refresh, color: BrandColors.blue, ), - onPressed: formCubit.genNewPassword, + onPressed: + context.read().genNewPassword, ), ), ), ), SizedBox(height: 30), BrandButton.rised( - onPressed: formCubit.state.isSubmitting + onPressed: formCubitState.isSubmitting ? null - : () { - formCubit.trySubmit(); - }, - title: 'Создать', + : () => context.read().trySubmit(), + title: 'basis.create'.tr(), ), SizedBox(height: 40), - Text( - 'Новый пользователь автоматически получит доступ ко всем сервисам. Ещё какое-то описание.'), + Text('users.new_user_info_note'.tr()), SizedBox(height: 30), ], ), diff --git a/lib/ui/pages/users/user.dart b/lib/ui/pages/users/user.dart index 8084969d..f01a362a 100644 --- a/lib/ui/pages/users/user.dart +++ b/lib/ui/pages/users/user.dart @@ -1,9 +1,9 @@ part of 'users.dart'; class _User extends StatelessWidget { - const _User({Key key, this.user}) : super(key: key); + const _User({Key? key, this.user}) : super(key: key); - final User user; + final User? user; @override Widget build(BuildContext context) { return InkWell( @@ -26,12 +26,12 @@ class _User extends StatelessWidget { width: 17, height: 17, decoration: BoxDecoration( - color: user.color, + color: user!.color, shape: BoxShape.circle, ), ), SizedBox(width: 20), - BrandText.h4(user.login), + BrandText.h4(user!.login), ], ), ), diff --git a/lib/ui/pages/users/user_details.dart b/lib/ui/pages/users/user_details.dart index 80b4de68..99f43315 100644 --- a/lib/ui/pages/users/user_details.dart +++ b/lib/ui/pages/users/user_details.dart @@ -2,14 +2,20 @@ part of 'users.dart'; class _UserDetails extends StatelessWidget { const _UserDetails({ - Key key, + Key? key, this.user, }) : super(key: key); - final User user; + final User? user; @override Widget build(BuildContext context) { + var config = context.watch().state; + + var domainName = config.isDomainFilled + ? config.cloudFlareDomain!.domainName! + : 'example.com'; + return BrandModalSheet( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -17,7 +23,7 @@ class _UserDetails extends StatelessWidget { Container( height: 200, decoration: BoxDecoration( - color: user.color, + color: user!.color, borderRadius: BorderRadius.vertical( top: Radius.circular(20), ), @@ -42,26 +48,28 @@ class _UserDetails extends StatelessWidget { break; case PopupMenuItemType.delete: showDialog( - context: context, - child: AlertDialog( - title: Text('Подтверждение '), + context: context, + builder: (context) { + return AlertDialog( + title: Text('basis.confirmation'.tr()), content: SingleChildScrollView( child: ListBody( children: [ - Text('удалить учетную запись?'), + Text('users.delete_confirm_question' + .tr()), ], ), ), actions: [ TextButton( - child: Text('Отменить'), + child: Text('basis.cancel'.tr()), onPressed: () { Navigator.of(context)..pop(); }, ), TextButton( child: Text( - 'Удалить', + 'basis.delete'.tr(), style: TextStyle( color: BrandColors.red1, ), @@ -72,7 +80,9 @@ class _UserDetails extends StatelessWidget { }, ), ], - )); + ); + }, + ); break; } }, @@ -82,7 +92,7 @@ class _UserDetails extends StatelessWidget { value: PopupMenuItemType.reset, child: Container( padding: EdgeInsets.only(left: 5), - child: Text('Сбросить пароль'), + child: Text('users.reset_password'.tr()), ), ), PopupMenuItem( @@ -90,7 +100,7 @@ class _UserDetails extends StatelessWidget { child: Container( padding: EdgeInsets.only(left: 5), child: Text( - 'Удалить', + 'basis.delete'.tr(), style: TextStyle(color: BrandColors.red1), ), ), @@ -106,7 +116,7 @@ class _UserDetails extends StatelessWidget { horizontal: 15, ), child: BrandText.h1( - user.login, + user!.login, softWrap: true, overflow: TextOverflow.ellipsis, )), @@ -119,32 +129,28 @@ class _UserDetails extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BrandText.small('Учетная запись'), + BrandText.small('users.account'.tr()), Container( height: 40, alignment: Alignment.centerLeft, - child: BrandText.h4('${user.login}@example.com'), + child: BrandText.h4('${user!.login}@$domainName'), ), SizedBox(height: 14), - BrandText.small('Пароль'), + BrandText.small('basis.password'.tr()), Container( height: 40, alignment: Alignment.centerLeft, - child: BrandText.h4(user.password), + child: BrandText.h4(user!.password), ), SizedBox(height: 24), BrandDivider(), SizedBox(height: 20), BrandButton.iconText( - title: 'Отправить реквизиты для входа', + title: 'users.send_regisration_data'.tr(), icon: Icon(BrandIcons.share), onPressed: () {}, ), SizedBox(height: 20), - BrandDivider(), - SizedBox(height: 20), - Text( - 'Вам был создан доступ к сервисам с логином и паролем к сервисам:- E-mail с адресом - Менеджер паролей: - Файловое облако: - Видеоконференция - Git сервер '), ], ), ) diff --git a/lib/ui/pages/users/users.dart b/lib/ui/pages/users/users.dart index c7f6ba88..8acb4016 100644 --- a/lib/ui/pages/users/users.dart +++ b/lib/ui/pages/users/users.dart @@ -13,6 +13,7 @@ import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; +import 'package:easy_localization/easy_localization.dart'; part 'fab.dart'; part 'new_user.dart'; @@ -21,14 +22,14 @@ part 'user.dart'; part 'empty.dart'; class UsersPage extends StatelessWidget { - const UsersPage({Key key}) : super(key: key); + const UsersPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final usersCubit = context.watch(); + final usersCubitState = context.watch().state; var isReady = context.watch().state.isFullyInitilized; - final users = usersCubit.state.users; - final isEmpty = usersCubit.state.isEmpty; + final users = usersCubitState.users; + final isEmpty = usersCubitState.isEmpty; Widget child; @@ -39,7 +40,7 @@ class UsersPage extends StatelessWidget { ? Container( alignment: Alignment.center, child: _NoUsers( - text: 'Добавьте первого пользователя', + text: 'users.add_new_user'.tr(), ), ) : ListView( @@ -51,7 +52,7 @@ class UsersPage extends StatelessWidget { return Scaffold( appBar: PreferredSize( - child: BrandHeader(title: 'Пользователи'), + child: BrandHeader(title: 'basis.users'.tr()), preferredSize: Size.fromHeight(52), ), floatingActionButton: isReady ? _Fab() : null, @@ -72,8 +73,7 @@ class UsersPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 15), child: Center( child: _NoUsers( - text: - 'Подключите сервер, домен и DNS в разеде Провайдеры, чтобы добавить первого пользователя', + text: 'users.not_ready'.tr(), ), ), ), diff --git a/lib/utils/extensions/elevation_extension.dart b/lib/utils/extensions/elevation_extension.dart index 5732c8f9..8be106fa 100644 --- a/lib/utils/extensions/elevation_extension.dart +++ b/lib/utils/extensions/elevation_extension.dart @@ -8,14 +8,14 @@ extension ElevationExtension on BoxDecoration { BoxDecoration get ev8 => copyWith(boxShadow: [shadow8]); BoxDecoration copyWith({ - Color color, - DecorationImage image, - BoxBorder border, - BorderRadiusGeometry borderRadius, - List boxShadow, - Gradient gradient, - BlendMode backgroundBlendMode, - BoxShape shape, + Color? color, + DecorationImage? image, + BoxBorder? border, + BorderRadiusGeometry? borderRadius, + List? boxShadow, + Gradient? gradient, + BlendMode? backgroundBlendMode, + BoxShape? shape, }) { return BoxDecoration( color: color ?? this.color, diff --git a/lib/utils/password_generator.dart b/lib/utils/password_generator.dart index 6b3e9098..a0ce6273 100644 --- a/lib/utils/password_generator.dart +++ b/lib/utils/password_generator.dart @@ -12,10 +12,10 @@ String genPass() { ///The password [_generatedValue] is of a specified length, including letters [_letterGen] of mixed cases, ///numbers [_numGen], and symbols[_symGen] depending on user choice. class PasswordGenerator { - bool _letterGen; - bool _numGen; - bool _symGen; - String _generatedValue; + late bool _letterGen; + late bool _numGen; + late bool _symGen; + late String _generatedValue; ///Constructor. /// @@ -43,7 +43,7 @@ class PasswordGenerator { ///'Randomly' selectes caracter type to generate and append [toAppend] to [_generatedValue] // ignore: unnecessary_statements for (n; n > 0; n--) { - String toAppend; + String? toAppend; var random = new Random(); ///loops until a valid character is generated, meaning the user has to check the character value @@ -67,7 +67,7 @@ class PasswordGenerator { ///Generates a letter when called. String _generateLetter() { - if (!_letterGen) return null; + if (!_letterGen) return ''; ///Finds the integer value for the range between a-z and A-Z, with [base] UTF-16 value for lowercase letters and ///[baseUpper] UTF-16 value for uppercase letters @@ -87,7 +87,7 @@ class PasswordGenerator { } ///Generates a number when called - String _generateNumber() { + String? _generateNumber() { if (!_numGen) return null; ///Finds the integer value for the range between 0-9 @@ -101,7 +101,7 @@ class PasswordGenerator { } ///Generates a symbol when called - String _generateSymbol() { + String? _generateSymbol() { if (!_symGen) return null; ///Finds the integer value for the range between symbols !-. diff --git a/lib/utils/route_transitions/slide_bottom.dart b/lib/utils/route_transitions/slide_bottom.dart index 115831f5..607ab105 100644 --- a/lib/utils/route_transitions/slide_bottom.dart +++ b/lib/utils/route_transitions/slide_bottom.dart @@ -37,7 +37,7 @@ class SlideBottomRoute extends PageRouteBuilder { SlideBottomRoute(this.widget) : super( pageBuilder: pageBuilder(widget), - transitionsBuilder: transitionsBuilder, + transitionsBuilder: transitionsBuilder as Widget Function(BuildContext, Animation, Animation, Widget), ); final Widget widget; diff --git a/lib/utils/route_transitions/slide_right.dart b/lib/utils/route_transitions/slide_right.dart index 603b6bd0..ae9129e7 100644 --- a/lib/utils/route_transitions/slide_right.dart +++ b/lib/utils/route_transitions/slide_right.dart @@ -37,7 +37,7 @@ class SlideRightRoute extends PageRouteBuilder { SlideRightRoute(this.widget) : super( pageBuilder: pageBuilder(widget), - transitionsBuilder: transitionsBuilder, + transitionsBuilder: transitionsBuilder as Widget Function(BuildContext, Animation, Animation, Widget), ); final Widget widget; diff --git a/pubspec.lock b/pubspec.lock index 7dd044ad..088143aa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,63 +7,63 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "12.0.0" + version: "14.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.40.6" + version: "0.41.2" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "3.1.2" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "2.0.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" basic_utils: dependency: "direct dev" description: name: basic_utils url: "https://pub.dartlang.org" source: hosted - version: "2.7.0-rc.4" + version: "3.0.0-nullsafety.1" bloc: dependency: transitive description: name: bloc url: "https://pub.dartlang.org" source: hosted - version: "6.1.1" + version: "7.0.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" build: dependency: transitive description: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "1.6.2" build_config: dependency: transitive description: @@ -77,28 +77,28 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.10" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.5.1" + version: "1.5.3" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.10.11" + version: "1.11.5" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.5" + version: "6.1.10" built_collection: dependency: transitive description: @@ -119,14 +119,14 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" checked_yaml: dependency: transitive description: @@ -147,7 +147,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" code_builder: dependency: transitive description: @@ -161,119 +161,112 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "3.0.0" coverage: dependency: transitive description: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.15.2" crypto: dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.2" + version: "3.0.0" cubit_form: dependency: "direct main" description: name: cubit_form url: "https://pub.dartlang.org" source: hosted - version: "0.0.16" + version: "1.0.0-nullsafety.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "1.3.10" - dartx: - dependency: transitive - description: - name: dartx - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.0" + version: "1.3.12" dio: dependency: "direct main" description: name: dio url: "https://pub.dartlang.org" source: hosted - version: "3.0.10" + version: "4.0.0-prev1" easy_localization: dependency: "direct main" description: name: easy_localization url: "https://pub.dartlang.org" source: hosted - version: "2.3.3" + version: "3.0.0" + easy_logger: + dependency: transitive + description: + name: easy_logger + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2" either_option: dependency: "direct main" description: name: either_option url: "https://pub.dartlang.org" source: hosted - version: "1.0.6" + version: "2.0.1-dev.1" email_validator: dependency: transitive description: name: email_validator url: "https://pub.dartlang.org" source: hosted - version: "1.0.6" + version: "2.0.1" equatable: dependency: "direct main" description: name: equatable url: "https://pub.dartlang.org" source: hosted - version: "1.2.5" + version: "2.0.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" fixnum: dependency: transitive description: @@ -292,26 +285,33 @@ packages: name: flutter_bloc url: "https://pub.dartlang.org" source: hosted - version: "6.1.1" + version: "7.0.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.8.1" + version: "0.9.0" flutter_localizations: dependency: transitive description: flutter source: sdk version: "0.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.0" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "3.3.5" + version: "4.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -328,21 +328,14 @@ packages: name: get_it url: "https://pub.dartlang.org" source: hosted - version: "5.0.4" + version: "6.0.0" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" + version: "2.0.0" graphs: dependency: transitive description: @@ -356,35 +349,21 @@ packages: name: hive url: "https://pub.dartlang.org" source: hosted - version: "1.4.4+1" + version: "2.0.0" hive_flutter: dependency: "direct main" description: name: hive_flutter url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" - hive_generator: - dependency: "direct dev" - description: - name: hive_generator - url: "https://pub.dartlang.org" - source: hosted - version: "0.8.2" - html: - dependency: transitive - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.0+4" + version: "1.0.0" http: dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_multi_server: dependency: transitive description: @@ -398,28 +377,21 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" image: dependency: transitive description: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.19" - import_js_library: - dependency: transitive - description: - name: import_js_library - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" + version: "3.0.1" intl: dependency: transitive description: name: intl url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "0.17.0" io: dependency: transitive description: @@ -433,49 +405,56 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3-nullsafety.2" + version: "0.6.3" json_annotation: dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "3.1.1" + version: "4.0.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "3.5.1" + version: "4.0.2" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "0.11.4" + version: "1.0.0" + markdown: + dependency: transitive + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" mask_text_input_formatter: dependency: transitive description: name: mask_text_input_formatter url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "2.0.0-nullsafety.2" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" mime: dependency: transitive description: @@ -489,21 +468,7 @@ packages: name: nested url: "https://pub.dartlang.org" source: hosted - version: "0.0.4" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" + version: "1.0.0" node_preamble: dependency: transitive description: @@ -524,105 +489,105 @@ packages: name: package_info url: "https://pub.dartlang.org" source: hosted - version: "0.4.3+2" + version: "2.0.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" path_provider: dependency: transitive description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.24" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+6" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.2" + version: "1.11.0" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "4.0.2" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" pointycastle: dependency: transitive description: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "3.0.0-nullsafety.2" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0-nullsafety.2" + version: "1.5.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.1.0" provider: dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" source: hosted - version: "4.3.2+2" + version: "5.0.0" pub_semver: dependency: transitive description: @@ -650,49 +615,49 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.12+4" + version: "2.0.5" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.2+4" + version: "2.0.0" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+11" + version: "2.0.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.2+7" + version: "2.0.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+3" + version: "2.0.0" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "0.7.9" + version: "1.1.0" shelf_packages_handler: dependency: transitive description: @@ -713,14 +678,7 @@ packages: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "0.2.3" - shortuuid: - dependency: transitive - description: - name: shortuuid - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" + version: "0.2.4+1" sky_engine: dependency: transitive description: flutter @@ -732,42 +690,42 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+1" + version: "0.9.10+3" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.10-nullsafety.2" + version: "0.10.10" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" stream_transform: dependency: transitive description: @@ -781,42 +739,35 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test: dependency: transitive description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.16.0-nullsafety.5" + version: "1.16.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.12-nullsafety.5" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.0" + version: "0.3.15" timing: dependency: transitive description: @@ -830,63 +781,56 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" url_launcher: dependency: "direct main" description: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.7.10" + version: "6.0.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+4" + version: "2.0.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+9" + version: "2.0.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.9" + version: "2.0.2" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.5+1" + version: "2.0.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+3" - uuid: - dependency: transitive - description: - name: uuid - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.2" + version: "2.0.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" vm_service: dependency: transitive description: @@ -900,21 +844,35 @@ packages: name: wakelock url: "https://pub.dartlang.org" source: hosted - version: "0.2.1+1" + version: "0.5.0+2" + wakelock_macos: + dependency: transitive + description: + name: wakelock_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "0.1.0+1" + version: "0.2.0" wakelock_web: dependency: transitive description: name: wakelock_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.0+3" + version: "0.2.0" + wakelock_windows: + dependency: transitive + description: + name: wakelock_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" watcher: dependency: transitive description: @@ -928,7 +886,7 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" webkit_inspection_protocol: dependency: transitive description: @@ -942,28 +900,28 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.4" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "4.5.1" + version: "5.0.2" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.1.0" sdks: - dart: ">=2.10.0 <2.11.0" - flutter: ">=1.22.0 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0c8e4179..b891badd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,38 +4,38 @@ publish_to: 'none' version: 0.1.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' + flutter: ">=2.0.0" dependencies: flutter: sdk: flutter - crypto: ^2.1.5 - cubit_form: ^0.0.16 - cupertino_icons: ^1.0.0 - dio: ^3.0.10 - easy_localization: ^2.3.3 - either_option: ^1.0.6 - equatable: ^1.2.5 - flutter_bloc: ^6.1.1 - flutter_secure_storage: ^3.3.5 - get_it: ^5.0.4 - google_fonts: ^1.1.1 - hive: ^1.4.4+1 - hive_flutter: ^0.3.1 - json_annotation: ^3.1.1 - package_info: ^0.4.3+2 - provider: ^4.3.2+2 - url_launcher: ^5.7.10 - wakelock: ^0.2.1+1 + crypto: ^3.0.0 + cubit_form: ^1.0.0-nullsafety.0 + cupertino_icons: ^1.0.2 + dio: ^4.0.0-beta7 + easy_localization: ^3.0.0 + either_option: ^2.0.1-dev.1 + equatable: ^2.0.0 + flutter_bloc: ^7.0.0-nullsafety.5 + flutter_markdown: ^0.6.0 + flutter_secure_storage: ^4.1.0 + get_it: ^6.0.0 + hive: ^2.0.0 + hive_flutter: ^1.0.0 + json_annotation: ^4.0.0 + package_info: ^2.0.0 + provider: ^5.0.0 + url_launcher: ^6.0.2 + wakelock: ^0.5.0+2 dev_dependencies: flutter_test: sdk: flutter - basic_utils: ^2.6.3 - build_runner: ^1.10.11 - flutter_launcher_icons: ^0.8.1 - hive_generator: ^0.8.2 - json_serializable: ^3.5.1 + basic_utils: ^3.0.0-nullsafety.1 + build_runner: ^1.11.5 + flutter_launcher_icons: ^0.9.0 + json_serializable: ^4.0.2 flutter_icons: android: "launcher_icon" @@ -50,7 +50,19 @@ flutter: - assets/images/onboarding/ - assets/images/logos/ - assets/translations/ + - assets/markdown/ fonts: - family: BrandIcons fonts: - asset: assets/fonts/BrandIcons.ttf + - family: Inter + fonts: + - asset: assets/fonts/Inter-Regular.ttf + - asset: assets/fonts/Inter-Medium.ttf + weight: 500 + - asset: assets/fonts/Inter-SemiBold.ttf + weight: 600 + - asset: assets/fonts/Inter-Bold.ttf + weight: 700 + - asset: assets/fonts/Inter-ExtraBold.ttf + weight: 800