fdroid
Kherel 2021-03-15 16:39:44 +01:00
parent afd569ba96
commit 0ec549042c
81 changed files with 572 additions and 486 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,3 +1,46 @@
{
"test": "en-test"
"test": "en-test",
"basis": {
"_comment": "базовые элементы интерфейса",
"providers": "Провайдеры",
"services": "Сервисы",
"users": "Пользователи",
"more": "Еще",
"next": "Далее",
"got_it": "Понял"
},
"more": {
"_comment": "Элементы на странице еще",
"configuration_wizard": "Мастер Подключения",
"settings": "Настройки приложения",
"about_project": "О проекте SelfPrivacy",
"about_app": "О приложении",
"onboarding": "Onboarding",
"console": "Console"
},
"onboarding": {
"_comment": "страницы онбординга",
"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 is 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": "вкладка провайдеры",
"page_title": "Your Data Center",
"server": {
"card_title": "Сервер"
},
"domain": {
"card_title": "Домен"
},
"backup": {
"card_title": "Резервное копирование"
}
},
"not_ready_card": {
"1": "Завершите настройку приложения используя ",
"2": "@:more.configuration_wizard",
"3": " для продолжения работы"
}
}

View File

@ -1,7 +1,47 @@
{
"test": "en-test",
"basis:": {
"_comment": "Повторяющиеся названия",
"next": "Далее"
"test": "ru-test",
"basis": {
"_comment": "базовые элементы интерфейса",
"providers": "Провайдеры",
"services": "Сервисы",
"users": "Пользователи",
"more": "Еще",
"next": "Далее",
"got_it": "Понял"
},
"more": {
"_comment": "Элементы на странице еще",
"configuration_wizard": "Мастер Подключения",
"settings": "Настройки приложения",
"about_project": "О проекте SelfPrivacy",
"about_app": "О приложении",
"onboarding": "Onboarding",
"console": "Console"
},
"onboarding": {
"_comment": "страницы онбординга",
"page1_title": "Цифровая независимость доступна каждому",
"page1_text": "Почта, VPN, Мессенджер, социальная сеть и многое другое на вашем личном сервере, под вашим полным контролем.",
"page2_title": "SelfPrivacy — это не облако, а ваш личный дата-центр",
"page2_text": "У SelfPrivacy работает только с вашими сервис-провадерами: Hetzner, Cloudflare, Backblaze. Если у вас нет учетных записей, мы поможем их создать."
},
"providers": {
"_comment": "вкладка провайдеры",
"page_title": "Ваш Дата-центр",
"server": {
"card_title": "Сервер"
},
"domain": {
"card_title": "Домен"
},
"backup": {
"card_title": "Резервное копирование"
}
},
"not_ready_card": {
"_comment": "Карточка показывающая когда человек скипнул настройку, на карте текст из 3 блоков, средний содержит ссыку на мастер подключения",
"1": "Завершите настройку приложения используя ",
"2": "@:more.configuration_wizard",
"3": " для продолжения работы"
}
}

View File

@ -45,7 +45,7 @@ SPEC CHECKSUMS:
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

View File

@ -7,9 +7,9 @@ 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) {

View File

@ -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<NavigationService>().navigator;
void onError(Bloc cubit, Object error, StackTrace stackTrace) {
final navigator = getIt.get<NavigationService>().navigator!;
navigator.push(
materialRoute(

View File

@ -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!);
}
}

View File

@ -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!,
);
}
}

View File

