| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 | import 'dart:io';import 'package:appflowy/util/file_picker/file_picker_service.dart';import 'package:easy_localization/easy_localization.dart';import 'package:flowy_infra_ui/flowy_infra_ui.dart';import 'package:flutter/material.dart';import 'package:fluttertoast/fluttertoast.dart';import '../../../generated/locale_keys.g.dart';import '../../../startup/startup.dart';import '../../../workspace/application/settings/settings_location_cubit.dart';import '../../../workspace/presentation/home/toast.dart';enum _FolderPage {  options,  create,  open,}class FolderWidget extends StatefulWidget {  const FolderWidget({    Key? key,    required this.createFolderCallback,  }) : super(key: key);  final Future<void> Function() createFolderCallback;  @override  State<FolderWidget> createState() => _FolderWidgetState();}class _FolderWidgetState extends State<FolderWidget> {  var page = _FolderPage.options;  @override  Widget build(BuildContext context) {    return _mapIndexToWidget(context);  }  Widget _mapIndexToWidget(BuildContext context) {    switch (page) {      case _FolderPage.options:        return FolderOptionsWidget(          onPressedCreate: () {            setState(() => page = _FolderPage.create);          },          onPressedOpen: () {            _openFolder();          },        );      case _FolderPage.create:        return CreateFolderWidget(          onPressedBack: () {            setState(() => page = _FolderPage.options);          },          onPressedCreate: widget.createFolderCallback,        );      case _FolderPage.open:        return Container();    }  }  Future<void> _openFolder() async {    final directory = await getIt<FilePickerService>().getDirectoryPath();    if (directory != null) {      await getIt<SettingsLocationCubit>().setLocation(directory);      await widget.createFolderCallback();    }  }}class FolderOptionsWidget extends StatelessWidget {  const FolderOptionsWidget({    Key? key,    required this.onPressedCreate,    required this.onPressedOpen,  }) : super(key: key);  final VoidCallback onPressedCreate;  final VoidCallback onPressedOpen;  @override  Widget build(BuildContext context) {    return Column(      children: [        _FolderCard(          title: LocaleKeys.settings_files_createNewFolder.tr(),          subtitle: LocaleKeys.settings_files_createNewFolderDesc.tr(),          trailing: _buildTextButton(            context,            LocaleKeys.settings_files_create.tr(),            onPressedCreate,          ),        ),        _FolderCard(          title: LocaleKeys.settings_files_openFolder.tr(),          subtitle: LocaleKeys.settings_files_openFolderDesc.tr(),          trailing: _buildTextButton(            context,            LocaleKeys.settings_files_open.tr(),            onPressedOpen,          ),        ),      ],    );  }}class CreateFolderWidget extends StatefulWidget {  const CreateFolderWidget({    Key? key,    required this.onPressedBack,    required this.onPressedCreate,  }) : super(key: key);  final VoidCallback onPressedBack;  final Future<void> Function() onPressedCreate;  @override  State<CreateFolderWidget> createState() => CreateFolderWidgetState();}@visibleForTestingclass CreateFolderWidgetState extends State<CreateFolderWidget> {  var _folderName = 'appflowy';  @visibleForTesting  var directory = '';  final _fToast = FToast();  @override  void initState() {    super.initState();    _fToast.init(context);  }  @override  Widget build(BuildContext context) {    return Column(      children: [        Align(          alignment: Alignment.centerLeft,          child: TextButton.icon(            onPressed: widget.onPressedBack,            icon: const Icon(Icons.arrow_back_rounded),            label: const Text('Back'),          ),        ),        _FolderCard(          title: LocaleKeys.settings_files_location.tr(),          subtitle: LocaleKeys.settings_files_locationDesc.tr(),          trailing: SizedBox(            width: 120,            child: FlowyTextField(              hintText: LocaleKeys.settings_files_folderHintText.tr(),              onChanged: (name) => _folderName = name,              onSubmitted: (name) => setState(                () => _folderName = name,              ),            ),          ),        ),        _FolderCard(          title: LocaleKeys.settings_files_folderPath.tr(),          subtitle: _path,          trailing: _buildTextButton(            context,            LocaleKeys.settings_files_browser.tr(),            () async {              final dir = await getIt<FilePickerService>().getDirectoryPath();              if (dir != null) {                setState(() => directory = dir);              }            },          ),        ),        const VSpace(4.0),        Padding(          padding: const EdgeInsets.symmetric(horizontal: 4.0),          child: Row(            children: [              _buildTextButton(                context,                LocaleKeys.settings_files_create.tr(),                () async {                  if (_path.isEmpty) {                    _showToast(                      LocaleKeys.settings_files_locationCannotBeEmpty.tr(),                    );                  } else {                    await getIt<SettingsLocationCubit>().setLocation(_path);                    await widget.onPressedCreate();                  }                },              ),            ],          ),        )      ],    );  }  String get _path {    if (directory.isEmpty) return '';    final String path;    if (Platform.isMacOS) {      path = directory.replaceAll('/Volumes/Macintosh HD', '');    } else {      path = directory;    }    return '$path/$_folderName';  }  void _showToast(String message) {    _fToast.showToast(      child: FlowyMessageToast(message: message),      gravity: ToastGravity.CENTER,    );  }}Widget _buildTextButton(    BuildContext context, String title, VoidCallback onPressed) {  return FlowyTextButton(    title,    onPressed: onPressed,    fillColor: Theme.of(context).colorScheme.primary,    fontColor: Theme.of(context).colorScheme.onPrimary,    hoverColor: Theme.of(context).colorScheme.primaryContainer,  );}class _FolderCard extends StatelessWidget {  const _FolderCard({    Key? key,    required this.title,    required this.subtitle,    this.trailing,  }) : super(key: key);  final String title;  final String subtitle;  final Widget? trailing;  @override  Widget build(BuildContext context) {    return Card(      child: Padding(        padding: const EdgeInsets.symmetric(          vertical: 4.0,          horizontal: 16.0,        ),        child: Row(          children: [            Expanded(              child: Column(                crossAxisAlignment: CrossAxisAlignment.start,                children: [                  FlowyText.medium(                    title,                  ),                  Row(                    children: [                      Flexible(                        child: Text(                          subtitle,                          overflow: TextOverflow.ellipsis,                          style:                              Theme.of(context).textTheme.bodyMedium!.copyWith(                                    fontWeight: FontWeight.w400,                                  ),                        ),                      ),                    ],                  ),                ],              ),            ),            if (trailing != null) ...[              const HSpace(40),              trailing!,            ],          ],        ),      ),    );  }}
 |