mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-28 19:56:50 +00:00
update
This commit is contained in:
parent
bc6c55b528
commit
804147b8d6
|
@ -20,9 +20,11 @@
|
||||||
"domain": "Domain",
|
"domain": "Domain",
|
||||||
"saving": "Saving..",
|
"saving": "Saving..",
|
||||||
"nickname": "nickname",
|
"nickname": "nickname",
|
||||||
"loading": "loading",
|
"loading": "Loading...",
|
||||||
"later": "Настрою потом",
|
"later": "Настрою потом",
|
||||||
"reset": "Reset"
|
"reset": "Reset",
|
||||||
|
"details": "Details",
|
||||||
|
"no_data": "No data"
|
||||||
},
|
},
|
||||||
"more": {
|
"more": {
|
||||||
"_comment": "'More' tab",
|
"_comment": "'More' tab",
|
||||||
|
@ -54,26 +56,25 @@
|
||||||
"page_title": "Your Data Center",
|
"page_title": "Your Data Center",
|
||||||
"server": {
|
"server": {
|
||||||
"card_title": "Server",
|
"card_title": "Server",
|
||||||
|
"status": "Status — Good",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "It's a virtual computer, where all your services live.",
|
"1": "It's a virtual computer, where all your services live."
|
||||||
"2": "1 CPU, RAM 4Gb, 40Gb — $5 per month",
|
|
||||||
"3": "Status — Good"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain": {
|
"domain": {
|
||||||
"card_title": "Domain",
|
"card_title": "Domain",
|
||||||
|
"status": "Status — Good",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "It's your personal internet address that will point to the server and other services of yours.",
|
"1": "It's your personal internet address that will point to the server and other services of yours.",
|
||||||
"2": "{} — expires on {}",
|
"2": "{} — expires on {}"
|
||||||
"3": "Status — Good"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backup": {
|
"backup": {
|
||||||
"card_title": "Backup",
|
"card_title": "Backup",
|
||||||
|
"status": "Status — Good",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "Will save your day in case of incident: hackers attack, server deletion, etc.",
|
"1": "Will save your day in case of incident: hackers attack, server deletion, etc.",
|
||||||
"2": "3Gb/10Gb, last backup was yesterday {}",
|
"2": "3Gb/10Gb, last backup was yesterday {}"
|
||||||
"3": "Status — Good"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
"nickname": "Никнейм",
|
"nickname": "Никнейм",
|
||||||
"loading": "Загрузка",
|
"loading": "Загрузка",
|
||||||
"later": "Настрою потом",
|
"later": "Настрою потом",
|
||||||
"reset": "Reset"
|
"reset": "Reset",
|
||||||
|
"details": "Детальная информация",
|
||||||
|
"no_data": "Нет данных"
|
||||||
},
|
},
|
||||||
"more": {
|
"more": {
|
||||||
"_comment": "вкладка еще",
|
"_comment": "вкладка еще",
|
||||||
|
@ -54,26 +56,25 @@
|
||||||
"page_title": "Ваш Дата-центр",
|
"page_title": "Ваш Дата-центр",
|
||||||
"server": {
|
"server": {
|
||||||
"card_title": "Сервер",
|
"card_title": "Сервер",
|
||||||
|
"status": "Статус — в норме",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "Это виртульный компьютер на котором работают все ваши сервисы.",
|
"1": "Это виртульный компьютер на котором работают все ваши сервисы."
|
||||||
"2": "1 CPU, RAM 4Gb, 40Gb — $5 в месяц",
|
|
||||||
"3": "Статус — в норме"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain": {
|
"domain": {
|
||||||
"card_title": "Домен",
|
"card_title": "Домен",
|
||||||
|
"status": "Статус — в норме",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "Это ваш личный адрес в интернете, который будет указывать на сервер и другие ваши сервисы.",
|
"1": "Это ваш личный адрес в интернете, который будет указывать на сервер и другие ваши сервисы.",
|
||||||
"2": "{} — продлен до {}",
|
"2": "{} — продлен до {}"
|
||||||
"3": "Статус — в норме"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backup": {
|
"backup": {
|
||||||
"card_title": "Резервное копирование",
|
"card_title": "Резервное копирование",
|
||||||
|
"status": "Статус — в норме",
|
||||||
"bottom_sheet": {
|
"bottom_sheet": {
|
||||||
"1": "Выручит в любой ситуации: хакерская атака, удаление сервера и т.п.",
|
"1": "Выручит в любой ситуации: хакерская атака, удаление сервера и т.п.",
|
||||||
"2": "3Gb — бестплатно до 10Gb, последний вчера в {}",
|
"2": "3Gb — бестплатно до 10Gb, последний вчера в {}"
|
||||||
"3": "Статус — в норме"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
7
build.yaml
Normal file
7
build.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
builders:
|
||||||
|
json_serializable:
|
||||||
|
options:
|
||||||
|
create_factory: true
|
||||||
|
create_to_json: false
|
|
@ -38,6 +38,12 @@ final headline4Style = defaultTextStyle.copyWith(
|
||||||
color: BrandColors.headlineColor,
|
color: BrandColors.headlineColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final headline5Style = defaultTextStyle.copyWith(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: NamedFontWeight.medium,
|
||||||
|
color: BrandColors.headlineColor.withOpacity(0.8),
|
||||||
|
);
|
||||||
|
|
||||||
final body1Style = defaultTextStyle;
|
final body1Style = defaultTextStyle;
|
||||||
final body2Style = defaultTextStyle.copyWith(
|
final body2Style = defaultTextStyle.copyWith(
|
||||||
color: BrandColors.textColor2,
|
color: BrandColors.textColor2,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import 'package:selfprivacy/logic/get_it/console.dart';
|
||||||
import 'package:selfprivacy/logic/models/message.dart';
|
import 'package:selfprivacy/logic/models/message.dart';
|
||||||
|
|
||||||
abstract class ApiMap {
|
abstract class ApiMap {
|
||||||
|
|
||||||
Future<Dio> getClient() async {
|
Future<Dio> getClient() async {
|
||||||
var dio = Dio(await options);
|
var dio = Dio(await options);
|
||||||
if (hasLoger) {
|
if (hasLoger) {
|
||||||
|
@ -31,28 +30,15 @@ abstract class ApiMap {
|
||||||
abstract final String rootAddress;
|
abstract final String rootAddress;
|
||||||
abstract final bool hasLoger;
|
abstract final bool hasLoger;
|
||||||
abstract final bool isWithToken;
|
abstract final bool isWithToken;
|
||||||
|
|
||||||
|
ValidateStatus? validateStatus;
|
||||||
|
|
||||||
|
void close(Dio client) {
|
||||||
|
client.close();
|
||||||
|
validateStatus = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstract class ApiMapOld {
|
|
||||||
// ApiMapOld() {
|
|
||||||
// var client = Dio()..interceptors.add(ConsoleInterceptor());
|
|
||||||
// (client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
|
|
||||||
// (HttpClient client) {
|
|
||||||
// client.badCertificateCallback =
|
|
||||||
// (X509Certificate cert, String host, int port) => true;
|
|
||||||
// return client;
|
|
||||||
// };
|
|
||||||
// loggedClient = client;
|
|
||||||
// }
|
|
||||||
// String? rootAddress;
|
|
||||||
|
|
||||||
// late Dio loggedClient;
|
|
||||||
|
|
||||||
// void close() {
|
|
||||||
// loggedClient.close();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
class ConsoleInterceptor extends InterceptorsWrapper {
|
class ConsoleInterceptor extends InterceptorsWrapper {
|
||||||
void addMessage(Message message) {
|
void addMessage(Message message) {
|
||||||
getIt.get<ConsoleModel>().addMessage(message);
|
getIt.get<ConsoleModel>().addMessage(message);
|
||||||
|
|
|
@ -11,7 +11,6 @@ class BackblazeApi extends ApiMap {
|
||||||
if (isWithToken) {
|
if (isWithToken) {
|
||||||
var backblazeCredential = getIt<ApiConfigModel>().backblazeCredential;
|
var backblazeCredential = getIt<ApiConfigModel>().backblazeCredential;
|
||||||
var token = backblazeCredential!.applicationKey;
|
var token = backblazeCredential!.applicationKey;
|
||||||
assert(token != null);
|
|
||||||
options.headers = {'Authorization': 'Basic $token'};
|
options.headers = {'Authorization': 'Basic $token'};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +21,6 @@ class BackblazeApi extends ApiMap {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateStatus? validateStatus;
|
|
||||||
@override
|
@override
|
||||||
String rootAddress = 'https://api.backblazeb2.com/b2api/v2/';
|
String rootAddress = 'https://api.backblazeb2.com/b2api/v2/';
|
||||||
|
|
||||||
|
@ -32,7 +30,7 @@ class BackblazeApi extends ApiMap {
|
||||||
'b2_authorize_account',
|
'b2_authorize_account',
|
||||||
options: Options(headers: {'Authorization': 'Basic $encodedApiKey'}),
|
options: Options(headers: {'Authorization': 'Basic $encodedApiKey'}),
|
||||||
);
|
);
|
||||||
client.close();
|
close(client);
|
||||||
if (response.statusCode == HttpStatus.ok) {
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
return true;
|
return true;
|
||||||
} else if (response.statusCode == HttpStatus.unauthorized) {
|
} else if (response.statusCode == HttpStatus.unauthorized) {
|
||||||
|
|
|
@ -22,8 +22,6 @@ class CloudflareApi extends ApiMap {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateStatus? validateStatus;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String rootAddress = 'https://api.cloudflare.com/client/v4';
|
String rootAddress = 'https://api.cloudflare.com/client/v4';
|
||||||
|
|
||||||
|
@ -36,8 +34,7 @@ class CloudflareApi extends ApiMap {
|
||||||
Response response = await client.get('/user/tokens/verify',
|
Response response = await client.get('/user/tokens/verify',
|
||||||
options: Options(headers: {'Authorization': 'Bearer $token'}));
|
options: Options(headers: {'Authorization': 'Bearer $token'}));
|
||||||
|
|
||||||
client.close();
|
close(client);
|
||||||
validateStatus = null;
|
|
||||||
|
|
||||||
if (response.statusCode == HttpStatus.ok) {
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -48,7 +45,7 @@ class CloudflareApi extends ApiMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getZoneId(String domain) async {
|
Future<String> getZoneId(String domain) async {
|
||||||
validateStatus = (status) {
|
validateStatus = (status) {
|
||||||
return status == HttpStatus.ok || status == HttpStatus.forbidden;
|
return status == HttpStatus.ok || status == HttpStatus.forbidden;
|
||||||
};
|
};
|
||||||
|
@ -58,14 +55,9 @@ class CloudflareApi extends ApiMap {
|
||||||
queryParameters: {'name': domain},
|
queryParameters: {'name': domain},
|
||||||
);
|
);
|
||||||
|
|
||||||
client.close();
|
close(client);
|
||||||
validateStatus = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return response.data['result'][0]['id'];
|
return response.data['result'][0]['id'];
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeSimilarRecords({
|
Future<void> removeSimilarRecords({
|
||||||
|
@ -92,7 +84,7 @@ class CloudflareApi extends ApiMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
await Future.wait(allDeleteFutures);
|
await Future.wait(allDeleteFutures);
|
||||||
client.close();
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createMultipleDnsRecords({
|
Future<void> createMultipleDnsRecords({
|
||||||
|
@ -118,7 +110,7 @@ class CloudflareApi extends ApiMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
await Future.wait(allCreateFutures);
|
await Future.wait(allCreateFutures);
|
||||||
client.close();
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DnsRecords> projectDnsRecords(String? domainName, String? ip4) {
|
List<DnsRecords> projectDnsRecords(String? domainName, String? ip4) {
|
||||||
|
@ -171,7 +163,7 @@ class CloudflareApi extends ApiMap {
|
||||||
queryParameters: {'per_page': 50},
|
queryParameters: {'per_page': 50},
|
||||||
);
|
);
|
||||||
|
|
||||||
client.close();
|
close(client);
|
||||||
return response.data['result']
|
return response.data['result']
|
||||||
.map<String>((el) => el['name'] as String)
|
.map<String>((el) => el['name'] as String)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/api_map.dart';
|
import 'package:selfprivacy/logic/api_maps/api_map.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hetzner_server_info.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_details.dart';
|
import 'package:selfprivacy/logic/models/server_details.dart';
|
||||||
import 'package:selfprivacy/logic/models/user.dart';
|
import 'package:selfprivacy/logic/models/user.dart';
|
||||||
import 'package:selfprivacy/utils/password_generator2.dart';
|
import 'package:selfprivacy/utils/password_generator2.dart';
|
||||||
|
@ -29,8 +30,6 @@ class HetznerApi extends ApiMap {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateStatus? validateStatus;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String rootAddress = 'https://api.hetzner.cloud/v1';
|
String rootAddress = 'https://api.hetzner.cloud/v1';
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ class HetznerApi extends ApiMap {
|
||||||
headers: {'Authorization': 'Bearer $token'},
|
headers: {'Authorization': 'Bearer $token'},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
client.close();
|
close(client);
|
||||||
|
|
||||||
if (response.statusCode == HttpStatus.ok) {
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -87,7 +86,7 @@ class HetznerApi extends ApiMap {
|
||||||
List list = response.data['servers'];
|
List list = response.data['servers'];
|
||||||
var server = list.firstWhere((el) => el['name'] == 'selfprivacy-server');
|
var server = list.firstWhere((el) => el['name'] == 'selfprivacy-server');
|
||||||
await client.delete('/servers/${server['id']}');
|
await client.delete('/servers/${server['id']}');
|
||||||
client.close();
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<HetznerServerDetails> startServer({
|
Future<HetznerServerDetails> startServer({
|
||||||
|
@ -96,7 +95,7 @@ class HetznerApi extends ApiMap {
|
||||||
var client = await getClient();
|
var client = await getClient();
|
||||||
|
|
||||||
await client.post('/servers/${server.id}/actions/poweron');
|
await client.post('/servers/${server.id}/actions/poweron');
|
||||||
client.close();
|
close(client);
|
||||||
|
|
||||||
return server.copyWith(
|
return server.copyWith(
|
||||||
startTime: DateTime.now(),
|
startTime: DateTime.now(),
|
||||||
|
@ -108,7 +107,7 @@ class HetznerApi extends ApiMap {
|
||||||
}) async {
|
}) async {
|
||||||
var client = await getClient();
|
var client = await getClient();
|
||||||
await client.post('/servers/${server.id}/actions/poweron');
|
await client.post('/servers/${server.id}/actions/poweron');
|
||||||
client.close();
|
close(client);
|
||||||
return server.copyWith(
|
return server.copyWith(
|
||||||
startTime: DateTime.now(),
|
startTime: DateTime.now(),
|
||||||
);
|
);
|
||||||
|
@ -118,13 +117,15 @@ class HetznerApi extends ApiMap {
|
||||||
var hetznerServer = getIt<ApiConfigModel>().hetznerServer;
|
var hetznerServer = getIt<ApiConfigModel>().hetznerServer;
|
||||||
var client = await getClient();
|
var client = await getClient();
|
||||||
await client.post('/servers/${hetznerServer!.id}/metrics');
|
await client.post('/servers/${hetznerServer!.id}/metrics');
|
||||||
client.close();
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInfo() async {
|
Future<HetznerServerInfo> getInfo() async {
|
||||||
var hetznerServer = getIt<ApiConfigModel>().hetznerServer;
|
var hetznerServer = getIt<ApiConfigModel>().hetznerServer;
|
||||||
var client = await getClient();
|
var client = await getClient();
|
||||||
await client.post('/servers/${hetznerServer!.id}');
|
Response response = await client.get('/servers/${hetznerServer!.id}');
|
||||||
client.close();
|
close(client);
|
||||||
|
|
||||||
|
return HetznerServerInfo.fromJson(response.data!['server']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ class ServerApi extends ApiMap {
|
||||||
if (isWithToken) {
|
if (isWithToken) {
|
||||||
var cloudFlareDomain = getIt<ApiConfigModel>().cloudFlareDomain;
|
var cloudFlareDomain = getIt<ApiConfigModel>().cloudFlareDomain;
|
||||||
var domainName = cloudFlareDomain!.domainName;
|
var domainName = cloudFlareDomain!.domainName;
|
||||||
assert(domainName != null);
|
|
||||||
|
|
||||||
options = BaseOptions(baseUrl: 'https://api.$domainName');
|
options = BaseOptions(baseUrl: 'https://api.$domainName');
|
||||||
}
|
}
|
||||||
|
@ -37,7 +36,7 @@ class ServerApi extends ApiMap {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
client.close();
|
close(client);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
await repository.createServer(
|
await repository.createServer(
|
||||||
state.rootUser!,
|
state.rootUser!,
|
||||||
state.cloudFlareDomain!.domainName!,
|
state.cloudFlareDomain!.domainName,
|
||||||
state.cloudFlareKey!,
|
state.cloudFlareKey!,
|
||||||
onCancel: onCancel,
|
onCancel: onCancel,
|
||||||
onSuccess: onSuccess,
|
onSuccess: onSuccess,
|
||||||
|
|
|
@ -92,7 +92,6 @@ class AppConfigState extends Equatable {
|
||||||
isServerReseted,
|
isServerReseted,
|
||||||
hasFinalChecked,
|
hasFinalChecked,
|
||||||
];
|
];
|
||||||
print('progress: $res');
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_repository.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hetzner_server_info.dart';
|
||||||
|
|
||||||
|
part 'server_detailed_info_state.dart';
|
||||||
|
|
||||||
|
class ServerDetailsCubit extends Cubit<ServerDetailsState> {
|
||||||
|
ServerDetailsCubit() : super(ServerDetailsInitial());
|
||||||
|
|
||||||
|
ServerDetailsRepository repository = ServerDetailsRepository();
|
||||||
|
|
||||||
|
void check() async {
|
||||||
|
var isReadyToCheck = getIt<ApiConfigModel>().hetznerServer != null;
|
||||||
|
if (isReadyToCheck) {
|
||||||
|
emit(ServerDetailsLoading());
|
||||||
|
var data = await repository.load();
|
||||||
|
emit(Loaded(serverInfo: data, checkTime: DateTime.now()));
|
||||||
|
} else {
|
||||||
|
emit(ServerDetailsNotReady());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hetzner_server_info.dart';
|
||||||
|
|
||||||
|
class ServerDetailsRepository {
|
||||||
|
Future<HetznerServerInfo> load() async {
|
||||||
|
var client = HetznerApi();
|
||||||
|
return await client.getInfo();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
part of 'server_detailed_info_cubit.dart';
|
||||||
|
|
||||||
|
abstract class ServerDetailsState extends Equatable {
|
||||||
|
const ServerDetailsState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerDetailsInitial extends ServerDetailsState {}
|
||||||
|
|
||||||
|
class ServerDetailsLoading extends ServerDetailsState {}
|
||||||
|
|
||||||
|
class ServerDetailsNotReady extends ServerDetailsState {}
|
||||||
|
|
||||||
|
class Loading extends ServerDetailsState {}
|
||||||
|
|
||||||
|
class Loaded extends ServerDetailsState {
|
||||||
|
final HetznerServerInfo serverInfo;
|
||||||
|
final DateTime checkTime;
|
||||||
|
|
||||||
|
Loaded({
|
||||||
|
required this.serverInfo,
|
||||||
|
required this.checkTime,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [serverInfo, checkTime];
|
||||||
|
}
|
|
@ -6,13 +6,13 @@ part 'backblaze_credential.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 4)
|
@HiveType(typeId: 4)
|
||||||
class BackblazeCredential {
|
class BackblazeCredential {
|
||||||
BackblazeCredential({this.keyId, this.applicationKey});
|
BackblazeCredential({required this.keyId, required this.applicationKey});
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final String? keyId;
|
final String keyId;
|
||||||
|
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
final String? applicationKey;
|
final String applicationKey;
|
||||||
|
|
||||||
get encodedApiKey => encodedBackblazeKey(keyId, applicationKey);
|
get encodedApiKey => encodedBackblazeKey(keyId, applicationKey);
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ class BackblazeCredentialAdapter extends TypeAdapter<BackblazeCredential> {
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
};
|
};
|
||||||
return BackblazeCredential(
|
return BackblazeCredential(
|
||||||
keyId: fields[0] as String?,
|
keyId: fields[0] as String,
|
||||||
applicationKey: fields[1] as String?,
|
applicationKey: fields[1] as String,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,16 @@ part 'cloudflare_domain.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 3)
|
@HiveType(typeId: 3)
|
||||||
class CloudFlareDomain {
|
class CloudFlareDomain {
|
||||||
CloudFlareDomain({this.domainName, this.zoneId});
|
CloudFlareDomain({
|
||||||
|
required this.domainName,
|
||||||
|
required this.zoneId,
|
||||||
|
});
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final String? domainName;
|
final String domainName;
|
||||||
|
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
final String? zoneId;
|
final String zoneId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|
|
@ -17,8 +17,8 @@ class CloudFlareDomainAdapter extends TypeAdapter<CloudFlareDomain> {
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
};
|
};
|
||||||
return CloudFlareDomain(
|
return CloudFlareDomain(
|
||||||
domainName: fields[0] as String?,
|
domainName: fields[0] as String,
|
||||||
zoneId: fields[1] as String?,
|
zoneId: fields[1] as String,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
89
lib/logic/models/hetzner_server_info.dart
Normal file
89
lib/logic/models/hetzner_server_info.dart
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'hetzner_server_info.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerServerInfo {
|
||||||
|
final int id;
|
||||||
|
final String name;
|
||||||
|
final ServerStatus status;
|
||||||
|
final DateTime created;
|
||||||
|
|
||||||
|
@JsonKey(name: 'server_type')
|
||||||
|
final HetznerServerTypeInfo serverType;
|
||||||
|
|
||||||
|
@JsonKey(name: 'datacenter', fromJson: HetznerServerInfo.locationFromJson)
|
||||||
|
final HetznerLocation location;
|
||||||
|
|
||||||
|
static HetznerLocation locationFromJson(Map json) =>
|
||||||
|
HetznerLocation.fromJson(json['location']);
|
||||||
|
|
||||||
|
static HetznerServerInfo fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerServerInfoFromJson(json);
|
||||||
|
|
||||||
|
HetznerServerInfo(
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.status,
|
||||||
|
this.created,
|
||||||
|
this.serverType,
|
||||||
|
this.location,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ServerStatus {
|
||||||
|
running,
|
||||||
|
initializing,
|
||||||
|
starting,
|
||||||
|
stopping,
|
||||||
|
off,
|
||||||
|
deleting,
|
||||||
|
migrating,
|
||||||
|
rebuilding,
|
||||||
|
unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerServerTypeInfo {
|
||||||
|
final int cores;
|
||||||
|
final num memory;
|
||||||
|
final int disk;
|
||||||
|
|
||||||
|
final List<HetznerPriceInfo> prices;
|
||||||
|
|
||||||
|
HetznerServerTypeInfo(this.cores, this.memory, this.disk, this.prices);
|
||||||
|
|
||||||
|
static HetznerServerTypeInfo fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerServerTypeInfoFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerPriceInfo {
|
||||||
|
HetznerPriceInfo(this.hourly, this.monthly);
|
||||||
|
|
||||||
|
@JsonKey(name: 'price_hourly', fromJson: HetznerPriceInfo.getPrice)
|
||||||
|
final double hourly;
|
||||||
|
|
||||||
|
@JsonKey(name: 'price_monthly', fromJson: HetznerPriceInfo.getPrice)
|
||||||
|
final double monthly;
|
||||||
|
|
||||||
|
static HetznerPriceInfo fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerPriceInfoFromJson(json);
|
||||||
|
|
||||||
|
static double getPrice(Map json) => double.parse(json['gross'] as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HetznerLocation {
|
||||||
|
final String country;
|
||||||
|
final String city;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
@JsonKey(name: 'network_zone')
|
||||||
|
final String zone;
|
||||||
|
|
||||||
|
HetznerLocation(this.country, this.city, this.description, this.zone);
|
||||||
|
|
||||||
|
static HetznerLocation fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$HetznerLocationFromJson(json);
|
||||||
|
}
|
84
lib/logic/models/hetzner_server_info.g.dart
Normal file
84
lib/logic/models/hetzner_server_info.g.dart
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'hetzner_server_info.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
HetznerServerInfo _$HetznerServerInfoFromJson(Map<String, dynamic> json) {
|
||||||
|
return HetznerServerInfo(
|
||||||
|
json['id'] as int,
|
||||||
|
json['name'] as String,
|
||||||
|
_$enumDecode(_$ServerStatusEnumMap, json['status']),
|
||||||
|
DateTime.parse(json['created'] as String),
|
||||||
|
HetznerServerTypeInfo.fromJson(json['server_type'] as Map<String, dynamic>),
|
||||||
|
HetznerServerInfo.locationFromJson(json['datacenter'] as Map),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
K _$enumDecode<K, V>(
|
||||||
|
Map<K, V> enumValues,
|
||||||
|
Object? source, {
|
||||||
|
K? unknownValue,
|
||||||
|
}) {
|
||||||
|
if (source == null) {
|
||||||
|
throw ArgumentError(
|
||||||
|
'A value must be provided. Supported values: '
|
||||||
|
'${enumValues.values.join(', ')}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enumValues.entries.singleWhere(
|
||||||
|
(e) => e.value == source,
|
||||||
|
orElse: () {
|
||||||
|
if (unknownValue == null) {
|
||||||
|
throw ArgumentError(
|
||||||
|
'`$source` is not one of the supported values: '
|
||||||
|
'${enumValues.values.join(', ')}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return MapEntry(unknownValue, enumValues.values.first);
|
||||||
|
},
|
||||||
|
).key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _$ServerStatusEnumMap = {
|
||||||
|
ServerStatus.running: 'running',
|
||||||
|
ServerStatus.initializing: 'initializing',
|
||||||
|
ServerStatus.starting: 'starting',
|
||||||
|
ServerStatus.stopping: 'stopping',
|
||||||
|
ServerStatus.off: 'off',
|
||||||
|
ServerStatus.deleting: 'deleting',
|
||||||
|
ServerStatus.migrating: 'migrating',
|
||||||
|
ServerStatus.rebuilding: 'rebuilding',
|
||||||
|
ServerStatus.unknown: 'unknown',
|
||||||
|
};
|
||||||
|
|
||||||
|
HetznerServerTypeInfo _$HetznerServerTypeInfoFromJson(
|
||||||
|
Map<String, dynamic> json) {
|
||||||
|
return HetznerServerTypeInfo(
|
||||||
|
json['cores'] as int,
|
||||||
|
json['memory'] as num,
|
||||||
|
json['disk'] as int,
|
||||||
|
(json['prices'] as List<dynamic>)
|
||||||
|
.map((e) => HetznerPriceInfo.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
HetznerPriceInfo _$HetznerPriceInfoFromJson(Map<String, dynamic> json) {
|
||||||
|
return HetznerPriceInfo(
|
||||||
|
HetznerPriceInfo.getPrice(json['price_hourly'] as Map),
|
||||||
|
HetznerPriceInfo.getPrice(json['price_monthly'] as Map),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
HetznerLocation _$HetznerLocationFromJson(Map<String, dynamic> json) {
|
||||||
|
return HetznerLocation(
|
||||||
|
json['country'] as String,
|
||||||
|
json['city'] as String,
|
||||||
|
json['description'] as String,
|
||||||
|
json['network_zone'] as String,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
@JsonSerializable(createFactory: false)
|
|
||||||
class ServerInfo {
|
|
||||||
final String id;
|
|
||||||
final String name;
|
|
||||||
final ServerStatus status;
|
|
||||||
final DateTime created;
|
|
||||||
|
|
||||||
ServerInfo(this.id, this.name, this.status, this.created);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ServerStatus {
|
|
||||||
running,
|
|
||||||
initializing,
|
|
||||||
starting,
|
|
||||||
stopping,
|
|
||||||
off,
|
|
||||||
deleting,
|
|
||||||
migrating,
|
|
||||||
rebuilding,
|
|
||||||
unknown,
|
|
||||||
}
|
|
|
@ -37,8 +37,6 @@ class MyApp extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
AppSettingsState appSettings = context.watch<AppSettingsCubit>().state;
|
AppSettingsState appSettings = context.watch<AppSettingsCubit>().state;
|
||||||
|
|
||||||
var a = DateTime.parse('2021-03-23T20:00:06+00:00');
|
|
||||||
print(a);
|
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
|
|
|
@ -34,7 +34,7 @@ class BrandButton {
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
|
||||||
static iconText({
|
static emptyWithIconText({
|
||||||
Key? key,
|
Key? key,
|
||||||
required VoidCallback onPressed,
|
required VoidCallback onPressed,
|
||||||
required String title,
|
required String title,
|
||||||
|
|
|
@ -6,6 +6,7 @@ enum TextType {
|
||||||
h2, // cards titles
|
h2, // cards titles
|
||||||
h3, // titles in about page
|
h3, // titles in about page
|
||||||
h4, // caption
|
h4, // caption
|
||||||
|
h5, // Table data
|
||||||
body1, // normal
|
body1, // normal
|
||||||
body2, // with opacity
|
body2, // with opacity
|
||||||
medium,
|
medium,
|
||||||
|
@ -63,10 +64,28 @@ class BrandText extends StatelessWidget {
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
factory BrandText.h4(String? text, {TextStyle? style}) => BrandText(
|
factory BrandText.h4(
|
||||||
|
String? text, {
|
||||||
|
TextStyle? style,
|
||||||
|
TextAlign? textAlign,
|
||||||
|
}) =>
|
||||||
|
BrandText(
|
||||||
text,
|
text,
|
||||||
type: TextType.h4,
|
type: TextType.h4,
|
||||||
style: style,
|
style: style,
|
||||||
|
textAlign: textAlign,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory BrandText.h5(
|
||||||
|
String? text, {
|
||||||
|
TextStyle? style,
|
||||||
|
TextAlign? textAlign,
|
||||||
|
}) =>
|
||||||
|
BrandText(
|
||||||
|
text,
|
||||||
|
type: TextType.h5,
|
||||||
|
style: style,
|
||||||
|
textAlign: textAlign,
|
||||||
);
|
);
|
||||||
factory BrandText.body1(String? text, {TextStyle? style}) => BrandText(
|
factory BrandText.body1(String? text, {TextStyle? style}) => BrandText(
|
||||||
text,
|
text,
|
||||||
|
@ -123,6 +142,11 @@ class BrandText extends StatelessWidget {
|
||||||
? headline4Style.copyWith(color: Colors.white)
|
? headline4Style.copyWith(color: Colors.white)
|
||||||
: headline4Style;
|
: headline4Style;
|
||||||
break;
|
break;
|
||||||
|
case TextType.h5:
|
||||||
|
style = isDark
|
||||||
|
? headline5Style.copyWith(color: Colors.white)
|
||||||
|
: headline5Style;
|
||||||
|
break;
|
||||||
case TextType.body1:
|
case TextType.body1:
|
||||||
style = isDark ? body1Style.copyWith(color: Colors.white) : body1Style;
|
style = isDark ? body1Style.copyWith(color: Colors.white) : body1Style;
|
||||||
break;
|
break;
|
||||||
|
|
51
lib/ui/components/one_page/one_page.dart
Normal file
51
lib/ui/components/one_page/one_page.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/pre_styled_buttons.dart';
|
||||||
|
|
||||||
|
class OnePage extends StatelessWidget {
|
||||||
|
const OnePage({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SafeArea(
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 51,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
child: BrandText.h4('basis.details'.tr()),
|
||||||
|
),
|
||||||
|
BrandDivider(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
preferredSize: Size.fromHeight(52),
|
||||||
|
),
|
||||||
|
body: child,
|
||||||
|
bottomNavigationBar: SafeArea(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(boxShadow: kElevationToShadow[3]),
|
||||||
|
height: kBottomNavigationBarHeight,
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: PreStyledButtons.close(
|
||||||
|
onPress: () => Navigator.of(context).pop()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
30
lib/ui/components/pre_styled_buttons.dart
Normal file
30
lib/ui/components/pre_styled_buttons.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
|
class PreStyledButtons {
|
||||||
|
static Widget close({
|
||||||
|
required VoidCallback onPress,
|
||||||
|
}) =>
|
||||||
|
_CloseButton(onPress: onPress);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CloseButton extends StatelessWidget {
|
||||||
|
const _CloseButton({Key? key, required this.onPress}) : super(key: key);
|
||||||
|
|
||||||
|
final VoidCallback onPress;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return OutlinedButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
BrandText.h4('basis.close'.tr()),
|
||||||
|
Icon(Icons.close),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,9 +10,15 @@ import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.da
|
||||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
||||||
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/one_page/one_page.dart';
|
||||||
import 'package:selfprivacy/ui/pages/providers/settings/settings.dart';
|
import 'package:selfprivacy/ui/pages/providers/settings/settings.dart';
|
||||||
|
import 'package:selfprivacy/ui/pages/server_details/server_details.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:selfprivacy/utils/route_transitions/slide_bottom.dart';
|
||||||
|
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||||
|
|
||||||
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
class ProvidersPage extends StatefulWidget {
|
class ProvidersPage extends StatefulWidget {
|
||||||
ProvidersPage({Key? key}) : super(key: key);
|
ProvidersPage({Key? key}) : super(key: key);
|
||||||
|
@ -64,9 +70,11 @@ class _Card extends StatelessWidget {
|
||||||
final ProviderModel provider;
|
final ProviderModel provider;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String? title;
|
late String title;
|
||||||
String? message;
|
String? message;
|
||||||
String? stableText;
|
late String stableText;
|
||||||
|
late VoidCallback onTap;
|
||||||
|
|
||||||
AppConfigState appConfig = context.watch<AppConfigCubit>().state;
|
AppConfigState appConfig = context.watch<AppConfigCubit>().state;
|
||||||
|
|
||||||
var domainName =
|
var domainName =
|
||||||
|
@ -75,20 +83,24 @@ class _Card extends StatelessWidget {
|
||||||
switch (provider.type) {
|
switch (provider.type) {
|
||||||
case ProviderType.server:
|
case ProviderType.server:
|
||||||
title = 'providers.server.card_title'.tr();
|
title = 'providers.server.card_title'.tr();
|
||||||
stableText = 'В норме';
|
stableText = 'providers.domain.status'.tr();
|
||||||
|
|
||||||
|
stableText = 'providers.server.status'.tr();
|
||||||
|
onTap = () => Navigator.of(context).push(
|
||||||
|
SlideBottomRoute(
|
||||||
|
OnePage(
|
||||||
|
title: title,
|
||||||
|
child: ServerDetails(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case ProviderType.domain:
|
case ProviderType.domain:
|
||||||
title = 'providers.domain.card_title'.tr();
|
title = 'providers.domain.card_title'.tr();
|
||||||
message = domainName;
|
message = domainName;
|
||||||
stableText = 'Домен настроен';
|
stableText = 'providers.domain.status'.tr();
|
||||||
break;
|
|
||||||
case ProviderType.backup:
|
onTap = () => showModalBottomSheet<void>(
|
||||||
title = 'providers.backup.card_title'.tr();
|
|
||||||
stableText = 'В норме';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => showModalBottomSheet<void>(
|
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
@ -98,7 +110,27 @@ class _Card extends StatelessWidget {
|
||||||
statusText: stableText,
|
statusText: stableText,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
break;
|
||||||
|
case ProviderType.backup:
|
||||||
|
title = 'providers.backup.card_title'.tr();
|
||||||
|
stableText = 'providers.backup.status'.tr();
|
||||||
|
|
||||||
|
onTap = () => showModalBottomSheet<void>(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return _ProviderDetails(
|
||||||
|
provider: provider,
|
||||||
|
statusText: stableText,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
child: BrandCard(
|
child: BrandCard(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -139,20 +171,11 @@ class _ProviderDetails extends StatelessWidget {
|
||||||
|
|
||||||
var config = context.watch<AppConfigCubit>().state;
|
var config = context.watch<AppConfigCubit>().state;
|
||||||
|
|
||||||
var domainName = config.isDomainFilled
|
var domainName = UiHelpers.getDomainName(config);
|
||||||
? config.cloudFlareDomain!.domainName!
|
|
||||||
: 'example.com';
|
|
||||||
switch (provider.type) {
|
switch (provider.type) {
|
||||||
case ProviderType.server:
|
case ProviderType.server:
|
||||||
title = 'providers.server.card_title'.tr();
|
throw ('wrong type');
|
||||||
children = [
|
|
||||||
BrandText.body1('providers.server.bottom_sheet.1'.tr()),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
BrandText.body1('providers.server.bottom_sheet.2'.tr()),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
BrandText.body1('providers.server.bottom_sheet.3'.tr()),
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
case ProviderType.domain:
|
case ProviderType.domain:
|
||||||
title = 'providers.domain.card_title'.tr();
|
title = 'providers.domain.card_title'.tr();
|
||||||
children = [
|
children = [
|
||||||
|
@ -161,7 +184,7 @@ class _ProviderDetails extends StatelessWidget {
|
||||||
BrandText.body1(
|
BrandText.body1(
|
||||||
'providers.domain.bottom_sheet.2'.tr(args: [domainName, 'Date'])),
|
'providers.domain.bottom_sheet.2'.tr(args: [domainName, 'Date'])),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
BrandText.body1('providers.domain.bottom_sheet.3'.tr()),
|
BrandText.body1('providers.domain.status'.tr()),
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case ProviderType.backup:
|
case ProviderType.backup:
|
||||||
|
@ -185,38 +208,7 @@ class _ProviderDetails extends StatelessWidget {
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Align(
|
SizedBox(height: 40),
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
horizontal: 2,
|
|
||||||
),
|
|
||||||
child: PopupMenuButton<_PopupMenuItemType>(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
onSelected: (_PopupMenuItemType result) {
|
|
||||||
switch (result) {
|
|
||||||
case _PopupMenuItemType.setting:
|
|
||||||
navigatorKey.currentState!
|
|
||||||
.push(materialRoute(SettingsPage()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: Icon(Icons.more_vert),
|
|
||||||
itemBuilder: (BuildContext context) => [
|
|
||||||
PopupMenuItem<_PopupMenuItemType>(
|
|
||||||
value: _PopupMenuItemType.setting,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 5),
|
|
||||||
child: Text('basis.settings'.tr()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: brandPagePadding2,
|
padding: brandPagePadding2,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -242,5 +234,3 @@ class _ProviderDetails extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum _PopupMenuItemType { setting }
|
|
||||||
|
|
290
lib/ui/pages/server_details/server_details.dart
Normal file
290
lib/ui/pages/server_details/server_details.dart
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/state_types.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/switch_block/switch_bloc.dart';
|
||||||
|
import 'package:selfprivacy/utils/named_font_weight.dart';
|
||||||
|
|
||||||
|
part 'server_settings.dart';
|
||||||
|
|
||||||
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
class ServerDetails extends StatefulWidget {
|
||||||
|
const ServerDetails({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ServerDetailsState createState() => _ServerDetailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ServerDetailsState extends State<ServerDetails>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late TabController tabController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
tabController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
tabController = TabController(length: 2, vsync: this);
|
||||||
|
tabController.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
|
||||||
|
var providerState = isReady ? StateType.stable : StateType.uninitialized;
|
||||||
|
|
||||||
|
late String title = 'providers.server.card_title'.tr();
|
||||||
|
|
||||||
|
return TabBarView(
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
controller: tabController,
|
||||||
|
children: [
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ServerDetailsCubit()..check(),
|
||||||
|
child: Builder(builder: (context) {
|
||||||
|
var details = context.watch<ServerDetailsCubit>().state;
|
||||||
|
if (details is ServerDetailsLoading ||
|
||||||
|
details is ServerDetailsInitial) {
|
||||||
|
return _TempMessage(message: 'basis.loading'.tr());
|
||||||
|
} else if (details is ServerDetailsNotReady) {
|
||||||
|
return _TempMessage(message: 'basis.no_data'.tr());
|
||||||
|
} else if (details is Loaded) {
|
||||||
|
var data = details.serverInfo;
|
||||||
|
var checkTime = details.checkTime;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: brandPagePadding2,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
IconStatusMask(
|
||||||
|
status: providerState,
|
||||||
|
child: Icon(
|
||||||
|
BrandIcons.server,
|
||||||
|
size: 40,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
BrandText.h2(title),
|
||||||
|
Spacer(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 4,
|
||||||
|
horizontal: 2,
|
||||||
|
),
|
||||||
|
child: PopupMenuButton<_PopupMenuItemType>(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
onSelected: (_PopupMenuItemType result) {
|
||||||
|
switch (result) {
|
||||||
|
case _PopupMenuItemType.setting:
|
||||||
|
tabController.animateTo(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.more_vert),
|
||||||
|
itemBuilder: (BuildContext context) => [
|
||||||
|
PopupMenuItem<_PopupMenuItemType>(
|
||||||
|
value: _PopupMenuItemType.setting,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(left: 5),
|
||||||
|
child: Text('basis.settings'.tr()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
BrandText.body1('providers.server.bottom_sheet.1'.tr()),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
Center(child: BrandText.h2('General information')),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Table(
|
||||||
|
columnWidths: {
|
||||||
|
0: FractionColumnWidth(.5),
|
||||||
|
1: FractionColumnWidth(.5),
|
||||||
|
},
|
||||||
|
defaultVerticalAlignment:
|
||||||
|
TableCellVerticalAlignment.middle,
|
||||||
|
children: [
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Last check'),
|
||||||
|
getRowValue(formater.format(checkTime)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Server Id'),
|
||||||
|
getRowValue(data.id.toString()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Status:'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.status.toString().split('.')[1].toUpperCase()}',
|
||||||
|
isBold: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('CPU'),
|
||||||
|
getRowValue(
|
||||||
|
data.serverType.cores.toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Memory'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.serverType.memory.toString()} GB',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Disk Local'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.serverType.disk.toString()} GB',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Price monthly:'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.serverType.prices[1].monthly.toString()}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Price hourly:'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.serverType.prices[1].hourly.toString()}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
Center(child: BrandText.h2('Location')),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Table(
|
||||||
|
columnWidths: {
|
||||||
|
0: FractionColumnWidth(.5),
|
||||||
|
1: FractionColumnWidth(.5),
|
||||||
|
},
|
||||||
|
defaultVerticalAlignment:
|
||||||
|
TableCellVerticalAlignment.middle,
|
||||||
|
children: [
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Country'),
|
||||||
|
getRowValue(
|
||||||
|
'${data.location.country}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('City'),
|
||||||
|
getRowValue(data.location.city),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
getRowTitle('Description'),
|
||||||
|
getRowValue(data.location.description),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// BrandText.body1('providers.server.bottom_sheet.2'.tr()),
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
// BrandText.body1('providers.server.bottom_sheet.3'.tr()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw Exception('wrong state');
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
_ServerSettings(tabController: tabController),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getRowTitle(String title) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 10),
|
||||||
|
child: BrandText.h5(
|
||||||
|
title,
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getRowValue(String title, {bool isBold = false}) {
|
||||||
|
return BrandText.body1(
|
||||||
|
title,
|
||||||
|
style: isBold
|
||||||
|
? TextStyle(
|
||||||
|
fontWeight: NamedFontWeight.demiBold,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _PopupMenuItemType { setting }
|
||||||
|
|
||||||
|
class _TempMessage extends StatelessWidget {
|
||||||
|
const _TempMessage({
|
||||||
|
Key? key,
|
||||||
|
required this.message,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height - 100,
|
||||||
|
child: Center(
|
||||||
|
child: BrandText.body2(message),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateFormat formater = DateFormat('HH:mm:ss');
|
136
lib/ui/pages/server_details/server_settings.dart
Normal file
136
lib/ui/pages/server_details/server_settings.dart
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
part of 'server_details.dart';
|
||||||
|
|
||||||
|
class _ServerSettings extends StatelessWidget {
|
||||||
|
const _ServerSettings({
|
||||||
|
Key? key,
|
||||||
|
required this.tabController,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final TabController tabController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(
|
||||||
|
padding: brandPagePadding2,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
height: 52,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
padding: EdgeInsets.only(left: 1),
|
||||||
|
child: Container(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(BrandIcons.arrow_left),
|
||||||
|
onPressed: () => tabController.animateTo(0),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
BrandText.h4('basis.settings'.tr()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BrandDivider(),
|
||||||
|
SwitcherBlock(
|
||||||
|
onChange: (_) {},
|
||||||
|
child: _TextColumn(
|
||||||
|
title: 'Allow Auto-upgrade',
|
||||||
|
value: 'Wether to allow automatic packages upgrades',
|
||||||
|
),
|
||||||
|
isActive: true,
|
||||||
|
),
|
||||||
|
SwitcherBlock(
|
||||||
|
onChange: (_) {},
|
||||||
|
child: _TextColumn(
|
||||||
|
title: 'Reboot after upgrade',
|
||||||
|
value: 'Reboot without prompt after applying updates',
|
||||||
|
),
|
||||||
|
isActive: false,
|
||||||
|
),
|
||||||
|
_Button(
|
||||||
|
onTap: () {},
|
||||||
|
child: _TextColumn(
|
||||||
|
title: 'Server Timezone',
|
||||||
|
value: 'Europe/Kyiv',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_Button(
|
||||||
|
onTap: () {},
|
||||||
|
child: _TextColumn(
|
||||||
|
title: 'Server Locale',
|
||||||
|
value: 'Default',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_Button(
|
||||||
|
onTap: () {},
|
||||||
|
child: _TextColumn(
|
||||||
|
hasWarning: true,
|
||||||
|
title: 'Factory Reset',
|
||||||
|
value: 'Restore default settings on your server',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Button extends StatelessWidget {
|
||||||
|
const _Button({
|
||||||
|
Key? key,
|
||||||
|
required this.onTap,
|
||||||
|
required this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(top: 20, bottom: 5),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(width: 1, color: BrandColors.dividerColor),
|
||||||
|
)),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TextColumn extends StatelessWidget {
|
||||||
|
const _TextColumn({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.value,
|
||||||
|
this.hasWarning = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final String value;
|
||||||
|
final bool hasWarning;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
BrandText.body1(
|
||||||
|
title,
|
||||||
|
style: TextStyle(color: hasWarning ? BrandColors.warning : null),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
BrandText.body1(
|
||||||
|
value,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
height: 1.53,
|
||||||
|
color: hasWarning ? BrandColors.warning : BrandColors.gray1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/config/text_themes.dart';
|
import 'package:selfprivacy/config/text_themes.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/models/state_types.dart';
|
import 'package:selfprivacy/logic/models/state_types.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
|
import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||||
|
@ -13,6 +14,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';
|
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
|
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import '../rootRoute.dart';
|
import '../rootRoute.dart';
|
||||||
|
@ -105,10 +107,10 @@ class _Card extends StatelessWidget {
|
||||||
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
|
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
|
||||||
var changeTab = context.read<ChangeTab>().onPress;
|
var changeTab = context.read<ChangeTab>().onPress;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => showModalBottomSheet<void>(
|
onTap: () => showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
// isScrollControlled: true,
|
||||||
backgroundColor: Colors.transparent,
|
// backgroundColor: Colors.transparent,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return _ServiceDetails(
|
return _ServiceDetails(
|
||||||
serviceType: serviceType,
|
serviceType: serviceType,
|
||||||
|
@ -170,9 +172,7 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
late Widget child;
|
late Widget child;
|
||||||
|
|
||||||
var config = context.watch<AppConfigCubit>().state;
|
var config = context.watch<AppConfigCubit>().state;
|
||||||
var domainName = config.isDomainFilled
|
var domainName = UiHelpers.getDomainName(config);
|
||||||
? config.cloudFlareDomain!.domainName!
|
|
||||||
: 'example.com';
|
|
||||||
|
|
||||||
var linksStyle = body1Style.copyWith(
|
var linksStyle = body1Style.copyWith(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
|
@ -181,7 +181,6 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
: BrandColors.black,
|
: BrandColors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
decoration: TextDecoration.underline,
|
decoration: TextDecoration.underline,
|
||||||
// height: 1.1,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var textStyle = body1Style.copyWith(
|
var textStyle = body1Style.copyWith(
|
||||||
|
@ -198,9 +197,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
text: 'services.mail.bottom_sheet.1'.tr(args: [domainName]),
|
text: 'services.mail.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
child: Text(
|
child: Text(
|
||||||
'services.mail.bottom_sheet.2'.tr(),
|
'services.mail.bottom_sheet.2'.tr(),
|
||||||
|
@ -236,9 +236,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
.tr(args: [domainName]),
|
.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _launchURL('https://password.$domainName'),
|
onTap: () => _launchURL('https://password.$domainName'),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -259,9 +260,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
text: 'services.video.bottom_sheet.1'.tr(args: [domainName]),
|
text: 'services.video.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _launchURL('https://meet.$domainName'),
|
onTap: () => _launchURL('https://meet.$domainName'),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -282,9 +284,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
text: 'services.cloud.bottom_sheet.1'.tr(args: [domainName]),
|
text: 'services.cloud.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _launchURL('https://cloud.$domainName'),
|
onTap: () => _launchURL('https://cloud.$domainName'),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -306,9 +309,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
.tr(args: [domainName]),
|
.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _launchURL('https://social.$domainName'),
|
onTap: () => _launchURL('https://social.$domainName'),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -329,9 +333,10 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
text: 'services.git.bottom_sheet.1'.tr(args: [domainName]),
|
text: 'services.git.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
|
WidgetSpan(child: SizedBox(width: 5)),
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
padding: EdgeInsets.only(bottom: 0.8),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _launchURL('https://git.$domainName'),
|
onTap: () => _launchURL('https://git.$domainName'),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -345,13 +350,14 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return BrandModalSheet(
|
return Dialog(
|
||||||
child: Navigator(
|
shape: RoundedRectangleBorder(
|
||||||
key: navigatorKey,
|
borderRadius: BorderRadius.circular(20),
|
||||||
initialRoute: '/',
|
),
|
||||||
onGenerateRoute: (_) {
|
child: SingleChildScrollView(
|
||||||
return materialRoute(
|
child: Container(
|
||||||
Column(
|
width: 350,
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -359,22 +365,29 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 13),
|
|
||||||
IconStatusMask(
|
IconStatusMask(
|
||||||
status: status,
|
status: status,
|
||||||
child: Icon(icon, size: 40, color: Colors.white),
|
child: Icon(icon, size: 40, color: Colors.white),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
BrandText.h1(title),
|
BrandText.h2(title),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
child,
|
child,
|
||||||
|
SizedBox(height: 40),
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
child: BrandButton.rised(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
title: 'basis.close'.tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -397,3 +410,252 @@ class _ServiceDetails extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// class _ServiceDetails extends StatelessWidget {
|
||||||
|
// const _ServiceDetails({
|
||||||
|
// Key? key,
|
||||||
|
// required this.serviceType,
|
||||||
|
// required this.icon,
|
||||||
|
// required this.status,
|
||||||
|
// required this.title,
|
||||||
|
// required this.changeTab,
|
||||||
|
// }) : super(key: key);
|
||||||
|
|
||||||
|
// final ServiceTypes serviceType;
|
||||||
|
// final IconData icon;
|
||||||
|
// final StateType status;
|
||||||
|
// final String title;
|
||||||
|
// final ValueChanged<int> changeTab;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// late Widget child;
|
||||||
|
|
||||||
|
// var config = context.watch<AppConfigCubit>().state;
|
||||||
|
// var domainName = UiHelpers.getDomainName(config);
|
||||||
|
|
||||||
|
// var linksStyle = body1Style.copyWith(
|
||||||
|
// fontSize: 15,
|
||||||
|
// color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
// ? Colors.white
|
||||||
|
// : BrandColors.black,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// decoration: TextDecoration.underline,
|
||||||
|
// // height: 1.1,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// var textStyle = body1Style.copyWith(
|
||||||
|
// color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
// ? Colors.white
|
||||||
|
// : BrandColors.black,
|
||||||
|
// );
|
||||||
|
// switch (serviceType) {
|
||||||
|
// case ServiceTypes.mail:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.mail.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// child: Text(
|
||||||
|
// 'services.mail.bottom_sheet.2'.tr(),
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// onTap: () {
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// changeTab(2);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.messenger:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.messenger.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.passwordManager:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.password_manager.bottom_sheet.1'
|
||||||
|
// .tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () => _launchURL('https://password.$domainName'),
|
||||||
|
// child: Text(
|
||||||
|
// 'password.$domainName',
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.video:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.video.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () => _launchURL('https://meet.$domainName'),
|
||||||
|
// child: Text(
|
||||||
|
// 'meet.$domainName',
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.cloud:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.cloud.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () => _launchURL('https://cloud.$domainName'),
|
||||||
|
// child: Text(
|
||||||
|
// 'cloud.$domainName',
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.socialNetwork:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.social_network.bottom_sheet.1'
|
||||||
|
// .tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () => _launchURL('https://social.$domainName'),
|
||||||
|
// child: Text(
|
||||||
|
// 'social.$domainName',
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case ServiceTypes.git:
|
||||||
|
// child = RichText(
|
||||||
|
// text: TextSpan(
|
||||||
|
// children: [
|
||||||
|
// TextSpan(
|
||||||
|
// text: 'services.git.bottom_sheet.1'.tr(args: [domainName]),
|
||||||
|
// style: textStyle,
|
||||||
|
// ),
|
||||||
|
// WidgetSpan(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: EdgeInsets.only(bottom: 0.8, left: 5),
|
||||||
|
// child: GestureDetector(
|
||||||
|
// onTap: () => _launchURL('https://git.$domainName'),
|
||||||
|
// child: Text(
|
||||||
|
// 'git.$domainName',
|
||||||
|
// style: linksStyle,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// return BrandModalSheet(
|
||||||
|
// child: Navigator(
|
||||||
|
// key: navigatorKey,
|
||||||
|
// initialRoute: '/',
|
||||||
|
// onGenerateRoute: (_) {
|
||||||
|
// return materialRoute(
|
||||||
|
// Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Padding(
|
||||||
|
// padding: brandPagePadding1,
|
||||||
|
// child: Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// SizedBox(height: 13),
|
||||||
|
// IconStatusMask(
|
||||||
|
// status: status,
|
||||||
|
// child: Icon(icon, size: 40, color: Colors.white),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
// BrandText.h1(title),
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
// child,
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void _launchURL(url) async {
|
||||||
|
// var _possible = await canLaunch(url);
|
||||||
|
|
||||||
|
// if (_possible) {
|
||||||
|
// try {
|
||||||
|
// await launch(
|
||||||
|
// url,
|
||||||
|
// forceSafariVC: true,
|
||||||
|
// enableJavaScript: true,
|
||||||
|
// );
|
||||||
|
// } catch (e) {
|
||||||
|
// print(e);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// throw 'Could not launch $url';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,12 @@ class _NewUser extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var config = context.watch<AppConfigCubit>().state;
|
var config = context.watch<AppConfigCubit>().state;
|
||||||
|
|
||||||
var domainName = config.isDomainFilled
|
var domainName = UiHelpers.getDomainName(config);
|
||||||
? config.cloudFlareDomain!.domainName!
|
|
||||||
: 'example.com';
|
|
||||||
|
|
||||||
return BrandModalSheet(
|
return BrandModalSheet(
|
||||||
child: BlocProvider(
|
child: BlocProvider(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
UserFormCubit(usersCubit: context.watch<UsersCubit>()),
|
UserFormCubit(usersCubit: context.read<UsersCubit>()),
|
||||||
child: Builder(builder: (context) {
|
child: Builder(builder: (context) {
|
||||||
var formCubitState = context.watch<UserFormCubit>().state;
|
var formCubitState = context.watch<UserFormCubit>().state;
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@ class _UserDetails extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var config = context.watch<AppConfigCubit>().state;
|
var config = context.watch<AppConfigCubit>().state;
|
||||||
|
|
||||||
var domainName = config.isDomainFilled
|
var domainName = UiHelpers.getDomainName(config);
|
||||||
? config.cloudFlareDomain!.domainName!
|
|
||||||
: 'example.com';
|
|
||||||
|
|
||||||
return BrandModalSheet(
|
return BrandModalSheet(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -44,8 +42,8 @@ class _UserDetails extends StatelessWidget {
|
||||||
),
|
),
|
||||||
onSelected: (PopupMenuItemType result) {
|
onSelected: (PopupMenuItemType result) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case PopupMenuItemType.reset:
|
// case PopupMenuItemType.reset:
|
||||||
break;
|
// break;
|
||||||
case PopupMenuItemType.delete:
|
case PopupMenuItemType.delete:
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -88,13 +86,13 @@ class _UserDetails extends StatelessWidget {
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.more_vert),
|
icon: Icon(Icons.more_vert),
|
||||||
itemBuilder: (BuildContext context) => [
|
itemBuilder: (BuildContext context) => [
|
||||||
PopupMenuItem<PopupMenuItemType>(
|
// PopupMenuItem<PopupMenuItemType>(
|
||||||
value: PopupMenuItemType.reset,
|
// value: PopupMenuItemType.reset,
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: EdgeInsets.only(left: 5),
|
// padding: EdgeInsets.only(left: 5),
|
||||||
child: Text('users.reset_password'.tr()),
|
// child: Text('users.reset_password'.tr()),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
PopupMenuItem<PopupMenuItemType>(
|
PopupMenuItem<PopupMenuItemType>(
|
||||||
value: PopupMenuItemType.delete,
|
value: PopupMenuItemType.delete,
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -145,7 +143,7 @@ class _UserDetails extends StatelessWidget {
|
||||||
SizedBox(height: 24),
|
SizedBox(height: 24),
|
||||||
BrandDivider(),
|
BrandDivider(),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
BrandButton.iconText(
|
BrandButton.emptyWithIconText(
|
||||||
title: 'users.send_regisration_data'.tr(),
|
title: 'users.send_regisration_data'.tr(),
|
||||||
icon: Icon(BrandIcons.share),
|
icon: Icon(BrandIcons.share),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
|
@ -161,6 +159,6 @@ class _UserDetails extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PopupMenuItemType {
|
enum PopupMenuItemType {
|
||||||
reset,
|
// reset,
|
||||||
delete,
|
delete,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.da
|
||||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||||
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||||
|
|
||||||
part 'fab.dart';
|
part 'fab.dart';
|
||||||
part 'new_user.dart';
|
part 'new_user.dart';
|
||||||
|
|
|
@ -36,8 +36,10 @@ Function transitionsBuilder = (
|
||||||
class SlideBottomRoute extends PageRouteBuilder {
|
class SlideBottomRoute extends PageRouteBuilder {
|
||||||
SlideBottomRoute(this.widget)
|
SlideBottomRoute(this.widget)
|
||||||
: super(
|
: super(
|
||||||
|
transitionDuration: Duration(milliseconds: 150),
|
||||||
pageBuilder: pageBuilder(widget),
|
pageBuilder: pageBuilder(widget),
|
||||||
transitionsBuilder: transitionsBuilder as Widget Function(BuildContext, Animation<double>, Animation<double>, Widget),
|
transitionsBuilder: transitionsBuilder as Widget Function(
|
||||||
|
BuildContext, Animation<double>, Animation<double>, Widget),
|
||||||
);
|
);
|
||||||
|
|
||||||
final Widget widget;
|
final Widget widget;
|
||||||
|
|
9
lib/utils/ui_helpers.dart
Normal file
9
lib/utils/ui_helpers.dart
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
|
|
||||||
|
/// it's ui helpers use only for ui components, don't use for logic components.
|
||||||
|
|
||||||
|
class UiHelpers {
|
||||||
|
static String getDomainName(AppConfigState config) => config.isDomainFilled
|
||||||
|
? config.cloudFlareDomain!.domainName
|
||||||
|
: 'example.com';
|
||||||
|
}
|
14
pubspec.lock
14
pubspec.lock
|
@ -357,6 +357,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
hive_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: hive_generator
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -789,6 +796,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
unicons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: unicons
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -27,6 +27,7 @@ dependencies:
|
||||||
package_info: ^2.0.0
|
package_info: ^2.0.0
|
||||||
pretty_dio_logger: ^1.1.1
|
pretty_dio_logger: ^1.1.1
|
||||||
provider: ^5.0.0
|
provider: ^5.0.0
|
||||||
|
unicons: ^1.0.2
|
||||||
url_launcher: ^6.0.2
|
url_launcher: ^6.0.2
|
||||||
wakelock: ^0.5.0+2
|
wakelock: ^0.5.0+2
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ dev_dependencies:
|
||||||
basic_utils: ^3.0.0-nullsafety.1
|
basic_utils: ^3.0.0-nullsafety.1
|
||||||
build_runner: ^1.11.5
|
build_runner: ^1.11.5
|
||||||
flutter_launcher_icons: ^0.9.0
|
flutter_launcher_icons: ^0.9.0
|
||||||
|
hive_generator: ^1.0.0
|
||||||
json_serializable: ^4.0.2
|
json_serializable: ^4.0.2
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
|
|
Loading…
Reference in a new issue