@ -18,9 +18,9 @@ abstract class ApiMap {
};
loggedClient = client;
}
String rootAddress;
String? rootAddress;
Dio loggedClient;
late Dio loggedClient;
void close() {
loggedClient.close();
@ -61,7 +61,7 @@ class ConsoleInterceptor extends InterceptorsWrapper {
addMessage(
Message.warn(
text:
'response-uri: ${response?.request?.uri}\ncode: ${response?.statusCode}\ndata: ${response?.toString()}\n',
'response-uri: ${response?.request.uri}\ncode: ${response?.statusCode}\ndata: ${response?.toString()}\n',
),
);
return super.onError(err);

View File

@ -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<bool> 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;

View File

@ -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<bool> isValid(String token) async {
var url = '$rootAddress/user/tokens/verify';
@ -35,7 +35,7 @@ class CloudflareApi extends ApiMap {
}
}
Future<String> getZoneId(String token, String domain) async {
Future<String?> getZoneId(String? token, String domain) async {
var url = '$rootAddress/zones';
var options = Options(
@ -59,8 +59,8 @@ class CloudflareApi extends ApiMap {
}
Future<void> 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<void> 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<DnsRecords> projectDnsRecords(String domainName, String ip4) {
List<DnsRecords> 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<List<String>> domainList() async {
Future<List<String>?> 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<String>((el) => el['name'] as String)
.map<String>((el) => el['name'] as String?)
.toList();
}
}

View File

@ -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<bool> 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<HetznerServerDetails> 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<void> 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<HetznerServerDetails> startServer({
HetznerServerDetails server,
required HetznerServerDetails server,
}) async {
await loggedClient.post('/${server.id}/actions/poweron');
@ -84,7 +83,7 @@ class HetznerApi extends ApiMap {
}
Future<HetznerServerDetails> restart({
HetznerServerDetails server,
required HetznerServerDetails server,
}) async {
await loggedClient.post('/${server.id}/actions/poweron');

View File

@ -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',
);

View File

@ -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';
@ -64,23 +63,23 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
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 +110,16 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
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 +132,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
));
timer = Timer(pauseDuration, () async {
var hetznerServerDetails = await repository.restart(
state.hetznerKey,
state.hetznerServer,
state!.hetznerKey,
state.hetznerServer!,
);
emit(
state.copyWith(
@ -165,19 +164,19 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
}
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 +237,12 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
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 +258,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
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,8 +276,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
void _closeTimer() {
if (timer != null && timer.isActive) {
timer.cancel();
if (timer != null && timer!.isActive) {
timer!.cancel();
}
}
}

View File

@ -60,7 +60,7 @@ class AppConfigRepository {
}
Future<HetznerServerDetails> 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<bool> isDnsAddressesMatch(String domainName, String ip4) async {
Future<bool> isDnsAddressesMatch(String? domainName, String? ip4) async {
print(domainName);
var addresses = <String>[
'$domainName',
@ -116,12 +116,12 @@ class AppConfigRepository {
}
Future<void> createServer(
String hetznerKey,
String? hetznerKey,
User rootUser,
String domainName,
String cloudFlareKey, {
void Function() onCancel,
Future<void> Function(HetznerServerDetails serverDetails) onSuccess,
String? domainName,
String? cloudFlareKey, {
void Function()? onCancel,
required Future<void> 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<NavigationService>();
nav.showPopUpDialog(
BrandAlert(
@ -165,7 +165,7 @@ class AppConfigRepository {
text: 'Отменить',
onPressed: () {
hetznerApi.close();
onCancel();
onCancel!();
},
),
],
@ -176,8 +176,8 @@ class AppConfigRepository {
}
Future<void> 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<bool> isHttpServerWorking(String domainName) async {
Future<bool> isHttpServerWorking(String? domainName) async {
var api = ServerApi(domainName);
var isHttpServerWorking = await api.isHttpServerWorking();
api.close();
@ -203,7 +203,7 @@ class AppConfigRepository {
}
Future<HetznerServerDetails> restart(
String hetznerKey,
String? hetznerKey,
HetznerServerDetails server,
) async {
var hetznerApi = HetznerApi(hetznerKey);

View File

@ -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<Object> get props => [
List<Object?> 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<bool> get _fulfilementList => [
List<bool?> 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<Object> get props => [
List<Object?> get props => [
dataState,
timerStart,
duration,

View File

@ -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<AppSettingsState> {
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<AppSettingsState> {
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));
}

View File

@ -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;

View File

@ -42,13 +42,14 @@ class BackblazeFormCubit extends FormCubit {
final AppConfigCubit initializingCubit;
FieldCubit<String> keyId;
FieldCubit<String> applicationKey;
// ignore: close_sinks
late final FieldCubit<String> keyId;
// ignore: close_sinks
late final FieldCubit<String> applicationKey;
@override
FutureOr<bool> asyncValidation() async {
bool isKeyValid;
late bool isKeyValid;
try {
String encodedApiKey = encodedBackblazeKey(
keyId.state.value,

View File

@ -30,11 +30,11 @@ class CloudFlareFormCubit extends FormCubit {
final AppConfigCubit initializingCubit;
FieldCubit<String> apiKey;
late final FieldCubit<String> apiKey;
@override
FutureOr<bool> asyncValidation() async {
bool isKeyValid;
late bool isKeyValid;
try {
isKeyValid = await apiClient.isValid(apiKey.state.value);

View File

@ -5,7 +5,7 @@ import 'package:selfprivacy/logic/models/cloudflare_domain.dart';
class DomainSetupCubit extends Cubit<DomainSetupState> {
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<DomainSetupState> {
}
AppConfigCubit initializingCubit;
CloudflareApi api;
late CloudflareApi api;
Future<void> load() async {
emit(Loading(LoadingTypes.loadingDomain));
var list = await api.domainList();
var list = await (api.domainList() as Future<List<String>>);
if (list.isEmpty) {
emit(Empty());
} else if (list.length == 1) {

View File

@ -30,11 +30,12 @@ class HetznerFormCubit extends FormCubit {
final AppConfigCubit initializingCubit;
FieldCubit<String> apiKey;
// ignore: close_sinks
late final FieldCubit<String> apiKey;
@override
FutureOr<bool> asyncValidation() async {
bool isKeyValid;
late bool isKeyValid;
try {
isKeyValid = await apiClient.isValid(apiKey.state.value);
} catch (e) {

View File

@ -46,9 +46,12 @@ class RootUserFormCubit extends FormCubit {
final AppConfigCubit initializingCubit;
FieldCubit<String> userName;
FieldCubit<String> password;
FieldCubit<bool> isVisible;
// ignore: close_sinks
late final FieldCubit<String> userName;
// ignore: close_sinks
late final FieldCubit<String> password;
// ignore: close_sinks
late final FieldCubit<bool> isVisible;
@override
Future<void> close() async {

View File

@ -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<String>(
@ -25,7 +25,7 @@ class UserFormCubit extends FormCubit {
);
password = FieldCubit(
initalValue: isEdit ? user.password : genPass(),
initalValue: isEdit ? user!.password : genPass(),
validations: [
RequiredStringValidation('required'),
ValidationModel<String>(
@ -42,15 +42,16 @@ class UserFormCubit extends FormCubit {
login: login.state.value,
password: password.state.value,
);
usersCubit.add(user);
usersCubit.addUser(user);
}
FieldCubit<String> login;
FieldCubit<String> password;
// ignore: close_sinks
late FieldCubit<String> login;
late FieldCubit<String> password;
void genNewPassword() {
password.externalSetValue(genPass());
}
UsersCubit usersCubit;
late UsersCubit usersCubit;
}

View File

@ -5,7 +5,7 @@ class LegnthStringValidationWithLenghShowing extends ValidationModel<String> {
: 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;

View File

@ -8,14 +8,14 @@ part 'users_state.dart';
class UsersCubit extends Cubit<UsersState> {
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);

View File

@ -3,10 +3,10 @@ import 'package:flutter/widgets.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
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,

View File

@ -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;

View File

@ -17,8 +17,8 @@ class BackblazeCredentialAdapter extends TypeAdapter<BackblazeCredential> {
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?,
);
}

View File

@ -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() {

View File

@ -17,8 +17,8 @@ class CloudFlareDomainAdapter extends TypeAdapter<CloudFlareDomain> {
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?,
);
}

View File

@ -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;

View File

@ -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,
);

View File

@ -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<Object> get props => [state, type];
List<Object?> 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;
}
}

View File

@ -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,

View File

@ -17,10 +17,10 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
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?,
);
}

View File

@ -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) {

View File

@ -10,7 +10,7 @@ enum ServiceTypes {
}
class Service extends Equatable {
const Service({this.state, this.type});
const Service({required this.state, required this.type});
final StateType state;
final ServiceTypes type;
@ -21,5 +21,5 @@ class Service extends Equatable {
);
@override
List<Object> get props => [state, type];
List<Object?> get props => [state, type];
}

View File

@ -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<Object> get props => [login, password];
List<Object?> get props => [login, password];
Color get color => stringToColor(login);

View File

@ -36,7 +36,7 @@ void main() async {
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var appSettings = context.watch<AppSettingsCubit>().state;
AppSettingsState appSettings = context.watch<AppSettingsCubit>().state;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
@ -51,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!;
},
),
);

View File

@ -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!();
},
);
}

View File

@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
class BrandAlert extends AlertDialog {
BrandAlert({
Key key,
String title,
String contentText,
List<Widget> acitons,
Key? key,
String? title,
String? contentText,
List<Widget>? acitons,
}) : super(
key: key,
title: title != null ? Text(title) : null,
content: title != null ? Text(contentText) : null,
content: title != null ? Text(contentText!) : null,
actions: acitons,
);
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -19,7 +19,7 @@ class BrandIcons {
BrandIcons._();
static const _kFontFam = 'BrandIcons';
static const _kFontPkg = null;
static const dynamic _kFontPkg = null;
static const IconData connection =
IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);

View File

@ -4,11 +4,11 @@ var navigatorKey = GlobalKey<NavigatorState>();
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(

View File

@ -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,

View File

@ -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<BrandTabBar> {
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<BrandTabBar> {
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<BrandTabBar> {
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(

View File

@ -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,
@ -99,7 +99,7 @@ class BrandText extends StatelessWidget {
);
@override
Text build(BuildContext context) {
TextStyle style;
TextStyle? style;
var isDark = Theme.of(context).brightness == Brightness.dark;
switch (type) {
@ -153,7 +153,7 @@ class BrandText extends StatelessWidget {
style = style.merge(this.style);
}
return Text(
text,
text!,
style: style,
overflow: overflow,
softWrap: softWrap,

View File

@ -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<BrandTimer> {
String _timeString;
Timer timer;
String? _timeString;
late Timer timer;
@override
void initState() {
@ -31,8 +31,8 @@ class _BrandTimerState extends State<BrandTimer> {
_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<BrandTimer> {
}
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ек";
}

View File

@ -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;

View File

@ -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) {

View File

@ -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<Color> colors;
late List<Color> colors;
switch (status) {
case StateType.uninitialized:
colors = BrandColors.uninitializedGradientColors;

View File

@ -2,9 +2,10 @@ import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.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,13 +17,13 @@ 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(
'Мастер подключения',
'not_ready_card.2'.tr(),
style: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.blueAccent
@ -38,7 +39,7 @@ class NotReadyCard extends StatelessWidget {
),
),
TextSpan(
text: ' для продолжения работы',
text: 'not_ready_card.3'.tr(),
style: TextStyle(color: BrandColors.white),
),
],

View File

@ -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<ProgressBar> {
}
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(

View File

@ -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;

View File

@ -81,7 +81,7 @@ class InitializingPage extends StatelessWidget {
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<HetznerFormCubit>();
var formCubitState = context.watch<HetznerFormCubit>().state;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -111,7 +111,7 @@ class InitializingPage extends StatelessWidget {
'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
Spacer(),
CubitFormTextField(
formFieldCubit: formCubit.apiKey,
formFieldCubit: context.read<HetznerFormCubit>().apiKey,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -120,8 +120,9 @@ class InitializingPage extends StatelessWidget {
),
Spacer(),
BrandButton.rised(
onPressed:
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
onPressed: formCubitState.isSubmitting
? null
: () => context.read<HetznerFormCubit>().trySubmit(),
title: 'Подключить',
),
SizedBox(height: 10),
@ -150,7 +151,7 @@ class InitializingPage extends StatelessWidget {
return BlocProvider(
create: (context) => CloudFlareFormCubit(initializingCubit),
child: Builder(builder: (context) {
var formCubit = context.watch<CloudFlareFormCubit>();
var formCubitState = context.watch<CloudFlareFormCubit>().state;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -165,7 +166,7 @@ class InitializingPage extends StatelessWidget {
BrandText.body2('Для управления DNS вашего домена'),
Spacer(),
CubitFormTextField(
formFieldCubit: formCubit.apiKey,
formFieldCubit: context.read<CloudFlareFormCubit>().apiKey,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -174,8 +175,9 @@ class InitializingPage extends StatelessWidget {
),
Spacer(),
BrandButton.rised(
onPressed:
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
onPressed: formCubitState.isSubmitting
? null
: () => context.read<CloudFlareFormCubit>().trySubmit(),
title: 'Подключить',
),
SizedBox(height: 10),
@ -193,7 +195,7 @@ class InitializingPage extends StatelessWidget {
return BlocProvider(
create: (context) => BackblazeFormCubit(initializingCubit),
child: Builder(builder: (context) {
var formCubit = context.watch<BackblazeFormCubit>();
var formCubitState = context.watch<BackblazeFormCubit>().state;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -206,7 +208,7 @@ class InitializingPage extends StatelessWidget {
SizedBox(height: 10),
Spacer(),
CubitFormTextField(
formFieldCubit: formCubit.keyId,
formFieldCubit: context.read<BackblazeFormCubit>().keyId,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -215,7 +217,7 @@ class InitializingPage extends StatelessWidget {
),
Spacer(),
CubitFormTextField(
formFieldCubit: formCubit.applicationKey,
formFieldCubit: context.read<BackblazeFormCubit>().applicationKey,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -224,8 +226,9 @@ class InitializingPage extends StatelessWidget {
),
Spacer(),
BrandButton.rised(
onPressed:
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
onPressed: formCubitState.isSubmitting
? null
: () => context.read<BackblazeFormCubit>().trySubmit(),
title: 'Подключить',
),
SizedBox(height: 10),
@ -243,8 +246,7 @@ class InitializingPage extends StatelessWidget {
return BlocProvider(
create: (context) => DomainSetupCubit(initializingCubit)..load(),
child: Builder(builder: (context) {
var domainSetup = context.watch<DomainSetupCubit>();
var state = domainSetup.state;
DomainSetupState state = context.watch<DomainSetupCubit>().state;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -283,7 +285,7 @@ class InitializingPage extends StatelessWidget {
Container(
width: 50,
child: BrandButton.rised(
onPressed: () => domainSetup.load(),
onPressed: () => context.read<DomainSetupCubit>().load(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
@ -302,7 +304,7 @@ class InitializingPage extends StatelessWidget {
if (state is Empty) ...[
SizedBox(height: 30),
BrandButton.rised(
onPressed: () => domainSetup.load(),
onPressed: () => context.read<DomainSetupCubit>().load(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -319,7 +321,7 @@ class InitializingPage extends StatelessWidget {
if (state is Loaded) ...[
SizedBox(height: 30),
BrandButton.rised(
onPressed: () => domainSetup.saveDomain(),
onPressed: () => context.read<DomainSetupCubit>().saveDomain(),
title: 'Сохранить домен',
),
],
@ -340,7 +342,7 @@ class InitializingPage extends StatelessWidget {
return BlocProvider(
create: (context) => RootUserFormCubit(initializingCubit),
child: Builder(builder: (context) {
var formCubit = context.watch<RootUserFormCubit>();
var formCubitState = context.watch<RootUserFormCubit>().state;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -348,7 +350,7 @@ class InitializingPage extends StatelessWidget {
Spacer(),
SizedBox(height: 10),
CubitFormTextField(
formFieldCubit: formCubit.userName,
formFieldCubit: context.read<RootUserFormCubit>().userName,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -357,12 +359,12 @@ class InitializingPage extends StatelessWidget {
),
SizedBox(height: 10),
BlocBuilder<FieldCubit<bool>, FieldCubitState<bool>>(
bloc: formCubit.isVisible,
bloc: context.read<RootUserFormCubit>().isVisible,
builder: (context, state) {
var isVisible = state.value;
return CubitFormTextField(
obscureText: !isVisible,
formFieldCubit: formCubit.password,
formFieldCubit: context.read<RootUserFormCubit>().password,
textAlign: TextAlign.center,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
@ -371,7 +373,10 @@ class InitializingPage extends StatelessWidget {
icon: Icon(
isVisible ? Icons.visibility : Icons.visibility_off,
),
onPressed: () => formCubit.isVisible.setValue(!isVisible),
onPressed: () => context
.read<RootUserFormCubit>()
.isVisible
.setValue(!isVisible),
),
suffixIconConstraints: BoxConstraints(minWidth: 60),
prefixIconConstraints: BoxConstraints(maxWidth: 85),
@ -382,8 +387,9 @@ class InitializingPage extends StatelessWidget {
),
Spacer(),
BrandButton.rised(
onPressed:
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
onPressed: formCubitState.isSubmitting
? null
: () => context.read<RootUserFormCubit>().trySubmit(),
title: 'Подключить',
),
SizedBox(height: 10),
@ -410,7 +416,7 @@ class InitializingPage extends StatelessWidget {
Spacer(),
BrandButton.rised(
onPressed:
isLoading ? null : appConfigCubit.createServerAndSetDnsRecords,
isLoading! ? null : appConfigCubit.createServerAndSetDnsRecords,
title: isLoading ? 'loading' : 'Создать сервер',
),
Spacer(flex: 2),
@ -427,10 +433,10 @@ class InitializingPage extends StatelessWidget {
assert(appConfigCubit.state is TimerState, 'wronge state');
var state = appConfigCubit.state as TimerState;
String text;
if (state.isServerReseted) {
String? text;
if (state.isServerReseted!) {
text = 'Сервер презагружен, ждем последнюю проверку';
} else if (state.isServerStarted) {
} else if (state.isServerStarted!) {
text = 'Cервер запушен, сейчас он будет проверен и перезагружен';
} else if (state.isServerCreated) {
text = 'Cервер создан, идет проверка ДНС адресов и запуск сервера';
@ -443,7 +449,7 @@ class InitializingPage extends StatelessWidget {
SizedBox(height: 10),
BrandText.body2(text),
SizedBox(height: 10),
if (!state.isLoading)
if (!state.isLoading!)
Row(
children: [
BrandText.body2('До следующей проверки: '),
@ -453,7 +459,7 @@ class InitializingPage extends StatelessWidget {
)
],
),
if (state.isLoading) BrandText.body2('Проверка'),
if (state.isLoading!) BrandText.body2('Проверка'),
Spacer(
flex: 2,
),
@ -477,7 +483,7 @@ class InitializingPage extends StatelessWidget {
class _HowHetzner extends StatelessWidget {
const _HowHetzner({
Key key,
Key? key,
}) : super(key: key);
@override

View File

@ -5,7 +5,7 @@ import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
class AboutPage extends StatelessWidget {
const AboutPage({Key key}) : super(key: key);
const AboutPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -11,7 +11,7 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/utils/named_font_weight.dart';
class AppSettingsPage extends StatefulWidget {
const AppSettingsPage({Key key}) : super(key: key);
const AppSettingsPage({Key? key}) : super(key: key);
@override
_AppSettingsPageState createState() => _AppSettingsPageState();
@ -20,9 +20,7 @@ class AppSettingsPage extends StatefulWidget {
class _AppSettingsPageState extends State<AppSettingsPage> {
@override
Widget build(BuildContext context) {
var appSettings = context.watch<AppSettingsCubit>();
var isDarkModeOn = appSettings.state.isDarkModeOn;
var isDarkModeOn = context.watch<AppSettingsCubit>().state.isDarkModeOn;
return SafeArea(
child: Builder(builder: (context) {
@ -57,8 +55,9 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
activeColor: BrandColors.green1,
activeTrackColor: BrandColors.green2,
value: Theme.of(context).brightness == Brightness.dark,
onChanged: (value) => appSettings.updateDarkMode(
isDarkModeOn: !isDarkModeOn),
onChanged: (value) => context
.read<AppSettingsCubit>()
.updateDarkMode(isDarkModeOn: !isDarkModeOn),
),
],
),
@ -130,9 +129,9 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
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);

View File

@ -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();

View File

@ -6,7 +6,7 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:package_info/package_info.dart';
class InfoPage extends StatelessWidget {
const InfoPage({Key key}) : super(key: key);
const InfoPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -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,32 +34,32 @@ class MorePage extends StatelessWidget {
children: [
BrandDivider(),
_NavItem(
title: 'Мастер Подключения',
title: 'more.configuration_wizard'.tr(),
iconData: BrandIcons.settings,
goTo: InitializingPage(),
),
_NavItem(
title: 'Настройки приложения',
title: 'more.settings'.tr(),
iconData: BrandIcons.settings,
goTo: AppSettingsPage(),
),
_NavItem(
title: 'О проекте Selfprivacy',
title: 'more.about_project'.tr(),
iconData: BrandIcons.triangle,
goTo: AboutPage(),
),
_NavItem(
title: 'О приложении',
title: 'more.about_app'.tr(),
iconData: BrandIcons.help,
goTo: InfoPage(),
),
_NavItem(
title: 'Onboarding',
title: 'more.onboarding'.tr(),
iconData: BrandIcons.triangle,
goTo: OnboardingPage(nextPage: RootPage()),
),
_NavItem(
title: 'Console',
title: 'more.console'.tr(),
iconData: BrandIcons.triangle,
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;

View File

@ -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<OnboardingPage> {
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<OnboardingPage> {
curve: Curves.easeIn,
);
},
title: 'Далее',
title: 'basis.next'.tr(),
),
SizedBox(height: 30),
],
@ -94,10 +95,9 @@ class _OnboardingPageState extends State<OnboardingPage> {
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<OnboardingPage> {
Navigator.of(context)
.pushReplacement(materialRoute(widget.nextPage));
},
title: 'Понял',
title: 'basis.got_it'.tr(),
),
SizedBox(height: 30),
],
@ -137,10 +137,10 @@ class _OnboardingPageState extends State<OnboardingPage> {
}
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;

View File

@ -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();
@ -23,7 +24,8 @@ class ProvidersPage extends StatefulWidget {
class _ProvidersPageState extends State<ProvidersPage> {
@override
Widget build(BuildContext context) {
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
// var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = true;
final cards = ProviderType.values
.map((type) => _Card(
@ -32,7 +34,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
.toList();
return Scaffold(
appBar: PreferredSize(
child: BrandHeader(title: 'Провайдеры'),
child: BrandHeader(title: 'providers.page_title'.tr()),
preferredSize: Size.fromHeight(52),
),
body: ListView(
@ -50,32 +52,31 @@ class _ProvidersPageState extends State<ProvidersPage> {
}
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<AppConfigCubit>().state;
String? title;
String? message;
String? stableText;
AppConfigState appConfig = context.watch<AppConfigCubit>().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 +117,29 @@ 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;
switch (provider.type) {
case ProviderType.server:
title = 'Сервер';
title = 'providers.server.card_title'.tr();
break;
case ProviderType.domain:
title = 'Домен';
title = 'providers.domain.card_title'.tr();
break;
case ProviderType.backup:
title = 'Резервное копирование';
title = 'providers.backup.card_title'.tr();
break;
}
return BrandModalSheet(
@ -163,7 +165,7 @@ class _ProviderDetails extends StatelessWidget {
onSelected: (_PopupMenuItemType result) {
switch (result) {
case _PopupMenuItemType.setting:
navigatorKey.currentState
navigatorKey.currentState!
.push(materialRoute(SettingsPage()));
break;
}

View File

@ -7,7 +7,7 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart';
class SettingsPage extends StatelessWidget {
const SettingsPage({Key key}) : super(key: key);
const SettingsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -62,9 +62,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 +88,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);

View File

@ -7,7 +7,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 +15,7 @@ class RootPage extends StatefulWidget {
class _RootPageState extends State<RootPage>
with SingleTickerProviderStateMixin {
TabController tabController;
TabController? tabController;
@override
void initState() {
@ -26,7 +26,7 @@ class _RootPageState extends State<RootPage>
@override
void dispose() {
super.dispose();
tabController.dispose();
tabController!.dispose();
}
@override

View File

@ -12,7 +12,7 @@ import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
class ServicesPage extends StatefulWidget {
ServicesPage({Key key}) : super(key: key);
ServicesPage({Key? key}) : super(key: key);
@override
_ServicesPageState createState() => _ServicesPageState();
@ -21,9 +21,10 @@ class ServicesPage extends StatefulWidget {
class _ServicesPageState extends State<ServicesPage> {
@override
Widget build(BuildContext context) {
final serviceCubit = context.watch<ServicesCubit>();
final connected = serviceCubit.state.connected;
final uninitialized = serviceCubit.state.uninitialized;
final serviceCubitState = context.watch<ServicesCubit>().state;
final connected = serviceCubitState.connected;
final uninitialized = serviceCubitState.uninitialized;
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
return Scaffold(
@ -49,14 +50,14 @@ class _ServicesPageState extends State<ServicesPage> {
}
class _Card extends StatelessWidget {
const _Card({Key key, @required this.service}) : super(key: key);
const _Card({Key? key, required this.service}) : super(key: key);
final Service service;
@override
Widget build(BuildContext context) {
String title;
IconData iconData;
String description;
String? title;
IconData? iconData;
String? description;
switch (service.type) {
case ServiceTypes.messanger:

View File

@ -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;

View File

@ -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) {

View File

@ -3,13 +3,12 @@ part of 'users.dart';
class _NewUser extends StatelessWidget {
@override
Widget build(BuildContext context) {
final usersCubit = context.watch<UsersCubit>();
return BrandModalSheet(
child: BlocProvider(
create: (context) => UserFormCubit(usersCubit: usersCubit),
create: (context) =>
UserFormCubit(usersCubit: context.watch<UsersCubit>()),
child: Builder(builder: (context) {
var formCubit = context.watch<UserFormCubit>();
var formCubitState = context.watch<UserFormCubit>().state;
return BlocListener<UserFormCubit, FormCubitState>(
listener: (context, state) {
@ -27,7 +26,7 @@ class _NewUser extends StatelessWidget {
child: Column(
children: [
CubitFormTextField(
formFieldCubit: formCubit.login,
formFieldCubit: context.read<UserFormCubit>().login,
decoration: InputDecoration(
labelText: 'Логин',
suffixText: '@example',
@ -35,7 +34,7 @@ class _NewUser extends StatelessWidget {
),
SizedBox(height: 20),
CubitFormTextField(
formFieldCubit: formCubit.password,
formFieldCubit: context.read<UserFormCubit>().password,
decoration: InputDecoration(
alignLabelWithHint: false,
labelText: 'Пароль',
@ -46,18 +45,17 @@ class _NewUser extends StatelessWidget {
BrandIcons.refresh,
color: BrandColors.blue,
),
onPressed: formCubit.genNewPassword,
onPressed:
context.read<UserFormCubit>().genNewPassword,
),
),
),
),
SizedBox(height: 30),
BrandButton.rised(
onPressed: formCubit.state.isSubmitting
onPressed: formCubitState.isSubmitting
? null
: () {
formCubit.trySubmit();
},
: () => context.read<UserFormCubit>().trySubmit(),
title: 'Создать',
),
SizedBox(height: 40),

View File

@ -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),
],
),
),

View File

@ -2,11 +2,11 @@ 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) {
@ -17,7 +17,7 @@ class _UserDetails extends StatelessWidget {
Container(
height: 200,
decoration: BoxDecoration(
color: user.color,
color: user!.color,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
@ -109,7 +109,7 @@ class _UserDetails extends StatelessWidget {
horizontal: 15,
),
child: BrandText.h1(
user.login,
user!.login,
softWrap: true,
overflow: TextOverflow.ellipsis,
)),
@ -126,14 +126,14 @@ class _UserDetails extends StatelessWidget {
Container(
height: 40,
alignment: Alignment.centerLeft,
child: BrandText.h4('${user.login}@example.com'),
child: BrandText.h4('${user!.login}@example.com'),
),
SizedBox(height: 14),
BrandText.small('Пароль'),
Container(
height: 40,
alignment: Alignment.centerLeft,
child: BrandText.h4(user.password),
child: BrandText.h4(user!.password),
),
SizedBox(height: 24),
BrandDivider(),

View File

@ -21,14 +21,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<UsersCubit>();
final usersCubitState = context.watch<UsersCubit>().state;
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
final users = usersCubit.state.users;
final isEmpty = usersCubit.state.isEmpty;
final users = usersCubitState.users;
final isEmpty = usersCubitState.isEmpty;
Widget child;

View File

@ -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> boxShadow,
Gradient gradient,
BlendMode backgroundBlendMode,
BoxShape shape,
Color? color,
DecorationImage? image,
BoxBorder? border,
BorderRadiusGeometry? borderRadius,
List<BoxShadow>? boxShadow,
Gradient? gradient,
BlendMode? backgroundBlendMode,
BoxShape? shape,
}) {
return BoxDecoration(
color: color ?? this.color,

View File

@ -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 !-.

View File

@ -37,7 +37,7 @@ class SlideBottomRoute extends PageRouteBuilder {
SlideBottomRoute(this.widget)
: super(
pageBuilder: pageBuilder(widget),
transitionsBuilder: transitionsBuilder,
transitionsBuilder: transitionsBuilder as Widget Function(BuildContext, Animation<double>, Animation<double>, Widget),
);
final Widget widget;

View File

@ -37,7 +37,7 @@ class SlideRightRoute extends PageRouteBuilder {
SlideRightRoute(this.widget)
: super(
pageBuilder: pageBuilder(widget),
transitionsBuilder: transitionsBuilder,
transitionsBuilder: transitionsBuilder as Widget Function(BuildContext, Animation<double>, Animation<double>, Widget),
);
final Widget widget;

View File

@ -4,7 +4,8 @@ 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: