mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-02-02 14:16:58 +00:00
refactor: Replace RecoveryKeyCubit with RecoveryKeyBloc
This commit is contained in:
parent
1daf957245
commit
3a525f0d11
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/connection_status/connection_status_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/recovery_key/recovery_key_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
|
||||
|
@ -9,7 +10,6 @@ import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
|||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/devices/devices_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
|
||||
|
@ -31,7 +31,7 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
late final ServicesBloc servicesBloc;
|
||||
late final BackupsBloc backupsBloc;
|
||||
late final DnsRecordsCubit dnsRecordsCubit;
|
||||
late final RecoveryKeyCubit recoveryKeyCubit;
|
||||
late final RecoveryKeyBloc recoveryKeyBloc;
|
||||
late final ApiDevicesCubit apiDevicesCubit;
|
||||
late final ServerJobsBloc serverJobsBloc;
|
||||
late final ConnectionStatusBloc connectionStatusBloc;
|
||||
|
@ -47,7 +47,7 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
servicesBloc = ServicesBloc();
|
||||
backupsBloc = BackupsBloc();
|
||||
dnsRecordsCubit = DnsRecordsCubit();
|
||||
recoveryKeyCubit = RecoveryKeyCubit();
|
||||
recoveryKeyBloc = RecoveryKeyBloc();
|
||||
apiDevicesCubit = ApiDevicesCubit();
|
||||
serverJobsBloc = ServerJobsBloc();
|
||||
connectionStatusBloc = ConnectionStatusBloc();
|
||||
|
@ -90,7 +90,7 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
create: (final _) => dnsRecordsCubit,
|
||||
),
|
||||
BlocProvider(
|
||||
create: (final _) => recoveryKeyCubit,
|
||||
create: (final _) => recoveryKeyBloc,
|
||||
),
|
||||
BlocProvider(
|
||||
create: (final _) => apiDevicesCubit,
|
||||
|
|
94
lib/logic/bloc/recovery_key/recovery_key_bloc.dart
Normal file
94
lib/logic/bloc/recovery_key/recovery_key_bloc.dart
Normal file
|
@ -0,0 +1,94 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_concurrency/bloc_concurrency.dart';
|
||||
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/models/json/recovery_token_status.dart';
|
||||
|
||||
part 'recovery_key_event.dart';
|
||||
part 'recovery_key_state.dart';
|
||||
|
||||
class RecoveryKeyBloc extends Bloc<RecoveryKeyEvent, RecoveryKeyState> {
|
||||
RecoveryKeyBloc() : super(RecoveryKeyInitial()) {
|
||||
on<RecoveryKeyStatusChanged>(
|
||||
_mapRecoveryKeyStatusChangedToState,
|
||||
transformer: sequential(),
|
||||
);
|
||||
on<CreateNewRecoveryKey>(
|
||||
_mapCreateNewRecoveryKeyToState,
|
||||
transformer: sequential(),
|
||||
);
|
||||
on<ConsumedNewRecoveryKey>(
|
||||
_mapRecoveryKeyStatusRefreshToState,
|
||||
transformer: sequential(),
|
||||
);
|
||||
on<RecoveryKeyStatusRefresh>(
|
||||
_mapRecoveryKeyStatusRefreshToState,
|
||||
transformer: droppable(),
|
||||
);
|
||||
|
||||
final apiConnectionRepository = getIt<ApiConnectionRepository>();
|
||||
_apiDataSubscription = apiConnectionRepository.dataStream.listen(
|
||||
(final ApiData apiData) {
|
||||
add(
|
||||
RecoveryKeyStatusChanged(apiData.recoveryKeyStatus.data),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
StreamSubscription? _apiDataSubscription;
|
||||
|
||||
Future<void> _mapRecoveryKeyStatusChangedToState(
|
||||
final RecoveryKeyStatusChanged event,
|
||||
final Emitter<RecoveryKeyState> emit,
|
||||
) async {
|
||||
if (state is RecoveryKeyCreating) {
|
||||
return;
|
||||
}
|
||||
if (event.recoveryKeyStatus == null) {
|
||||
emit(RecoveryKeyError());
|
||||
return;
|
||||
}
|
||||
emit(RecoveryKeyLoaded(keyStatus: event.recoveryKeyStatus));
|
||||
}
|
||||
|
||||
Future<void> _mapCreateNewRecoveryKeyToState(
|
||||
final CreateNewRecoveryKey event,
|
||||
final Emitter<RecoveryKeyState> emit,
|
||||
) async {
|
||||
emit(RecoveryKeyCreating());
|
||||
final GenericResult<String> response =
|
||||
await getIt<ApiConnectionRepository>().api.generateRecoveryToken(
|
||||
event.expirationDate,
|
||||
event.numberOfUses,
|
||||
);
|
||||
if (response.success) {
|
||||
emit(RecoveryKeyCreating(recoveryKey: response.data));
|
||||
} else {
|
||||
emit(RecoveryKeyCreating(error: response.message ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _mapRecoveryKeyStatusRefreshToState(
|
||||
final RecoveryKeyEvent event,
|
||||
final Emitter<RecoveryKeyState> emit,
|
||||
) async {
|
||||
emit(RecoveryKeyRefreshing(keyStatus: state._status));
|
||||
getIt<ApiConnectionRepository>().apiData.recoveryKeyStatus.invalidate();
|
||||
await getIt<ApiConnectionRepository>().reload(null);
|
||||
}
|
||||
|
||||
@override
|
||||
void onChange(final Change<RecoveryKeyState> change) {
|
||||
super.onChange(change);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_apiDataSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
41
lib/logic/bloc/recovery_key/recovery_key_event.dart
Normal file
41
lib/logic/bloc/recovery_key/recovery_key_event.dart
Normal file
|
@ -0,0 +1,41 @@
|
|||
part of 'recovery_key_bloc.dart';
|
||||
|
||||
sealed class RecoveryKeyEvent extends Equatable {
|
||||
const RecoveryKeyEvent();
|
||||
}
|
||||
|
||||
class RecoveryKeyStatusChanged extends RecoveryKeyEvent {
|
||||
const RecoveryKeyStatusChanged(this.recoveryKeyStatus);
|
||||
|
||||
final RecoveryKeyStatus? recoveryKeyStatus;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [recoveryKeyStatus];
|
||||
}
|
||||
|
||||
class CreateNewRecoveryKey extends RecoveryKeyEvent {
|
||||
const CreateNewRecoveryKey({
|
||||
this.expirationDate,
|
||||
this.numberOfUses,
|
||||
});
|
||||
|
||||
final DateTime? expirationDate;
|
||||
final int? numberOfUses;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [expirationDate, numberOfUses];
|
||||
}
|
||||
|
||||
class ConsumedNewRecoveryKey extends RecoveryKeyEvent {
|
||||
const ConsumedNewRecoveryKey();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class RecoveryKeyStatusRefresh extends RecoveryKeyEvent {
|
||||
const RecoveryKeyStatusRefresh();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
67
lib/logic/bloc/recovery_key/recovery_key_state.dart
Normal file
67
lib/logic/bloc/recovery_key/recovery_key_state.dart
Normal file
|
@ -0,0 +1,67 @@
|
|||
part of 'recovery_key_bloc.dart';
|
||||
|
||||
sealed class RecoveryKeyState extends Equatable {
|
||||
RecoveryKeyState({
|
||||
required final RecoveryKeyStatus? keyStatus,
|
||||
}) : _hashCode = keyStatus.hashCode;
|
||||
|
||||
final int _hashCode;
|
||||
|
||||
RecoveryKeyStatus get _status =>
|
||||
getIt<ApiConnectionRepository>().apiData.recoveryKeyStatus.data ??
|
||||
const RecoveryKeyStatus(exists: false, valid: false);
|
||||
|
||||
bool get exists => _status.exists;
|
||||
bool get isValid => _status.valid;
|
||||
DateTime? get generatedAt => _status.date;
|
||||
DateTime? get expiresAt => _status.expiration;
|
||||
int? get usesLeft => _status.usesLeft;
|
||||
|
||||
bool get isInvalidBecauseExpired =>
|
||||
_status.expiration != null &&
|
||||
_status.expiration!.isBefore(DateTime.now());
|
||||
|
||||
bool get isInvalidBecauseUsed =>
|
||||
_status.usesLeft != null && _status.usesLeft == 0;
|
||||
}
|
||||
|
||||
class RecoveryKeyInitial extends RecoveryKeyState {
|
||||
RecoveryKeyInitial()
|
||||
: super(keyStatus: const RecoveryKeyStatus(exists: false, valid: false));
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class RecoveryKeyRefreshing extends RecoveryKeyState {
|
||||
RecoveryKeyRefreshing({required super.keyStatus});
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class RecoveryKeyLoaded extends RecoveryKeyState {
|
||||
RecoveryKeyLoaded({required super.keyStatus});
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class RecoveryKeyError extends RecoveryKeyState {
|
||||
RecoveryKeyError()
|
||||
: super(keyStatus: const RecoveryKeyStatus(exists: false, valid: false));
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class RecoveryKeyCreating extends RecoveryKeyState {
|
||||
RecoveryKeyCreating({this.recoveryKey, this.error})
|
||||
: super(keyStatus: const RecoveryKeyStatus(exists: false, valid: false));
|
||||
|
||||
final String? recoveryKey;
|
||||
final String? error;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [_hashCode, recoveryKey, error];
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
||||
|
||||
part 'recovery_key_state.dart';
|
||||
|
||||
class RecoveryKeyCubit
|
||||
extends ServerConnectionDependentCubit<RecoveryKeyState> {
|
||||
RecoveryKeyCubit() : super(const RecoveryKeyState.initial());
|
||||
|
||||
final ServerApi api = ServerApi();
|
||||
|
||||
@override
|
||||
void load() async {
|
||||
// if (serverInstallationCubit.state is ServerInstallationFinished) {
|
||||
final RecoveryKeyStatus? status = await _getRecoveryKeyStatus();
|
||||
if (status == null) {
|
||||
emit(state.copyWith(loadingStatus: LoadingStatus.error));
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: status,
|
||||
loadingStatus: LoadingStatus.success,
|
||||
),
|
||||
);
|
||||
}
|
||||
// } else {
|
||||
// emit(state.copyWith(loadingStatus: LoadingStatus.uninitialized));
|
||||
// }
|
||||
}
|
||||
|
||||
Future<RecoveryKeyStatus?> _getRecoveryKeyStatus() async {
|
||||
final GenericResult<RecoveryKeyStatus?> response =
|
||||
await api.getRecoveryTokenStatus();
|
||||
if (response.success) {
|
||||
return response.data;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
emit(state.copyWith(loadingStatus: LoadingStatus.refreshing));
|
||||
final RecoveryKeyStatus? status = await _getRecoveryKeyStatus();
|
||||
if (status == null) {
|
||||
emit(state.copyWith(loadingStatus: LoadingStatus.error));
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(status: status, loadingStatus: LoadingStatus.success),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> generateRecoveryKey({
|
||||
final DateTime? expirationDate,
|
||||
final int? numberOfUses,
|
||||
}) async {
|
||||
final GenericResult<String> response =
|
||||
await api.generateRecoveryToken(expirationDate, numberOfUses);
|
||||
if (response.success) {
|
||||
unawaited(refresh());
|
||||
return response.data;
|
||||
} else {
|
||||
throw GenerationError(response.message ?? 'Unknown error');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void clear() {
|
||||
emit(state.copyWith(loadingStatus: LoadingStatus.uninitialized));
|
||||
}
|
||||
}
|
||||
|
||||
class GenerationError extends Error {
|
||||
GenerationError(this.message);
|
||||
final String message;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
part of 'recovery_key_cubit.dart';
|
||||
|
||||
class RecoveryKeyState extends ServerInstallationDependendState {
|
||||
const RecoveryKeyState(this._status, this.loadingStatus);
|
||||
|
||||
const RecoveryKeyState.initial()
|
||||
: this(
|
||||
const RecoveryKeyStatus(exists: false, valid: false),
|
||||
LoadingStatus.refreshing,
|
||||
);
|
||||
|
||||
final RecoveryKeyStatus _status;
|
||||
final LoadingStatus loadingStatus;
|
||||
|
||||
bool get exists => _status.exists;
|
||||
bool get isValid => _status.valid;
|
||||
DateTime? get generatedAt => _status.date;
|
||||
DateTime? get expiresAt => _status.expiration;
|
||||
int? get usesLeft => _status.usesLeft;
|
||||
|
||||
bool get isInvalidBecauseExpired =>
|
||||
_status.expiration != null &&
|
||||
_status.expiration!.isBefore(DateTime.now());
|
||||
|
||||
bool get isInvalidBecauseUsed =>
|
||||
_status.usesLeft != null && _status.usesLeft == 0;
|
||||
|
||||
@override
|
||||
List<Object> get props => [_status, loadingStatus];
|
||||
|
||||
RecoveryKeyState copyWith({
|
||||
final RecoveryKeyStatus? status,
|
||||
final LoadingStatus? loadingStatus,
|
||||
}) =>
|
||||
RecoveryKeyState(
|
||||
status ?? _status,
|
||||
loadingStatus ?? this.loadingStatus,
|
||||
);
|
||||
}
|
|
@ -8,6 +8,7 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.da
|
|||
import 'package:selfprivacy/logic/models/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
||||
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
|
||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
|
@ -101,6 +102,8 @@ class ApiConnectionRepository {
|
|||
_apiData.backups.data = await _apiData.backups.fetchData();
|
||||
_apiData.services.data = await _apiData.services.fetchData();
|
||||
_apiData.volumes.data = await _apiData.volumes.fetchData();
|
||||
_apiData.recoveryKeyStatus.data =
|
||||
await _apiData.recoveryKeyStatus.fetchData();
|
||||
_dataStream.add(_apiData);
|
||||
|
||||
connectionStatus = ConnectionStatus.connected;
|
||||
|
@ -140,6 +143,8 @@ class ApiConnectionRepository {
|
|||
.refetchData(version, () => _dataStream.add(_apiData));
|
||||
await _apiData.volumes
|
||||
.refetchData(version, () => _dataStream.add(_apiData));
|
||||
await _apiData.recoveryKeyStatus
|
||||
.refetchData(version, () => _dataStream.add(_apiData));
|
||||
}
|
||||
|
||||
void emitData() {
|
||||
|
@ -159,10 +164,12 @@ class ApiData {
|
|||
backupConfig = ApiDataElement<BackupConfiguration>(
|
||||
fetchData: () async => api.getBackupsConfiguration(),
|
||||
requiredApiVersion: '>=2.4.2',
|
||||
ttl: 120,
|
||||
),
|
||||
backups = ApiDataElement<List<Backup>>(
|
||||
fetchData: () async => api.getBackups(),
|
||||
requiredApiVersion: '>=2.4.2',
|
||||
ttl: 120,
|
||||
),
|
||||
services = ApiDataElement<List<Service>>(
|
||||
fetchData: () async => api.getAllServices(),
|
||||
|
@ -170,6 +177,10 @@ class ApiData {
|
|||
),
|
||||
volumes = ApiDataElement<List<ServerDiskVolume>>(
|
||||
fetchData: () async => api.getServerDiskVolumes(),
|
||||
),
|
||||
recoveryKeyStatus = ApiDataElement<RecoveryKeyStatus>(
|
||||
fetchData: () async => (await api.getRecoveryTokenStatus()).data,
|
||||
ttl: 300,
|
||||
);
|
||||
|
||||
ApiDataElement<List<ServerJob>> serverJobs;
|
||||
|
@ -178,6 +189,7 @@ class ApiData {
|
|||
ApiDataElement<List<Backup>> backups;
|
||||
ApiDataElement<List<Service>> services;
|
||||
ApiDataElement<List<ServerDiskVolume>> volumes;
|
||||
ApiDataElement<RecoveryKeyStatus> recoveryKeyStatus;
|
||||
}
|
||||
|
||||
enum ConnectionStatus {
|
||||
|
|
|
@ -4,8 +4,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/tls_options.dart';
|
||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/devices/devices_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart';
|
||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||
|
||||
@RoutePage()
|
||||
|
@ -89,18 +87,6 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('ApiDevicesCubit'),
|
||||
subtitle: Text(
|
||||
context.watch<ApiDevicesCubit>().state.status.toString(),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('RecoveryKeyCubit'),
|
||||
subtitle: Text(
|
||||
context.watch<RecoveryKeyCubit>().state.loadingStatus.toString(),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('ApiConnectionRepository status'),
|
||||
subtitle: Text(
|
||||
|
|
|
@ -2,9 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
||||
import 'package:selfprivacy/logic/cubit/recovery_key/recovery_key_cubit.dart';
|
||||
import 'package:selfprivacy/logic/bloc/recovery_key/recovery_key_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
||||
|
@ -21,34 +19,29 @@ class RecoveryKeyPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RecoveryKeyCubit>().load();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
final RecoveryKeyState keyStatus = context.watch<RecoveryKeyCubit>().state;
|
||||
final RecoveryKeyState keyStatus = context.watch<RecoveryKeyBloc>().state;
|
||||
|
||||
final List<Widget> widgets;
|
||||
String? subtitle =
|
||||
keyStatus.exists ? null : 'recovery_key.key_main_description'.tr();
|
||||
|
||||
switch (keyStatus.loadingStatus) {
|
||||
case LoadingStatus.refreshing:
|
||||
switch (keyStatus) {
|
||||
case RecoveryKeyRefreshing():
|
||||
subtitle = 'recovery_key.key_synchronizing'.tr();
|
||||
widgets = [
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
];
|
||||
break;
|
||||
case LoadingStatus.success:
|
||||
case RecoveryKeyLoaded():
|
||||
widgets = [
|
||||
const RecoveryKeyContent(),
|
||||
];
|
||||
break;
|
||||
case LoadingStatus.uninitialized:
|
||||
case LoadingStatus.error:
|
||||
case RecoveryKeyInitial():
|
||||
case RecoveryKeyError():
|
||||
case RecoveryKeyCreating():
|
||||
subtitle = 'recovery_key.key_connection_error'.tr();
|
||||
widgets = [
|
||||
const Icon(Icons.sentiment_dissatisfied_outlined),
|
||||
|
@ -58,7 +51,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
|
|||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
context.read<RecoveryKeyCubit>().load();
|
||||
context.read<RecoveryKeyBloc>().add(const RecoveryKeyStatusRefresh());
|
||||
},
|
||||
child: BrandHeroScreen(
|
||||
heroTitle: 'recovery_key.key_main_header'.tr(),
|
||||
|
@ -83,7 +76,7 @@ class _RecoveryKeyContentState extends State<RecoveryKeyContent> {
|
|||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
final RecoveryKeyState keyStatus = context.watch<RecoveryKeyCubit>().state;
|
||||
final RecoveryKeyState keyStatus = context.watch<RecoveryKeyBloc>().state;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
|
@ -241,34 +234,24 @@ class _RecoveryKeyConfigurationState extends State<RecoveryKeyConfiguration> {
|
|||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
final String token =
|
||||
await context.read<RecoveryKeyCubit>().generateRecoveryKey(
|
||||
numberOfUses: _isAmountToggled
|
||||
? int.tryParse(_amountController.text)
|
||||
: null,
|
||||
expirationDate: _isExpirationToggled ? _selectedDate : null,
|
||||
);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
await Navigator.of(context).push(
|
||||
materialRoute(
|
||||
RecoveryKeyReceiving(recoveryKey: token), // TO DO
|
||||
),
|
||||
);
|
||||
} on GenerationError catch (e) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
'recovery_key.generation_error'.tr(args: [e.message]),
|
||||
);
|
||||
context.read<RecoveryKeyBloc>().add(
|
||||
CreateNewRecoveryKey(
|
||||
expirationDate: _isExpirationToggled ? _selectedDate : null,
|
||||
numberOfUses:
|
||||
_isAmountToggled ? int.tryParse(_amountController.text) : null,
|
||||
),
|
||||
);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
await Navigator.of(context).push(
|
||||
materialRoute(
|
||||
const RecoveryKeyReceiving(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateErrorStatuses() {
|
||||
|
|
|
@ -1,23 +1,36 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/recovery_key/recovery_key_bloc.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
|
||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||
|
||||
class RecoveryKeyReceiving extends StatelessWidget {
|
||||
const RecoveryKeyReceiving({required this.recoveryKey, super.key});
|
||||
|
||||
final String recoveryKey;
|
||||
const RecoveryKeyReceiving({super.key});
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) => BrandHeroScreen(
|
||||
heroTitle: 'recovery_key.key_main_header'.tr(),
|
||||
heroSubtitle: 'recovery_key.key_receiving_description'.tr(),
|
||||
hasBackButton: true,
|
||||
hasFlashButton: false,
|
||||
children: [
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
Widget build(final BuildContext context) {
|
||||
final recoveryKeyState = context.watch<RecoveryKeyBloc>().state;
|
||||
|
||||
final String? recoveryKey = recoveryKeyState is RecoveryKeyCreating
|
||||
? recoveryKeyState.recoveryKey
|
||||
: null;
|
||||
|
||||
final String? error =
|
||||
recoveryKeyState is RecoveryKeyCreating ? recoveryKeyState.error : null;
|
||||
|
||||
return BrandHeroScreen(
|
||||
heroTitle: 'recovery_key.key_main_header'.tr(),
|
||||
heroSubtitle: 'recovery_key.key_receiving_description'.tr(),
|
||||
hasBackButton: true,
|
||||
hasFlashButton: false,
|
||||
children: [
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
if (recoveryKey == null && error == null)
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
if (recoveryKey != null)
|
||||
Text(
|
||||
recoveryKey,
|
||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||
|
@ -26,19 +39,31 @@ class RecoveryKeyReceiving extends StatelessWidget {
|
|||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
InfoBox(
|
||||
text: 'recovery_key.key_receiving_info'.tr(),
|
||||
if (error != null)
|
||||
Text(
|
||||
'recovery_key.generation_error'.tr(args: [error]),
|
||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||
fontSize: 24,
|
||||
fontFamily: 'RobotoMono',
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
BrandButton.filled(
|
||||
child: Text('recovery_key.key_receiving_done'.tr()),
|
||||
onPressed: () {
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
InfoBox(
|
||||
text: 'recovery_key.key_receiving_info'.tr(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
BrandButton.filled(
|
||||
child: Text('recovery_key.key_receiving_done'.tr()),
|
||||
onPressed: () {
|
||||
context.read<RecoveryKeyBloc>().add(const ConsumedNewRecoveryKey());
|
||||
Navigator.of(context).popUntil((final route) => route.isFirst);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue