mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-11-19 07:09:14 +00:00
feat: Allow setting the provider token after recovery
This commit is contained in:
parent
51b6e0ab41
commit
efed52f3ec
|
@ -693,6 +693,11 @@
|
|||
"loading": "Loading token status",
|
||||
"used_by": "Used for {servers}.",
|
||||
"check_again": "Check again",
|
||||
"no_tokens": "No tokens"
|
||||
"no_tokens": "No tokens",
|
||||
"server_without_token": "{server_domain} has no token for {provider}.",
|
||||
"tap_to_add_token": "Tap here to add a token",
|
||||
"add_server_provider_token": "Add server provider token",
|
||||
"server_provider_unknown": "Unknown server provider",
|
||||
"server_provider_unknown_description": "Your server provider is not supported by this app version."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,13 @@ import 'package:selfprivacy/logic/get_it/resources_model.dart';
|
|||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/dns_provider_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
||||
import 'package:selfprivacy/logic/providers/backups_providers/backups_provider_factory.dart';
|
||||
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider_factory.dart';
|
||||
import 'package:selfprivacy/logic/providers/provider_settings.dart';
|
||||
import 'package:selfprivacy/logic/providers/providers_controller.dart';
|
||||
import 'package:selfprivacy/logic/providers/server_providers/server_provider_factory.dart';
|
||||
|
||||
part 'tokens_event.dart';
|
||||
|
@ -23,6 +26,12 @@ class TokensBloc extends Bloc<TokensEvent, TokensState> {
|
|||
validateTokens,
|
||||
transformer: droppable(),
|
||||
);
|
||||
on<AddServerProviderToken>(
|
||||
addServerProviderCredential,
|
||||
);
|
||||
on<ServerSelectedForProviderToken>(
|
||||
connectServerToProviderToken,
|
||||
);
|
||||
|
||||
add(const RevalidateTokens());
|
||||
|
||||
|
@ -154,6 +163,51 @@ class TokensBloc extends Bloc<TokensEvent, TokensState> {
|
|||
return TokenStatus.valid;
|
||||
}
|
||||
|
||||
Future<void> addServerProviderCredential(
|
||||
final AddServerProviderToken event,
|
||||
final Emitter<TokensState> emit,
|
||||
) async {
|
||||
await getIt<ResourcesModel>()
|
||||
.addServerProviderToken(event.serverProviderCredential);
|
||||
|
||||
final ServerProviderSettings settings = ServerProviderSettings(
|
||||
provider: event.serverProviderCredential.provider,
|
||||
token: event.serverProviderCredential.token,
|
||||
isAuthorized: true,
|
||||
);
|
||||
ProvidersController.initServerProvider(settings);
|
||||
}
|
||||
|
||||
Future<void> connectServerToProviderToken(
|
||||
final ServerSelectedForProviderToken event,
|
||||
final Emitter<TokensState> emit,
|
||||
) async {
|
||||
await getIt<ResourcesModel>().associateServerWithToken(
|
||||
event.providerServer.id,
|
||||
event.serverProviderCredential.token,
|
||||
);
|
||||
final Server newServerData = Server(
|
||||
domain: event.server.domain,
|
||||
hostingDetails: ServerHostingDetails(
|
||||
ip4: event.providerServer.ip,
|
||||
id: event.providerServer.id,
|
||||
createTime: event.providerServer.created,
|
||||
volume: ServerProviderVolume(
|
||||
id: 0,
|
||||
name: 'recovered_volume',
|
||||
sizeByte: 0,
|
||||
serverId: event.providerServer.id,
|
||||
linuxDevice: '',
|
||||
),
|
||||
apiToken: event.server.hostingDetails.apiToken,
|
||||
provider: event.serverProviderCredential.provider,
|
||||
serverLocation: event.server.hostingDetails.serverLocation,
|
||||
serverType: event.server.hostingDetails.serverType,
|
||||
),
|
||||
);
|
||||
await getIt<ResourcesModel>().updateServerByDomain(newServerData);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_resourcesModelSubscription.cancel();
|
||||
|
|
|
@ -10,3 +10,27 @@ class RevalidateTokens extends TokensEvent {
|
|||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class AddServerProviderToken extends TokensEvent {
|
||||
const AddServerProviderToken(this.serverProviderCredential);
|
||||
|
||||
final ServerProviderCredential serverProviderCredential;
|
||||
|
||||
@override
|
||||
List<Object> get props => [serverProviderCredential];
|
||||
}
|
||||
|
||||
class ServerSelectedForProviderToken extends TokensEvent {
|
||||
const ServerSelectedForProviderToken(
|
||||
this.providerServer,
|
||||
this.server,
|
||||
this.serverProviderCredential,
|
||||
);
|
||||
|
||||
final ServerBasicInfoWithValidators providerServer;
|
||||
final Server server;
|
||||
final ServerProviderCredential serverProviderCredential;
|
||||
|
||||
@override
|
||||
List<Object> get props => [providerServer, server, serverProviderCredential];
|
||||
}
|
||||
|
|
|
@ -26,6 +26,21 @@ sealed class TokensState extends Equatable {
|
|||
List<TokenStatusWrapper<BackupsCredential>> get backupsCredentials;
|
||||
List<Server> get servers => _servers;
|
||||
|
||||
List<Server> get serversWithoutProviderCredentials => servers
|
||||
.where(
|
||||
(final Server server) =>
|
||||
server.hostingDetails.provider != ServerProviderType.unknown &&
|
||||
serverProviderCredentials.every(
|
||||
(
|
||||
final TokenStatusWrapper<ServerProviderCredential>
|
||||
serverProviderCredential,
|
||||
) =>
|
||||
!serverProviderCredential.data.associatedServerIds
|
||||
.contains(server.hostingDetails.id),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
Server getServerById(final int serverId) => servers.firstWhere(
|
||||
(final Server server) => server.hostingDetails.id == serverId,
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:equatable/equatable.dart';
|
|||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
|
||||
import 'package:selfprivacy/logic/get_it/resources_model.dart';
|
||||
import 'package:selfprivacy/logic/models/disk_size.dart';
|
||||
import 'package:selfprivacy/logic/models/disk_status.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
|
@ -68,10 +69,18 @@ class VolumesBloc extends Bloc<VolumesEvent, VolumesState> {
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
_resourcesModelSubscription =
|
||||
getIt<ResourcesModel>().statusStream.listen((final event) {
|
||||
if (event is ChangedServerProviderCredentials) {
|
||||
add(const VolumesServerLoaded());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
late StreamSubscription _apiStatusSubscription;
|
||||
late StreamSubscription _apiDataSubscription;
|
||||
late StreamSubscription _resourcesModelSubscription;
|
||||
bool isLoaded = false;
|
||||
|
||||
Future<Price?> getPricePerGb() async {
|
||||
|
@ -145,6 +154,7 @@ class VolumesBloc extends Bloc<VolumesEvent, VolumesState> {
|
|||
Future<void> close() async {
|
||||
await _apiStatusSubscription.cancel();
|
||||
await _apiDataSubscription.cancel();
|
||||
await _resourcesModelSubscription.cancel();
|
||||
await super.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cubit_form/cubit_form.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
|
||||
class AddServerProviderToExistingServerFormCubit extends FormCubit {
|
||||
AddServerProviderToExistingServerFormCubit(
|
||||
this.serverInstallationCubit,
|
||||
this.setServerProviderKey,
|
||||
) {
|
||||
apiKey = FieldCubit(
|
||||
initalValue: '',
|
||||
validations: [
|
||||
RequiredStringValidation('validations.required'.tr()),
|
||||
],
|
||||
);
|
||||
|
||||
super.addFields([apiKey]);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> onSubmit() async {
|
||||
// serverInstallationCubit.setServerProviderKey(apiKey.state.value);
|
||||
setServerProviderKey(apiKey.state.value);
|
||||
}
|
||||
|
||||
final ServerInstallationCubit serverInstallationCubit;
|
||||
final Function(String) setServerProviderKey;
|
||||
late final FieldCubit<String> apiKey;
|
||||
|
||||
@override
|
||||
FutureOr<bool> asyncValidation() async {
|
||||
bool? isKeyValid;
|
||||
|
||||
try {
|
||||
isKeyValid = await serverInstallationCubit
|
||||
.isServerProviderApiTokenValid(apiKey.state.value);
|
||||
} catch (e) {
|
||||
addError(e);
|
||||
}
|
||||
|
||||
if (isKeyValid == null) {
|
||||
apiKey.setError('');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isKeyValid) {
|
||||
apiKey.setError('initializing.provider_bad_key_error'.tr());
|
||||
}
|
||||
|
||||
return isKeyValid;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import 'package:selfprivacy/logic/models/callback_dialogue_branching.dart';
|
|||
import 'package:selfprivacy/logic/models/disk_size.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
|
@ -708,29 +709,54 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<List<ServerBasicInfoWithValidators>> getAvailableServers() async {
|
||||
final ServerInstallationRecovery dataState =
|
||||
state as ServerInstallationRecovery;
|
||||
final List<ServerBasicInfo> servers =
|
||||
await repository.getServersOnProviderAccount();
|
||||
Future<List<ServerBasicInfoWithValidators>> getAvailableServers({
|
||||
final Server? server,
|
||||
}) async {
|
||||
List<ServerBasicInfoWithValidators> validatedList = [];
|
||||
try {
|
||||
final Iterable<ServerBasicInfoWithValidators> validated = servers.map(
|
||||
(final ServerBasicInfo server) =>
|
||||
ServerBasicInfoWithValidators.fromServerBasicInfo(
|
||||
serverBasicInfo: server,
|
||||
isIpValid: server.ip == dataState.serverDetails?.ip4,
|
||||
isReverseDnsValid:
|
||||
server.reverseDns == dataState.serverDomain?.domainName ||
|
||||
server.reverseDns ==
|
||||
dataState.serverDomain?.domainName.split('.')[0],
|
||||
),
|
||||
);
|
||||
validatedList = validated.toList();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('modals.server_validators_error'.tr());
|
||||
if (server != null) {
|
||||
final List<ServerBasicInfo> servers =
|
||||
await repository.getServersOnProviderAccount();
|
||||
try {
|
||||
final Iterable<ServerBasicInfoWithValidators> validated = servers.map(
|
||||
(final ServerBasicInfo hostingServer) =>
|
||||
ServerBasicInfoWithValidators.fromServerBasicInfo(
|
||||
serverBasicInfo: hostingServer,
|
||||
isIpValid: hostingServer.ip == server.hostingDetails.ip4,
|
||||
isReverseDnsValid:
|
||||
hostingServer.reverseDns == server.domain.domainName ||
|
||||
hostingServer.reverseDns ==
|
||||
server.domain.domainName.split('.')[0],
|
||||
),
|
||||
);
|
||||
validatedList = validated.toList();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('modals.server_validators_error'.tr());
|
||||
}
|
||||
} else {
|
||||
final ServerInstallationRecovery dataState =
|
||||
state as ServerInstallationRecovery;
|
||||
final List<ServerBasicInfo> servers =
|
||||
await repository.getServersOnProviderAccount();
|
||||
try {
|
||||
final Iterable<ServerBasicInfoWithValidators> validated = servers.map(
|
||||
(final ServerBasicInfo server) =>
|
||||
ServerBasicInfoWithValidators.fromServerBasicInfo(
|
||||
serverBasicInfo: server,
|
||||
isIpValid: server.ip == dataState.serverDetails?.ip4,
|
||||
isReverseDnsValid:
|
||||
server.reverseDns == dataState.serverDomain?.domainName ||
|
||||
server.reverseDns ==
|
||||
dataState.serverDomain?.domainName.split('.')[0],
|
||||
),
|
||||
);
|
||||
validatedList = validated.toList();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('modals.server_validators_error'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
return validatedList;
|
||||
|
|
|
@ -173,6 +173,17 @@ class ResourcesModel {
|
|||
_statusStreamController.add(const ChangedServers());
|
||||
}
|
||||
|
||||
Future<void> updateServerByDomain(final Server server) async {
|
||||
final index = _servers.indexWhere(
|
||||
(final s) => s.domain.domainName == server.domain.domainName,
|
||||
);
|
||||
if (index != -1) {
|
||||
_servers[index] = server;
|
||||
await _box.put(BNames.servers, _servers);
|
||||
_statusStreamController.add(const ChangedServers());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setBackblazeBucket(final BackblazeBucket bucket) async {
|
||||
_backblazeBucket = bucket;
|
||||
await _box.put(BNames.backblazeBucket, _backblazeBucket);
|
||||
|
|
|
@ -117,6 +117,12 @@ enum ServerProviderType {
|
|||
hetzner => 'Hetzner Cloud',
|
||||
unknown => 'Unknown',
|
||||
};
|
||||
|
||||
String get supportArticle => switch (this) {
|
||||
digitalOcean => 'how_digital_ocean',
|
||||
hetzner => 'how_hetzner',
|
||||
unknown => '',
|
||||
};
|
||||
}
|
||||
|
||||
extension ServerProviderTypeIsSpecified on ServerProviderType? {
|
||||
|
|
167
lib/ui/pages/more/tokens/add_server_provider_token.dart
Normal file
167
lib/ui/pages/more/tokens/add_server_provider_token.dart
Normal file
|
@ -0,0 +1,167 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:cubit_form/cubit_form.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:selfprivacy/logic/bloc/tokens/tokens_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/forms/setup/initializing/add_server_provider_to_exsisting_server_form_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_confirm_server.dart';
|
||||
|
||||
@RoutePage()
|
||||
class AddServerProviderTokenPage extends StatefulWidget {
|
||||
const AddServerProviderTokenPage({
|
||||
required this.server,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Server server;
|
||||
|
||||
@override
|
||||
State<AddServerProviderTokenPage> createState() =>
|
||||
_AddServerProviderTokenPageState();
|
||||
}
|
||||
|
||||
class _AddServerProviderTokenPageState
|
||||
extends State<AddServerProviderTokenPage> {
|
||||
bool isChoosingServer = false;
|
||||
ServerProviderCredential? credential;
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
final ServerInstallationCubit appConfig =
|
||||
context.watch<ServerInstallationCubit>();
|
||||
|
||||
void setServerProviderKey(final String key) {
|
||||
final newCredential = ServerProviderCredential(
|
||||
token: key,
|
||||
provider: widget.server.hostingDetails.provider,
|
||||
tokenId: null,
|
||||
associatedServerIds: [],
|
||||
);
|
||||
context.read<TokensBloc>().add(
|
||||
AddServerProviderToken(newCredential),
|
||||
);
|
||||
setState(() {
|
||||
isChoosingServer = true;
|
||||
credential = newCredential;
|
||||
});
|
||||
}
|
||||
|
||||
if (isChoosingServer && credential != null) {
|
||||
return RecoveryConfirmServer(
|
||||
server: widget.server,
|
||||
serverProviderCredential: credential,
|
||||
submitCallback: () {
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.server.hostingDetails.provider == ServerProviderType.unknown) {
|
||||
return BrandHeroScreen(
|
||||
heroTitle: 'tokens.server_provider_unknown'.tr(),
|
||||
heroSubtitle: 'tokens.server_provider_unknown_description'.tr(),
|
||||
hasBackButton: true,
|
||||
hasFlashButton: false,
|
||||
ignoreBreakpoints: true,
|
||||
onBackButtonPressed: () {
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst);
|
||||
},
|
||||
children: [
|
||||
BrandButton.filled(
|
||||
text: 'basis.close'.tr(),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return _TokenProviderInput(
|
||||
appConfig: appConfig,
|
||||
server: widget.server,
|
||||
setServerProviderKey: setServerProviderKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TokenProviderInput extends StatelessWidget {
|
||||
const _TokenProviderInput({
|
||||
required this.appConfig,
|
||||
required this.server,
|
||||
required this.setServerProviderKey,
|
||||
});
|
||||
|
||||
final ServerInstallationCubit appConfig;
|
||||
final Server server;
|
||||
final Function(String) setServerProviderKey;
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => BlocProvider(
|
||||
create: (final BuildContext context) =>
|
||||
AddServerProviderToExistingServerFormCubit(
|
||||
appConfig,
|
||||
setServerProviderKey,
|
||||
),
|
||||
child: Builder(
|
||||
builder: (final BuildContext context) => BrandHeroScreen(
|
||||
heroTitle: 'recovering.provider_connected'.tr(
|
||||
args: [
|
||||
server.hostingDetails.provider.displayName,
|
||||
],
|
||||
),
|
||||
heroSubtitle: 'recovering.provider_connected_description'.tr(
|
||||
args: [server.domain.domainName],
|
||||
),
|
||||
hasBackButton: true,
|
||||
hasFlashButton: false,
|
||||
hasSupportDrawer: true,
|
||||
onBackButtonPressed: () {
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst);
|
||||
},
|
||||
children: [
|
||||
CubitFormTextField(
|
||||
autofocus: true,
|
||||
formFieldCubit: context
|
||||
.read<AddServerProviderToExistingServerFormCubit>()
|
||||
.apiKey,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'recovering.provider_connected_placeholder'.tr(
|
||||
args: [
|
||||
server.hostingDetails.provider.displayName,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(16),
|
||||
BrandButton.filled(
|
||||
onPressed: () => context
|
||||
.read<AddServerProviderToExistingServerFormCubit>()
|
||||
.trySubmit(),
|
||||
child: Text('basis.continue'.tr()),
|
||||
),
|
||||
const Gap(16),
|
||||
Builder(
|
||||
builder: (final context) => BrandButton.text(
|
||||
title: 'initializing.how'.tr(),
|
||||
onPressed: () => context
|
||||
.read<SupportSystemCubit>()
|
||||
.showArticle(
|
||||
article: server.hostingDetails.provider.supportArticle,
|
||||
context: context,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
|
@ -10,6 +10,7 @@ import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart';
|
|||
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
||||
import 'package:selfprivacy/ui/components/list_tiles/list_tile_on_surface_variant.dart';
|
||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||
import 'package:selfprivacy/ui/router/router.dart';
|
||||
|
||||
@RoutePage()
|
||||
class TokensPage extends StatelessWidget {
|
||||
|
@ -29,10 +30,7 @@ class TokensPage extends StatelessWidget {
|
|||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.server_provider_tokens'.tr(),
|
||||
),
|
||||
Divider(
|
||||
height: 0,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
const Divider(height: 0),
|
||||
if (state.serverProviderCredentials.isEmpty)
|
||||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.no_tokens'.tr(),
|
||||
|
@ -48,6 +46,34 @@ class TokensPage extends StatelessWidget {
|
|||
)
|
||||
.toList(),
|
||||
),
|
||||
if (state.serversWithoutProviderCredentials.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
const Divider(height: 0),
|
||||
Column(
|
||||
children: state.serversWithoutProviderCredentials
|
||||
.map(
|
||||
(final server) => ListTileOnSurfaceVariant(
|
||||
title: 'tokens.server_without_token'.tr(
|
||||
namedArgs: {
|
||||
'server_domain': server.domain.domainName,
|
||||
'provider': server
|
||||
.hostingDetails.provider.displayName,
|
||||
},
|
||||
),
|
||||
subtitle: 'tokens.tap_to_add_token'.tr(),
|
||||
leadingIcon: Icons.add_circle_outline,
|
||||
onTap: () => context.router.push(
|
||||
AddServerProviderTokenRoute(
|
||||
server: server,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -58,10 +84,7 @@ class TokensPage extends StatelessWidget {
|
|||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.dns_provider_tokens'.tr(),
|
||||
),
|
||||
Divider(
|
||||
height: 0,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
const Divider(height: 0),
|
||||
if (state.dnsProviderCredentials.isEmpty)
|
||||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.no_tokens'.tr(),
|
||||
|
@ -86,10 +109,7 @@ class TokensPage extends StatelessWidget {
|
|||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.backup_provider_tokens'.tr(),
|
||||
),
|
||||
Divider(
|
||||
height: 0,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
const Divider(height: 0),
|
||||
if (state.backupsCredentials.isEmpty)
|
||||
ListTileOnSurfaceVariant(
|
||||
title: 'tokens.no_tokens'.tr(),
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/logic/bloc/tokens/tokens_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||
|
||||
class RecoveryConfirmServer extends StatefulWidget {
|
||||
const RecoveryConfirmServer({super.key});
|
||||
const RecoveryConfirmServer({
|
||||
this.server,
|
||||
this.serverProviderCredential,
|
||||
this.submitCallback,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Server? server;
|
||||
final ServerProviderCredential? serverProviderCredential;
|
||||
final Function? submitCallback;
|
||||
|
||||
@override
|
||||
State<RecoveryConfirmServer> createState() => _RecoveryConfirmServerState();
|
||||
|
@ -45,8 +57,9 @@ class _RecoveryConfirmServerState extends State<RecoveryConfirmServer> {
|
|||
hasFlashButton: false,
|
||||
children: [
|
||||
FutureBuilder<List<ServerBasicInfoWithValidators>>(
|
||||
future:
|
||||
context.read<ServerInstallationCubit>().getAvailableServers(),
|
||||
future: context
|
||||
.read<ServerInstallationCubit>()
|
||||
.getAvailableServers(server: widget.server),
|
||||
builder: (final context, final snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final servers = snapshot.data;
|
||||
|
@ -248,8 +261,21 @@ class _RecoveryConfirmServerState extends State<RecoveryConfirmServer> {
|
|||
TextButton(
|
||||
child: Text('modals.yes'.tr()),
|
||||
onPressed: () {
|
||||
context.read<ServerInstallationCubit>().setServerId(server);
|
||||
Navigator.of(context).pop();
|
||||
if (widget.server != null &&
|
||||
widget.serverProviderCredential != null) {
|
||||
context.read<TokensBloc>().add(
|
||||
ServerSelectedForProviderToken(
|
||||
server,
|
||||
widget.server!,
|
||||
widget.serverProviderCredential!,
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
widget.submitCallback?.call();
|
||||
} else {
|
||||
context.read<ServerInstallationCubit>().setServerId(server);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:animations/animations.dart';
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/logic/models/disk_status.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
import 'package:selfprivacy/ui/pages/backups/backup_details.dart';
|
||||
import 'package:selfprivacy/ui/pages/backups/backups_list.dart';
|
||||
|
@ -12,6 +13,7 @@ import 'package:selfprivacy/ui/pages/more/app_settings/app_settings.dart';
|
|||
import 'package:selfprivacy/ui/pages/more/app_settings/developer_settings.dart';
|
||||
import 'package:selfprivacy/ui/pages/more/console/console_page.dart';
|
||||
import 'package:selfprivacy/ui/pages/more/more.dart';
|
||||
import 'package:selfprivacy/ui/pages/more/tokens/add_server_provider_token.dart';
|
||||
import 'package:selfprivacy/ui/pages/more/tokens/tokens_page.dart';
|
||||
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
|
||||
import 'package:selfprivacy/ui/pages/providers/providers.dart';
|
||||
|
@ -111,6 +113,7 @@ class RootRouter extends _$RootRouter {
|
|||
AutoRoute(page: ServerLogsRoute.page),
|
||||
AutoRoute(page: TokensRoute.page),
|
||||
AutoRoute(page: MemoryUsageByServiceRoute.page),
|
||||
AutoRoute(page: AddServerProviderTokenRoute.page),
|
||||
],
|
||||
),
|
||||
AutoRoute(page: ServicesMigrationRoute.page),
|
||||
|
@ -170,6 +173,8 @@ String getRouteTitle(final String routeName) {
|
|||
return 'tokens.title';
|
||||
case 'MemoryUsageByServiceRoute':
|
||||
return 'resource_chart.memory';
|
||||
case 'AddServerProviderTokenPage':
|
||||
return 'tokens.add_server_provider_token';
|
||||
default:
|
||||
return routeName;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,16 @@ abstract class _$RootRouter extends RootStackRouter {
|
|||
child: const AboutApplicationPage(),
|
||||
);
|
||||
},
|
||||
AddServerProviderTokenRoute.name: (routeData) {
|
||||
final args = routeData.argsAs<AddServerProviderTokenRouteArgs>();
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
child: AddServerProviderTokenPage(
|
||||
server: args.server,
|
||||
key: args.key,
|
||||
),
|
||||
);
|
||||
},
|
||||
AppSettingsRoute.name: (routeData) {
|
||||
return AutoRoutePage<dynamic>(
|
||||
routeData: routeData,
|
||||
|
@ -242,6 +252,45 @@ class AboutApplicationRoute extends PageRouteInfo<void> {
|
|||
static const PageInfo<void> page = PageInfo<void>(name);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AddServerProviderTokenPage]
|
||||
class AddServerProviderTokenRoute
|
||||
extends PageRouteInfo<AddServerProviderTokenRouteArgs> {
|
||||
AddServerProviderTokenRoute({
|
||||
required Server server,
|
||||
Key? key,
|
||||
List<PageRouteInfo>? children,
|
||||
}) : super(
|
||||
AddServerProviderTokenRoute.name,
|
||||
args: AddServerProviderTokenRouteArgs(
|
||||
server: server,
|
||||
key: key,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
static const String name = 'AddServerProviderTokenRoute';
|
||||
|
||||
static const PageInfo<AddServerProviderTokenRouteArgs> page =
|
||||
PageInfo<AddServerProviderTokenRouteArgs>(name);
|
||||
}
|
||||
|
||||
class AddServerProviderTokenRouteArgs {
|
||||
const AddServerProviderTokenRouteArgs({
|
||||
required this.server,
|
||||
this.key,
|
||||
});
|
||||
|
||||
final Server server;
|
||||
|
||||
final Key? key;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AddServerProviderTokenRouteArgs{server: $server, key: $key}';
|
||||
}
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [AppSettingsPage]
|
||||
class AppSettingsRoute extends PageRouteInfo<void> {
|
||||
|
|
Loading…
Reference in a new issue