import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/theme.dart'; import 'package:nc_photos/use_case/ls_single_file.dart'; import 'package:nc_photos/widget/dir_picker.dart'; import 'package:nc_photos/widget/processing_dialog.dart'; class RootPickerArguments { RootPickerArguments(this.account); final Account account; } class RootPicker extends StatefulWidget { static const routeName = "/root-picker"; static Route buildRoute(RootPickerArguments args) => MaterialPageRoute( builder: (context) => RootPicker.fromArgs(args), ); const RootPicker({ Key? key, required this.account, }) : super(key: key); RootPicker.fromArgs(RootPickerArguments args, {Key? key}) : this( key: key, account: args.account, ); @override createState() => _RootPickerState(); final Account account; } class _RootPickerState extends State { @override initState() { super.initState(); _initAccount(); } Future _initAccount() async { final c = KiwiContainer().resolve(); final files = []; for (final r in widget.account.roots) { try { if (r.isNotEmpty) { _ensureInitDialog(); files.add(await LsSingleFile(c.withRemoteFileRepo())( widget.account, file_util.unstripPath(widget.account, r))); } } catch (e, stackTrace) { _log.severe("[_initAccount] Failed", e, stackTrace); } } _dismissInitDialog(); setState(() { _initialPicks = files; }); } @override build(BuildContext context) { return AppTheme( child: Scaffold( body: _buildContent(context), ), ); } Widget _buildContent(BuildContext context) { return SafeArea( child: Column( children: [ Padding( padding: const EdgeInsets.all(24), child: Column( children: [ Text( L10n.global().rootPickerHeaderText, style: Theme.of(context).textTheme.headline5, textAlign: TextAlign.center, ), const SizedBox(height: 8), Align( alignment: AlignmentDirectional.topStart, child: Text( L10n.global().rootPickerSubHeaderText, ), ), ], ), ), Expanded( child: _initialPicks == null ? Container() : DirPicker( key: _pickerKey, account: widget.account, strippedRootDir: "", initialPicks: _initialPicks, onConfirmed: (picks) => _onPickerConfirmed(context, picks), ), ), Padding( padding: const EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () => _onSkipPressed(context), child: Text(L10n.global().skipButtonLabel), ), ElevatedButton( onPressed: _onConfirmPressed, child: Text(L10n.global().confirmButtonLabel), ), ], ), ), ], ), ); } void _onSkipPressed(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( content: Text(L10n.global().rootPickerSkipConfirmationDialogContent2), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: Text(MaterialLocalizations.of(context).cancelButtonLabel), ), TextButton( onPressed: () { Navigator.of(context).pop(true); }, child: Text(MaterialLocalizations.of(context).okButtonLabel), ), ], )).then((value) { if (value == true) { Navigator.of(context).pop(widget.account.copyWith(roots: [""])); } }); } void _onConfirmPressed() { _pickerKey.currentState?.confirm(); } void _onPickerConfirmed(BuildContext context, List picks) { final roots = picks.map((e) => e.strippedPath).toList(); if (roots.isEmpty) { SnackBarManager().showSnackBar(SnackBar( content: Text(L10n.global().rootPickerListEmptyNotification), duration: k.snackBarDurationNormal, )); return; } final newAccount = widget.account.copyWith(roots: roots); _log.info("[_onPickerConfirmed] Account is good: $newAccount"); Navigator.of(context).pop(newAccount); } void _ensureInitDialog() { if (_isInitDialogShown) { return; } _isInitDialogShown = true; SchedulerBinding.instance.addPostFrameCallback((_) { showDialog( barrierDismissible: false, context: context, builder: (context) => ProcessingDialog( text: L10n.global().genericProcessingDialogContent), ); }); } void _dismissInitDialog() { if (!_isInitDialogShown) { return; } Navigator.of(context).pop(); } final _pickerKey = GlobalKey(); List? _initialPicks; bool _isInitDialogShown = false; static final _log = Logger("widget.root_picker._RootPickerState"); }