From 8622ed30f18cb05d91f659eb4b9be94c5a55c4ba Mon Sep 17 00:00:00 2001 From: Inex Code Date: Thu, 23 Dec 2021 13:52:12 +0000 Subject: [PATCH] Add more instructions to UI --- assets/markdown/how_backblaze-en.md | 6 ++ assets/markdown/how_backblaze-ru.md | 6 ++ assets/markdown/how_cloudflare-en.md | 15 +++++ assets/markdown/how_cloudflare-ru.md | 13 +++++ assets/markdown/how_hetzner-en.md | 1 + assets/translations/en.json | 7 +++ assets/translations/ru.json | 7 +++ lib/logic/common_enum/common_enum.dart | 40 ++++++++++++++ lib/logic/cubit/backups/backups_cubit.dart | 4 +- lib/ui/pages/initializing/initializing.dart | 46 ++++++---------- lib/ui/pages/services/services.dart | 61 +++++++++++++++------ lib/ui/pages/users/user_details.dart | 5 +- 12 files changed, 162 insertions(+), 49 deletions(-) create mode 100644 assets/markdown/how_backblaze-en.md create mode 100644 assets/markdown/how_backblaze-ru.md create mode 100644 assets/markdown/how_cloudflare-en.md create mode 100644 assets/markdown/how_cloudflare-ru.md diff --git a/assets/markdown/how_backblaze-en.md b/assets/markdown/how_backblaze-en.md new file mode 100644 index 00000000..64946c3b --- /dev/null +++ b/assets/markdown/how_backblaze-en.md @@ -0,0 +1,6 @@ +### How to get Backblaze API Token +1. Visit the following link and authorize: https://secure.backblaze.com/user_signin.htm +2. On the left side of the interface, select **App Keys** in the **B2 Cloud Storage** subcategory. +3. Click on the blue **Generate New Master Application Key** button. +4. In the appeared pop-up window confirm the generation. +5. Save _keyID_ and _applicationKey_ in the safe place. For example, in the password manager. diff --git a/assets/markdown/how_backblaze-ru.md b/assets/markdown/how_backblaze-ru.md new file mode 100644 index 00000000..87ea25b2 --- /dev/null +++ b/assets/markdown/how_backblaze-ru.md @@ -0,0 +1,6 @@ +### Как получить Backblaze API Token +1. Переходим по ссылке https://secure.backblaze.com/user_signin.htm и авторизуемся. +2. В левой части интерфейса выбираем **App Keys** в подкатегории **"Account"**. +3. Нажимаем на синюю кнопку **Generate New Master Application Key**. +4. Во всплывающем окне подтверждаем генерацию. +5. Сохраняем _keyID_ и _applicationKey_ в надёжном месте. Например в менеджере паролей. diff --git a/assets/markdown/how_cloudflare-en.md b/assets/markdown/how_cloudflare-en.md new file mode 100644 index 00000000..368ea83a --- /dev/null +++ b/assets/markdown/how_cloudflare-en.md @@ -0,0 +1,15 @@ +### How to get Cloudflare API Token +1. Visit the following link: https://dash.cloudflare.com/ +2. the right corner, click on the profile icon (a man in a circle). For the mobile version of the site, in the upper left corner, click the **Menu** button (three horizontal bars), in the dropdown menu, click on **My Profile** +3. There are four configuration categories to choose from: *Communication*, *Authentication*, **API Tokens**, *Session*. Choose **API Tokens**. +4. Click on **Create Token** button. +5. Go down to the bottom and see the **Create Custom Token** field and press **Get Started** button on the right side. +6. In the **Token Name** field, give your token a name. +7. Next we have Permissions. In the leftmost field, select **Zone**. In the longest field, center, select **DNS**. In the rightmost field, select **Edit**. +8. Next, right under this line, click Add More. Similar field will appear. +9. In the leftmost field of the new line, select, similar to the last line — **Zone**. In the center — a little different. Here choose the same as in the left — **Zone**. In the rightmost field, select **Read**. +10. Next look at **Zone Resources**. Under this inscription there is a line with two fields. The left must have **Include** and the right must have **Specific Zone**. Once you select Specific Zone, another field appears on the right. Choose your domain in it. +11. Flick to the bottom and press the blue **Continue to Summary** button. +12. Check if you got everything right. A similar string must be present: *Domain — DNS:Edit, Zone:Read*. +13. Click on **Create Token**. +14. We copy the created token, and save it in a reliable place (preferably in the password manager). diff --git a/assets/markdown/how_cloudflare-ru.md b/assets/markdown/how_cloudflare-ru.md new file mode 100644 index 00000000..1e5da794 --- /dev/null +++ b/assets/markdown/how_cloudflare-ru.md @@ -0,0 +1,13 @@ +### Как получить Cloudflare API Token +1. Переходим по [ссылке](https://dash.cloudflare.com/) и авторизуемся в ранее созданном аккаунте. https://dash.cloudflare.com/ +В правом углу кликаем на иконку профиля (человечек в кружочке). Для мобильной версии сайта, в верхнем левом углу, нажимаем кнопку **Меню** (три горизонтальных полоски), в выпавшем меню, ищем пункт **My Profile**. +3. Нам предлагается на выбор, четыре категории настройки: **Preferences**, **Authentication**, **API Tokens**, **Sessions**. Выбираем **API Tokens**. +4. Самым первым пунктом видим кнопку **Create Token**. С полной уверенностью в себе и желанием обрести приватность, нажимаем на неё. +5. Спускаемся в самый низ и видим поле **Create Custom Token** и кнопку **Get Started** с правой стороны. Нажимаем. +6. В поле **Token Name** даём своему токену имя. Можете покреативить и отнестись к этому как к наименованию домашнего зверька :) +7. Далее, у нас **Permissions**. В первом поле выбираем Zone. Во втором поле, по центру, выбираем **DNS**. В последнем поле выбираем **Edit**. +8. Далее смотрим на **Zone Resources**. Под этой надписью есть строка с двумя полями. В первом должно быть **Include**, а во втором — **Specific Zone**. Как только Вы выберите **Specific Zone**, справа появится ещё одно поле. В нём выбираем наш домен. +9. Листаем в самый низ и нажимаем на синюю кнопку **Continue to Summary**. +10. Проверяем, всё ли мы правильно выбрали. Должна присутствовать подобная строка: ваш.домен — **DNS:Edit, Zone:Read**. +11. Нажимаем **Create Token**. +12. Копируем созданный токен, и сохраняем его в надёжном месте (желательно — в менеджере паролей). diff --git a/assets/markdown/how_hetzner-en.md b/assets/markdown/how_hetzner-en.md index 47042903..87303fd6 100644 --- a/assets/markdown/how_hetzner-en.md +++ b/assets/markdown/how_hetzner-en.md @@ -1,3 +1,4 @@ +### How to get Hetzner API Token 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, diff --git a/assets/translations/en.json b/assets/translations/en.json index e86ffa84..8675c86e 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -127,6 +127,7 @@ "mail": { "title": "E-Mail", "subtitle": "E-Mail for company and family.", + "login_info": "Use username and password from users tab. IMAP port is 143 with STARTTLS, SMTP port is 587 with STARTTLS.", "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" @@ -135,6 +136,7 @@ "messenger": { "title": "Messenger", "subtitle": "Telegram or Signal not so private as Delta.Chat that uses your private server.", + "login_info": "Use the same username and password as for e-mail.", "bottom_sheet": { "1": "For connection, please use {} domain and credentials that you created." } @@ -142,6 +144,7 @@ "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.", + "login_info": "You will have to create an account on the website.", "bottom_sheet": { "1": "You can connect to the service and create a user via this link:" } @@ -149,6 +152,7 @@ "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.", + "login_info": "No account needed.", "bottom_sheet": { "1": "Using Jitsi as simple as just visiting this link:" } @@ -156,6 +160,7 @@ "cloud": { "title": "Cloud Storage", "subtitle": "Do not allow cloud services to read your data by using NextCloud.", + "login_info": "Login is admin, password is the same as with your main user. Create new accounts in Nextcloud interface.", "bottom_sheet": { "1": "You can connect and create a new user here:" } @@ -163,6 +168,7 @@ "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.", + "login_info": "You will have to create an account on the website.", "bottom_sheet": { "1": "You can connect and create new social user here:" } @@ -170,6 +176,7 @@ "git": { "title": "Git Server", "subtitle": "Private alternative to the Github, that belongs to you, but not a Microsoft.", + "login_info": "You will have to create an account on the website. First user will become an admin.", "bottom_sheet": { "1": "You can connect and create a new user here:" } diff --git a/assets/translations/ru.json b/assets/translations/ru.json index fce1a125..a9b23e07 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -128,6 +128,7 @@ "mail": { "title": "Почта", "subtitle": "Электронная почта для семьи или компании.", + "login_info": "Используйте логин и пароль из вкладки пользователей. IMAP порт: 143, STARTTLS. SMTP порт: 587, STARTTLS.", "bottom_sheet": { "1": "Для подключения почтового ящика используйте {} и профиль, который Вы создали. Так же приглашайте", "2": "новых пользователей." @@ -136,6 +137,7 @@ "messenger": { "title": "Мессенджер", "subtitle": "Telegram и Signal не так приватны, как Delta.Chat — он использует Ваш личный сервер.", + "login_info": "Используйте те же логин и пароль, что и для почты.", "bottom_sheet": { "1": "Для подключения используйте {} и логин пароль, который Вы создали." } @@ -143,6 +145,7 @@ "password_manager": { "title": "Менеджер паролей", "subtitle": "Это фундамент Вашей безопасности. Создавать, хранить, копировать пароли между устройствами и вбивать их в формы поможет Bitwarden.", + "login_info": "Аккаунт нужно создать на сайте.", "bottom_sheet": { "1": "Подключиться к серверу и создать пользователя можно по адресу:." } @@ -150,6 +153,7 @@ "video": { "title": "Видеоконференция", "subtitle": "Jitsi meet — отличный аналог Zoom и Google meet который помимо удобства ещё и гарантирует Вам защищённые высококачественные видеоконференции.", + "login_info": "Аккаунт не требуется.", "bottom_sheet": { "1": "Для использования просто перейдите по ссылке:." } @@ -157,6 +161,7 @@ "cloud": { "title": "Файловое облако", "subtitle": "Не позволяйте облачным сервисам просматривать ваши данные. Используйте NextCloud — надёжный дом для всех Ваших данных.", + "login_info": "Логин администратора: admin, пароль такой же как у основного пользователя. Создавайте новых пользователей в интерфейсе администратора NextCloud.", "bottom_sheet": { "1": "Подключиться к серверу и создать пользователя можно по адресу:." } @@ -164,6 +169,7 @@ "social_network": { "title": "Социальная сеть", "subtitle": "Сложно поверить, но стало возможным создать свою собственную социальную сеть, со своими правилами и аудиторией.", + "login_info": "Аккаунт нужно создать на сайте.", "bottom_sheet": { "1": "Подключиться к серверу и создать пользователя можно по адресу:." } @@ -171,6 +177,7 @@ "git": { "title": "Git-сервер", "subtitle": "Приватная альтернатива Github, которая принадлежит вам, а не Microsoft.", + "login_info": "Аккаунт нужно создать на сайте. Первый зарегистрированный пользователь становится администратором.", "bottom_sheet": { "1": "Подключиться к серверу и создать пользователя можно по адресу:." } diff --git a/lib/logic/common_enum/common_enum.dart b/lib/logic/common_enum/common_enum.dart index e3d81309..9903f304 100644 --- a/lib/logic/common_enum/common_enum.dart +++ b/lib/logic/common_enum/common_enum.dart @@ -69,6 +69,46 @@ extension ServiceTypesExt on ServiceTypes { } } + String get loginInfo { + switch (this) { + case ServiceTypes.mail: + return 'services.mail.login_info'.tr(); + case ServiceTypes.messenger: + return 'services.messenger.login_info'.tr(); + case ServiceTypes.passwordManager: + return 'services.password_manager.login_info'.tr(); + case ServiceTypes.video: + return 'services.video.login_info'.tr(); + case ServiceTypes.cloud: + return 'services.cloud.login_info'.tr(); + case ServiceTypes.socialNetwork: + return 'services.social_network.login_info'.tr(); + case ServiceTypes.git: + return 'services.git.login_info'.tr(); + case ServiceTypes.vpn: + return ''; + } + } + + String get subdomain { + switch (this) { + case ServiceTypes.passwordManager: + return 'password'; + case ServiceTypes.video: + return 'meet'; + case ServiceTypes.cloud: + return 'cloud'; + case ServiceTypes.socialNetwork: + return 'social'; + case ServiceTypes.git: + return 'git'; + case ServiceTypes.vpn: + case ServiceTypes.messenger: + default: + return ''; + } + } + IconData get icon { switch (this) { case ServiceTypes.mail: diff --git a/lib/logic/cubit/backups/backups_cubit.dart b/lib/logic/cubit/backups/backups_cubit.dart index 7fb42ed3..16a90e54 100644 --- a/lib/logic/cubit/backups/backups_cubit.dart +++ b/lib/logic/cubit/backups/backups_cubit.dart @@ -6,6 +6,7 @@ import 'package:selfprivacy/logic/models/backblaze_bucket.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/api_maps/server.dart'; import 'package:selfprivacy/logic/api_maps/backblaze.dart'; +import 'package:easy_localization/easy_localization.dart'; part 'backups_state.dart'; @@ -151,7 +152,8 @@ class BackupsCubit extends AppConfigDependendCubit { Future forceUpdateBackups() async { emit(state.copyWith(preventActions: true)); await api.forceBackupListReload(); - getIt().showSnackBar('providers.backup.refetchingList'); + getIt() + .showSnackBar('providers.backup.refetchingList'.tr()); emit(state.copyWith(preventActions: false)); } diff --git a/lib/ui/pages/initializing/initializing.dart b/lib/ui/pages/initializing/initializing.dart index 4ab27eec..6e90e723 100644 --- a/lib/ui/pages/initializing/initializing.dart +++ b/lib/ui/pages/initializing/initializing.dart @@ -137,7 +137,8 @@ class InitializingPage extends StatelessWidget { ), SizedBox(height: 10), BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), + onPressed: () => + _showModal(context, _HowTo(fileName: 'how_hetzner')), title: 'initializing.how'.tr(), ), ], @@ -192,7 +193,11 @@ class InitializingPage extends StatelessWidget { ), SizedBox(height: 10), BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), + onPressed: () => _showModal( + context, + _HowTo( + fileName: 'how_cloudflare', + )), title: 'initializing.how'.tr(), ), ], @@ -243,7 +248,11 @@ class InitializingPage extends StatelessWidget { ), SizedBox(height: 10), BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), + onPressed: () => _showModal( + context, + _HowTo( + fileName: 'how_backblaze', + )), title: 'initializing.how'.tr(), ), ], @@ -336,11 +345,6 @@ class InitializingPage extends StatelessWidget { ], SizedBox(height: 10), Spacer(), - SizedBox(height: 10), - BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), - title: 'initializing.how'.tr(), - ), ], ); }), @@ -403,11 +407,6 @@ class InitializingPage extends StatelessWidget { : () => context.read().trySubmit(), text: 'basis.connect'.tr(), ), - SizedBox(height: 10), - BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), - title: 'initializing.how'.tr(), - ), ], ); }), @@ -431,11 +430,6 @@ class InitializingPage extends StatelessWidget { : () => appConfigCubit.createServerAndSetDnsRecords(), text: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(), ), - Spacer(flex: 2), - BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), - title: 'initializing.what'.tr(), - ), ], ); }); @@ -482,13 +476,6 @@ class InitializingPage extends StatelessWidget { ], ), if (state.isLoading) BrandText.body2('initializing.17'.tr()), - Spacer( - flex: 2, - ), - BrandButton.text( - onPressed: () => _showModal(context, _HowHetzner()), - title: 'initializing.what'.tr(), - ), ], ); }); @@ -503,11 +490,14 @@ class InitializingPage extends StatelessWidget { } } -class _HowHetzner extends StatelessWidget { - const _HowHetzner({ +class _HowTo extends StatelessWidget { + const _HowTo({ Key? key, + required this.fileName, }) : super(key: key); + final String fileName; + @override Widget build(BuildContext context) { return BrandBottomSheet( @@ -515,7 +505,7 @@ class _HowHetzner extends StatelessWidget { child: Padding( padding: paddingH15V0, child: BrandMarkdown( - fileName: 'how_hetzner', + fileName: fileName, ), ), ); diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart index e627a1b6..410d5048 100644 --- a/lib/ui/pages/services/services.dart +++ b/lib/ui/pages/services/services.dart @@ -38,6 +38,23 @@ class ServicesPage extends StatefulWidget { _ServicesPageState createState() => _ServicesPageState(); } +void _launchURL(url) async { + var _possible = await canLaunch(url); + + if (_possible) { + try { + await launch( + url, + enableJavaScript: true, + ); + } catch (e) { + print(e); + } + } else { + throw 'Could not launch $url'; + } +} + class _ServicesPageState extends State { @override Widget build(BuildContext context) { @@ -94,6 +111,9 @@ class _Card extends StatelessWidget { (!switchableServices.contains(serviceType) || serviceState.isEnableByType(serviceType)); + var config = context.watch().state; + var domainName = UiHelpers.getDomainName(config); + return GestureDetector( onTap: isSwithOn ? () => showDialog( @@ -163,6 +183,30 @@ class _Card extends StatelessWidget { SizedBox(height: 10), BrandText.h2(serviceType.title), SizedBox(height: 10), + if (serviceType.subdomain != '') + Column( + children: [ + GestureDetector( + onTap: () => _launchURL( + 'https://${serviceType.subdomain}.$domainName'), + child: Text( + '${serviceType.subdomain}.$domainName', + style: linkStyle, + ), + ), + SizedBox(height: 10), + ], + ), + if (serviceType == ServiceTypes.mail) + Column(children: [ + Text( + domainName, + style: linkStyle, + ), + SizedBox(height: 10), + ]), + BrandText.body2(serviceType.loginInfo), + SizedBox(height: 10), BrandText.body2(serviceType.subtitle), SizedBox(height: 10), ], @@ -438,21 +482,4 @@ class _ServiceDetails extends StatelessWidget { ), ); } - - void _launchURL(url) async { - var _possible = await canLaunch(url); - - if (_possible) { - try { - await launch( - url, - enableJavaScript: true, - ); - } catch (e) { - print(e); - } - } else { - throw 'Could not launch $url'; - } - } } diff --git a/lib/ui/pages/users/user_details.dart b/lib/ui/pages/users/user_details.dart index 52b22687..89d5d97f 100644 --- a/lib/ui/pages/users/user_details.dart +++ b/lib/ui/pages/users/user_details.dart @@ -75,9 +75,8 @@ class _UserDetails extends StatelessWidget { ), ), onPressed: () { - context - .read() - .addJob(DeleteUserJob(user: user)); + context.read().addJob( + DeleteUserJob(user: user)); Navigator.of(context) ..pop() ..pop();