mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-27 11:16:45 +00:00
Introduce new brand screen, use it for backups
This commit is contained in:
parent
8de33ea19b
commit
83a2d19e37
|
@ -111,6 +111,7 @@
|
||||||
"restoring": "Restoring from backup",
|
"restoring": "Restoring from backup",
|
||||||
"error_pending": "Server returned error, check it below",
|
"error_pending": "Server returned error, check it below",
|
||||||
"restore_alert": "You are about to restore from backup created on {}. All current data will be lost. Are you sure?",
|
"restore_alert": "You are about to restore from backup created on {}. All current data will be lost. Are you sure?",
|
||||||
|
"refresh": "Refresh status",
|
||||||
"refetchBackups": "Refetch backup list",
|
"refetchBackups": "Refetch backup list",
|
||||||
"refetchingList": "In a few minutes list will be updated"
|
"refetchingList": "In a few minutes list will be updated"
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
"restoring": "Восстановление из копии",
|
"restoring": "Восстановление из копии",
|
||||||
"error_pending": "Сервер вернул ошибку: проверьте её ниже.",
|
"error_pending": "Сервер вернул ошибку: проверьте её ниже.",
|
||||||
"restore_alert": "Вы собираетесь восстановить из копии созданной {}. Все текущие данные будут потеряны. Вы уверены?",
|
"restore_alert": "Вы собираетесь восстановить из копии созданной {}. Все текущие данные будут потеряны. Вы уверены?",
|
||||||
|
"refresh": "Обновить статус",
|
||||||
"refetchBackups": "Обновить список копий",
|
"refetchBackups": "Обновить список копий",
|
||||||
"refetchingList": "Через несколько минут список будет обновлён"
|
"refetchingList": "Через несколько минут список будет обновлён"
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,14 @@ final ligtTheme = ThemeData(
|
||||||
color: BrandColors.red1,
|
color: BrandColors.red1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
listTileTheme: ListTileThemeData(
|
||||||
|
minLeadingWidth: 24.0,
|
||||||
|
),
|
||||||
textTheme: TextTheme(
|
textTheme: TextTheme(
|
||||||
headline1: headline1Style,
|
headline1: headline1Style,
|
||||||
headline2: headline2Style,
|
headline2: headline2Style,
|
||||||
caption: headline4Style,
|
headline3: headline3Style,
|
||||||
|
headline4: headline4Style,
|
||||||
bodyText1: body1Style,
|
bodyText1: body1Style,
|
||||||
subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style
|
subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style
|
||||||
),
|
),
|
||||||
|
@ -56,7 +60,8 @@ var darkTheme = ligtTheme.copyWith(
|
||||||
textTheme: TextTheme(
|
textTheme: TextTheme(
|
||||||
headline1: headline1Style.copyWith(color: BrandColors.white),
|
headline1: headline1Style.copyWith(color: BrandColors.white),
|
||||||
headline2: headline2Style.copyWith(color: BrandColors.white),
|
headline2: headline2Style.copyWith(color: BrandColors.white),
|
||||||
caption: headline4Style.copyWith(color: BrandColors.white),
|
headline3: headline3Style.copyWith(color: BrandColors.white),
|
||||||
|
headline4: headline4Style.copyWith(color: BrandColors.white),
|
||||||
bodyText1: body1Style.copyWith(color: BrandColors.white),
|
bodyText1: body1Style.copyWith(color: BrandColors.white),
|
||||||
subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style
|
subtitle1: TextStyle(fontSize: 15, height: 1.6), // text input style
|
||||||
),
|
),
|
||||||
|
|
|
@ -20,6 +20,9 @@ class BrandCards {
|
||||||
shadow: bigShadow,
|
shadow: bigShadow,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
);
|
);
|
||||||
|
static Widget outlined({required Widget child}) => _OutlinedCard(
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BrandCard extends StatelessWidget {
|
class _BrandCard extends StatelessWidget {
|
||||||
|
@ -52,6 +55,29 @@ class _BrandCard extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _OutlinedCard extends StatelessWidget {
|
||||||
|
const _OutlinedCard({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
elevation: 0.0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
side: BorderSide(
|
||||||
|
color: Colors.grey.withOpacity(0.2),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final bigShadow = [
|
final bigShadow = [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
offset: Offset(0, 4),
|
offset: Offset(0, 4),
|
||||||
|
|
61
lib/ui/components/brand_hero_screen/brand_hero_screen.dart
Normal file
61
lib/ui/components/brand_hero_screen/brand_hero_screen.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
||||||
|
|
||||||
|
class BrandHeroScreen extends StatelessWidget {
|
||||||
|
const BrandHeroScreen({
|
||||||
|
Key? key,
|
||||||
|
this.headerTitle = '',
|
||||||
|
this.hasBackButton = true,
|
||||||
|
this.hasFlashButton = true,
|
||||||
|
required this.children,
|
||||||
|
this.heroIcon,
|
||||||
|
this.heroTitle,
|
||||||
|
this.heroSubtitle,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final List<Widget> children;
|
||||||
|
final String headerTitle;
|
||||||
|
final bool hasBackButton;
|
||||||
|
final bool hasFlashButton;
|
||||||
|
final IconData? heroIcon;
|
||||||
|
final String? heroTitle;
|
||||||
|
final String? heroSubtitle;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SafeArea(
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size.fromHeight(52.0),
|
||||||
|
child: BrandHeader(
|
||||||
|
title: headerTitle,
|
||||||
|
hasBackButton: hasBackButton,
|
||||||
|
hasFlashButton: hasFlashButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
padding: EdgeInsets.all(16.0),
|
||||||
|
children: <Widget>[
|
||||||
|
if (heroIcon != null)
|
||||||
|
Icon(
|
||||||
|
heroIcon,
|
||||||
|
size: 48.0,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0),
|
||||||
|
if (heroTitle != null)
|
||||||
|
Text(heroTitle!,
|
||||||
|
style: Theme.of(context).textTheme.headline2,
|
||||||
|
textAlign: TextAlign.center),
|
||||||
|
SizedBox(height: 8.0),
|
||||||
|
if (heroSubtitle != null)
|
||||||
|
Text(heroSubtitle!,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center),
|
||||||
|
SizedBox(height: 16.0),
|
||||||
|
...children,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
|
||||||
import 'package:selfprivacy/config/get_it_config.dart';
|
import 'package:selfprivacy/config/get_it_config.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/cubit/backups/backups_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
||||||
|
@ -9,13 +9,11 @@ import 'package:selfprivacy/logic/models/state_types.dart';
|
||||||
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
|
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.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/brand_text/brand_text.dart';
|
||||||
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
|
|
||||||
part 'header.dart';
|
import '../../components/brand_cards/brand_cards.dart';
|
||||||
|
|
||||||
var navigatorKey = GlobalKey<NavigatorState>();
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
@ -44,203 +42,200 @@ class _BackupDetailsState extends State<BackupDetails>
|
||||||
var backups = context.watch<BackupsCubit>().state.backups;
|
var backups = context.watch<BackupsCubit>().state.backups;
|
||||||
var refreshing = context.watch<BackupsCubit>().state.refreshing;
|
var refreshing = context.watch<BackupsCubit>().state.refreshing;
|
||||||
|
|
||||||
return Scaffold(
|
return BrandHeroScreen(
|
||||||
appBar: PreferredSize(
|
heroIcon: BrandIcons.save,
|
||||||
child: Column(
|
heroTitle: 'providers.backup.card_title'.tr(),
|
||||||
children: [
|
heroSubtitle: 'providers.backup.bottom_sheet.1'.tr(),
|
||||||
Container(
|
children: [
|
||||||
height: 51,
|
if (isReady && !isBackupInitialized)
|
||||||
alignment: Alignment.center,
|
BrandButton.rised(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
onPressed: preventActions
|
||||||
child: BrandText.h4('basis.details'.tr()),
|
? null
|
||||||
),
|
: () async {
|
||||||
BrandDivider(),
|
await context.read<BackupsCubit>().createBucket();
|
||||||
],
|
},
|
||||||
),
|
text: 'providers.backup.initialize'.tr(),
|
||||||
preferredSize: Size.fromHeight(52),
|
),
|
||||||
),
|
if (backupStatus == BackupStatusEnum.initializing)
|
||||||
body: SingleChildScrollView(
|
BrandText.body1('providers.backup.waitingForRebuild'.tr()),
|
||||||
physics: ClampingScrollPhysics(),
|
if (backupStatus != BackupStatusEnum.initializing &&
|
||||||
child: Column(
|
backupStatus != BackupStatusEnum.noKey)
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
BrandCards.outlined(
|
||||||
children: [
|
child: Column(
|
||||||
Padding(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
padding: paddingH15V0,
|
children: [
|
||||||
child: Column(
|
if (backupStatus == BackupStatusEnum.initialized)
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
ListTile(
|
||||||
children: [
|
onTap: preventActions
|
||||||
_Header(
|
? null
|
||||||
providerState: providerState,
|
: () async {
|
||||||
refreshing: refreshing,
|
await context.read<BackupsCubit>().createBackup();
|
||||||
|
},
|
||||||
|
leading: Icon(
|
||||||
|
Icons.add_circle_outline_rounded,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.create_new'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headline6,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
if (backupStatus == BackupStatusEnum.backingUp)
|
||||||
BrandText.h2('providers.backup.card_title'.tr()),
|
ListTile(
|
||||||
SizedBox(height: 10),
|
title: Text(
|
||||||
BrandText.body1('providers.backup.bottom_sheet.1'.tr()),
|
'providers.backup.creating'.tr(
|
||||||
SizedBox(height: 20),
|
args: [(backupProgress * 100).round().toString()]),
|
||||||
if (isReady && !isBackupInitialized)
|
style: Theme.of(context).textTheme.headline6,
|
||||||
BrandButton.rised(
|
|
||||||
onPressed: preventActions
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
await context.read<BackupsCubit>().createBucket();
|
|
||||||
},
|
|
||||||
text: 'providers.backup.initialize'.tr(),
|
|
||||||
),
|
),
|
||||||
if (backupStatus == BackupStatusEnum.initializing)
|
subtitle: LinearProgressIndicator(
|
||||||
BrandText.body1('providers.backup.waitingForRebuild'.tr()),
|
value: backupProgress,
|
||||||
if (backupStatus != BackupStatusEnum.initializing &&
|
backgroundColor: Colors.grey.withOpacity(0.2),
|
||||||
backupStatus != BackupStatusEnum.noKey)
|
|
||||||
Card(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
side: BorderSide(
|
|
||||||
color: Colors.grey.withOpacity(0.2),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (backupStatus == BackupStatusEnum.initialized)
|
|
||||||
ListTile(
|
|
||||||
onTap: preventActions
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
await context
|
|
||||||
.read<BackupsCubit>()
|
|
||||||
.createBackup();
|
|
||||||
},
|
|
||||||
leading: Icon(
|
|
||||||
Icons.add_circle_outline_rounded,
|
|
||||||
color: BrandColors.textColor1,
|
|
||||||
),
|
|
||||||
title: BrandText.h5(
|
|
||||||
'providers.backup.create_new'.tr()),
|
|
||||||
),
|
|
||||||
if (backupStatus == BackupStatusEnum.backingUp)
|
|
||||||
ListTile(
|
|
||||||
title: BrandText.h5('providers.backup.creating'
|
|
||||||
.tr(args: [
|
|
||||||
(backupProgress * 100).round().toString()
|
|
||||||
])),
|
|
||||||
subtitle: LinearProgressIndicator(
|
|
||||||
value: backupProgress,
|
|
||||||
backgroundColor: Colors.grey.withOpacity(0.2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (backupStatus == BackupStatusEnum.restoring)
|
|
||||||
ListTile(
|
|
||||||
title: BrandText.h5('providers.backup.restoring'
|
|
||||||
.tr(args: [
|
|
||||||
(backupProgress * 100).round().toString()
|
|
||||||
])),
|
|
||||||
subtitle: LinearProgressIndicator(
|
|
||||||
backgroundColor: Colors.grey.withOpacity(0.2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (backupStatus == BackupStatusEnum.error)
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: BrandColors.red1,
|
|
||||||
),
|
|
||||||
title: BrandText.h5(
|
|
||||||
'providers.backup.error_pending'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
),
|
||||||
// Card with a list of existing backups
|
if (backupStatus == BackupStatusEnum.restoring)
|
||||||
// Each list item has a date
|
ListTile(
|
||||||
// When clicked, starts the restore action
|
title: Text(
|
||||||
if (backupStatus != BackupStatusEnum.initializing &&
|
'providers.backup.restoring'.tr(
|
||||||
backupStatus != BackupStatusEnum.noKey)
|
args: [(backupProgress * 100).round().toString()]),
|
||||||
Card(
|
style: Theme.of(context).textTheme.headline6,
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
side: BorderSide(
|
|
||||||
color: Colors.grey.withOpacity(0.2),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(
|
|
||||||
Icons.refresh,
|
|
||||||
color: BrandColors.textColor1,
|
|
||||||
),
|
|
||||||
title:
|
|
||||||
BrandText.h5('providers.backup.restore'.tr()),
|
|
||||||
),
|
|
||||||
Divider(
|
|
||||||
height: 1.0,
|
|
||||||
),
|
|
||||||
if (backups.isEmpty)
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
),
|
|
||||||
title: Text('providers.backup.no_backups'.tr()),
|
|
||||||
),
|
|
||||||
if (backups.isNotEmpty)
|
|
||||||
Column(
|
|
||||||
children: backups.map((backup) {
|
|
||||||
return ListTile(
|
|
||||||
onTap: preventActions
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
var nav = getIt<NavigationService>();
|
|
||||||
nav.showPopUpDialog(BrandAlert(
|
|
||||||
title: 'providers.backup.restoring'
|
|
||||||
.tr(),
|
|
||||||
contentText:
|
|
||||||
'providers.backup.restore_alert'
|
|
||||||
.tr(args: [
|
|
||||||
backup.time.toString()
|
|
||||||
]),
|
|
||||||
actions: [
|
|
||||||
ActionButton(
|
|
||||||
text: 'basis.cancel'.tr(),
|
|
||||||
),
|
|
||||||
ActionButton(
|
|
||||||
onPressed: () => {
|
|
||||||
context
|
|
||||||
.read<BackupsCubit>()
|
|
||||||
.restoreBackup(backup.id)
|
|
||||||
},
|
|
||||||
text: 'modals.yes'.tr(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},
|
|
||||||
title: Text(
|
|
||||||
MaterialLocalizations.of(context)
|
|
||||||
.formatShortDate(backup.time) +
|
|
||||||
' ' +
|
|
||||||
TimeOfDay.fromDateTime(backup.time)
|
|
||||||
.format(context),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (backupStatus == BackupStatusEnum.error)
|
subtitle: LinearProgressIndicator(
|
||||||
BrandText.body1(backupError.toString()),
|
backgroundColor: Colors.grey.withOpacity(0.2),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
|
if (backupStatus == BackupStatusEnum.error)
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: BrandColors.red1,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.error_pending'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headline6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
),
|
||||||
],
|
SizedBox(height: 16),
|
||||||
|
// Card with a list of existing backups
|
||||||
|
// Each list item has a date
|
||||||
|
// When clicked, starts the restore action
|
||||||
|
if (backupStatus != BackupStatusEnum.initializing &&
|
||||||
|
backupStatus != BackupStatusEnum.noKey)
|
||||||
|
BrandCards.outlined(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.refresh,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.restore'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.headline6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
height: 1.0,
|
||||||
|
),
|
||||||
|
if (backups.isEmpty)
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
),
|
||||||
|
title: Text('providers.backup.no_backups'.tr()),
|
||||||
|
),
|
||||||
|
if (backups.isNotEmpty)
|
||||||
|
Column(
|
||||||
|
children: backups.map((backup) {
|
||||||
|
return ListTile(
|
||||||
|
onTap: preventActions
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
var nav = getIt<NavigationService>();
|
||||||
|
nav.showPopUpDialog(BrandAlert(
|
||||||
|
title: 'providers.backup.restoring'.tr(),
|
||||||
|
contentText: 'providers.backup.restore_alert'
|
||||||
|
.tr(args: [backup.time.toString()]),
|
||||||
|
actions: [
|
||||||
|
ActionButton(
|
||||||
|
text: 'basis.cancel'.tr(),
|
||||||
|
),
|
||||||
|
ActionButton(
|
||||||
|
onPressed: () => {
|
||||||
|
context
|
||||||
|
.read<BackupsCubit>()
|
||||||
|
.restoreBackup(backup.id)
|
||||||
|
},
|
||||||
|
text: 'modals.yes'.tr(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
MaterialLocalizations.of(context)
|
||||||
|
.formatShortDate(backup.time) +
|
||||||
|
' ' +
|
||||||
|
TimeOfDay.fromDateTime(backup.time)
|
||||||
|
.format(context),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
BrandCards.outlined(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.refresh'.tr(),
|
||||||
|
),
|
||||||
|
onTap: refreshing
|
||||||
|
? null
|
||||||
|
: () => {context.read<BackupsCubit>().updateBackups()},
|
||||||
|
enabled: !refreshing,
|
||||||
|
),
|
||||||
|
if (providerState != StateType.uninitialized)
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Divider(
|
||||||
|
height: 1.0,
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.refetchBackups'.tr(),
|
||||||
|
),
|
||||||
|
onTap: preventActions
|
||||||
|
? null
|
||||||
|
: () => {
|
||||||
|
context
|
||||||
|
.read<BackupsCubit>()
|
||||||
|
.forceUpdateBackups()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
height: 1.0,
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
'providers.backup.reuploadKey'.tr(),
|
||||||
|
),
|
||||||
|
onTap: preventActions
|
||||||
|
? null
|
||||||
|
: () => {context.read<BackupsCubit>().reuploadKey()},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (backupStatus == BackupStatusEnum.error)
|
||||||
|
BrandText.body1(backupError.toString()),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
part of 'backup_details.dart';
|
|
||||||
|
|
||||||
class _Header extends StatelessWidget {
|
|
||||||
const _Header(
|
|
||||||
{Key? key, required this.providerState, required this.refreshing})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final StateType providerState;
|
|
||||||
final bool refreshing;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
IconStatusMask(
|
|
||||||
status: providerState,
|
|
||||||
child: Icon(
|
|
||||||
BrandIcons.save,
|
|
||||||
size: 40,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
horizontal: 2,
|
|
||||||
),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: refreshing
|
|
||||||
? null
|
|
||||||
: () => {context.read<BackupsCubit>().updateBackups()},
|
|
||||||
icon: const Icon(Icons.refresh_rounded),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
horizontal: 2,
|
|
||||||
),
|
|
||||||
child: PopupMenuButton<_PopupMenuItemType>(
|
|
||||||
enabled: providerState != StateType.uninitialized,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
onSelected: (_PopupMenuItemType result) {
|
|
||||||
switch (result) {
|
|
||||||
case _PopupMenuItemType.reuploadKey:
|
|
||||||
context.read<BackupsCubit>().reuploadKey();
|
|
||||||
break;
|
|
||||||
case _PopupMenuItemType.refetchBackups:
|
|
||||||
context.read<BackupsCubit>().forceUpdateBackups();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: Icon(Icons.more_vert),
|
|
||||||
itemBuilder: (BuildContext context) => [
|
|
||||||
PopupMenuItem<_PopupMenuItemType>(
|
|
||||||
value: _PopupMenuItemType.reuploadKey,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 5),
|
|
||||||
child: Text('providers.backup.reuploadKey'.tr()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem<_PopupMenuItemType>(
|
|
||||||
value: _PopupMenuItemType.refetchBackups,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 5),
|
|
||||||
child: Text('providers.backup.refetchBackups'.tr()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum _PopupMenuItemType { reuploadKey, refetchBackups }
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
|
@ -15,7 +16,7 @@ import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
||||||
import 'package:selfprivacy/ui/helpers/modals.dart';
|
import 'package:selfprivacy/ui/helpers/modals.dart';
|
||||||
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
|
import 'package:selfprivacy/ui/pages/backup_details/backup_details.dart';
|
||||||
import 'package:selfprivacy/ui/pages/server_details/server_details.dart';
|
import 'package:selfprivacy/ui/pages/server_details/server_details.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
import 'package:selfprivacy/utils/ui_helpers.dart';
|
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||||
|
|
||||||
var navigatorKey = GlobalKey<NavigatorState>();
|
var navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
@ -120,15 +121,9 @@ class _Card extends StatelessWidget {
|
||||||
title = 'providers.backup.card_title'.tr();
|
title = 'providers.backup.card_title'.tr();
|
||||||
stableText = 'providers.backup.status'.tr();
|
stableText = 'providers.backup.status'.tr();
|
||||||
|
|
||||||
onTap = () => showBrandBottomSheet(
|
onTap = () => Navigator.of(context).push(materialRoute(
|
||||||
context: context,
|
BackupDetails(),
|
||||||
builder: (BuildContext context) {
|
));
|
||||||
return BrandBottomSheet(
|
|
||||||
isExpended: true,
|
|
||||||
child: BackupDetails(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
|
|
Loading…
Reference in a new issue