mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 10:28:50 +01:00
Export collection with different provider
This commit is contained in:
parent
e7212e0643
commit
3f38efccf3
10 changed files with 635 additions and 1 deletions
108
app/lib/entity/collection/exporter.dart
Normal file
108
app/lib/entity/collection/exporter.dart
Normal file
|
@ -0,0 +1,108 @@
|
|||
import 'package:clock/clock.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:kiwi/kiwi.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/controller/collections_controller.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/album.dart';
|
||||
import 'package:nc_photos/entity/album/cover_provider.dart';
|
||||
import 'package:nc_photos/entity/album/item.dart';
|
||||
import 'package:nc_photos/entity/album/provider.dart';
|
||||
import 'package:nc_photos/entity/album/sort_provider.dart';
|
||||
import 'package:nc_photos/entity/collection.dart';
|
||||
import 'package:nc_photos/entity/collection/content_provider/album.dart';
|
||||
import 'package:nc_photos/entity/collection/content_provider/nc_album.dart';
|
||||
import 'package:nc_photos/entity/collection_item.dart';
|
||||
import 'package:nc_photos/entity/file_descriptor.dart';
|
||||
import 'package:nc_photos/entity/nc_album.dart';
|
||||
import 'package:nc_photos/use_case/find_file.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
|
||||
part 'exporter.g.dart';
|
||||
|
||||
@npLog
|
||||
class CollectionExporter {
|
||||
const CollectionExporter(this.account, this.collectionsController,
|
||||
this.collection, this.items, this.exportName);
|
||||
|
||||
/// Export as a new collection backed by our client side album
|
||||
Future<Collection> asAlbum() async {
|
||||
final files = await FindFile(KiwiContainer().resolve<DiContainer>())(
|
||||
account,
|
||||
items.whereType<CollectionFileItem>().map((e) => e.file.fdId).toList(),
|
||||
onFileNotFound: (fileId) {
|
||||
_log.severe("[asAlbum] File not found: $fileId");
|
||||
},
|
||||
);
|
||||
final newAlbum = Album(
|
||||
name: exportName,
|
||||
provider: AlbumStaticProvider(
|
||||
items: items
|
||||
.map((e) {
|
||||
if (e is CollectionFileItem) {
|
||||
final f = files
|
||||
.firstWhereOrNull((f) => f.compareServerIdentity(e.file));
|
||||
if (f == null) {
|
||||
return null;
|
||||
} else {
|
||||
return AlbumFileItem(
|
||||
addedBy: account.userId,
|
||||
addedAt: clock.now().toUtc(),
|
||||
file: f,
|
||||
);
|
||||
}
|
||||
} else if (e is CollectionLabelItem) {
|
||||
return AlbumLabelItem(
|
||||
addedBy: account.userId,
|
||||
addedAt: clock.now().toUtc(),
|
||||
text: e.text,
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.whereNotNull()
|
||||
.toList(),
|
||||
latestItemTime: collection.lastModified,
|
||||
),
|
||||
coverProvider: const AlbumAutoCoverProvider(),
|
||||
sortProvider: const AlbumTimeSortProvider(isAscending: false),
|
||||
);
|
||||
var newCollection = Collection(
|
||||
name: exportName,
|
||||
contentProvider: CollectionAlbumProvider(
|
||||
account: account,
|
||||
album: newAlbum,
|
||||
),
|
||||
);
|
||||
return await collectionsController.createNew(newCollection);
|
||||
}
|
||||
|
||||
/// Export as a new collection backed by Nextcloud album
|
||||
Future<Collection> asNcAlbum() async {
|
||||
var newCollection = Collection(
|
||||
name: exportName,
|
||||
contentProvider: CollectionNcAlbumProvider(
|
||||
account: account,
|
||||
album: NcAlbum.createNew(account: account, name: exportName),
|
||||
),
|
||||
);
|
||||
newCollection = await collectionsController.createNew(newCollection);
|
||||
// only files are supported in NcAlbum
|
||||
final newFiles =
|
||||
items.whereType<CollectionFileItem>().map((e) => e.file).toList();
|
||||
final data = collectionsController
|
||||
.peekStream()
|
||||
.data
|
||||
.firstWhere((e) => e.collection.compareIdentity(newCollection));
|
||||
await data.controller.addFiles(newFiles);
|
||||
return newCollection;
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final CollectionsController collectionsController;
|
||||
final Collection collection;
|
||||
final List<CollectionItem> items;
|
||||
final String exportName;
|
||||
}
|
14
app/lib/entity/collection/exporter.g.dart
Normal file
14
app/lib/entity/collection/exporter.g.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'exporter.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$CollectionExporterNpLog on CollectionExporter {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("entity.collection.exporter.CollectionExporter");
|
||||
}
|
|
@ -43,6 +43,7 @@ import 'package:nc_photos/use_case/inflate_file_descriptor.dart';
|
|||
import 'package:nc_photos/use_case/remove.dart';
|
||||
import 'package:nc_photos/widget/collection_picker.dart';
|
||||
import 'package:nc_photos/widget/draggable_item_list.dart';
|
||||
import 'package:nc_photos/widget/export_collection_dialog.dart';
|
||||
import 'package:nc_photos/widget/fancy_option_picker.dart';
|
||||
import 'package:nc_photos/widget/file_sharer.dart';
|
||||
import 'package:nc_photos/widget/network_thumbnail.dart';
|
||||
|
|
|
@ -160,6 +160,13 @@ extension _$_DownloadToString on _Download {
|
|||
}
|
||||
}
|
||||
|
||||
extension _$_ExportToString on _Export {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_Export {}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$_BeginEditToString on _BeginEdit {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
|
|
|
@ -41,11 +41,16 @@ class _AppBar extends StatelessWidget {
|
|||
value: _MenuOption.unsetCover,
|
||||
child: Text(L10n.global().unsetAlbumCoverTooltip),
|
||||
),
|
||||
if (state.items.isNotEmpty)
|
||||
if (state.items.isNotEmpty) ...[
|
||||
PopupMenuItem(
|
||||
value: _MenuOption.download,
|
||||
child: Text(L10n.global().downloadTooltip),
|
||||
),
|
||||
const PopupMenuItem(
|
||||
value: _MenuOption.export,
|
||||
child: Text("Export"),
|
||||
),
|
||||
],
|
||||
],
|
||||
onSelected: (option) {
|
||||
_onMenuSelected(context, option);
|
||||
|
@ -82,6 +87,24 @@ class _AppBar extends StatelessWidget {
|
|||
case _MenuOption.download:
|
||||
context.read<_Bloc>().add(const _Download());
|
||||
break;
|
||||
case _MenuOption.export:
|
||||
_onExportSelected(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onExportSelected(BuildContext context) async {
|
||||
final bloc = context.read<_Bloc>();
|
||||
final result = await showDialog<Collection>(
|
||||
context: context,
|
||||
builder: (_) => ExportCollectionDialog(
|
||||
account: bloc.account,
|
||||
collection: bloc.state.collection,
|
||||
items: bloc.state.items,
|
||||
),
|
||||
);
|
||||
if (result != null) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,6 +397,7 @@ enum _MenuOption {
|
|||
edit,
|
||||
unsetCover,
|
||||
download,
|
||||
export,
|
||||
}
|
||||
|
||||
enum _SelectionMenuOption {
|
||||
|
|
|
@ -112,6 +112,14 @@ class _Download implements _Event {
|
|||
String toString() => _$toString();
|
||||
}
|
||||
|
||||
@toString
|
||||
class _Export implements _Event {
|
||||
const _Export();
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
}
|
||||
|
||||
@toString
|
||||
class _BeginEdit implements _Event {
|
||||
const _BeginEdit();
|
||||
|
|
225
app/lib/widget/export_collection_dialog.dart
Normal file
225
app/lib/widget/export_collection_dialog.dart
Normal file
|
@ -0,0 +1,225 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:copy_with/copy_with.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/controller/account_controller.dart';
|
||||
import 'package:nc_photos/controller/collections_controller.dart';
|
||||
import 'package:nc_photos/entity/collection.dart';
|
||||
import 'package:nc_photos/entity/collection/exporter.dart';
|
||||
import 'package:nc_photos/entity/collection_item.dart';
|
||||
import 'package:nc_photos/exception_event.dart';
|
||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||
import 'package:nc_photos/k.dart' as k;
|
||||
import 'package:nc_photos/snack_bar_manager.dart';
|
||||
import 'package:nc_photos/widget/processing_dialog.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
part 'export_collection_dialog.g.dart';
|
||||
part 'export_collection_dialog/bloc.dart';
|
||||
part 'export_collection_dialog/state_event.dart';
|
||||
|
||||
class ExportCollectionDialog extends StatelessWidget {
|
||||
const ExportCollectionDialog({
|
||||
super.key,
|
||||
required this.account,
|
||||
required this.collection,
|
||||
required this.items,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => _Bloc(
|
||||
account: account,
|
||||
collectionsController:
|
||||
context.read<AccountController>().collectionsController,
|
||||
collection: collection,
|
||||
items: items,
|
||||
),
|
||||
child: const _WrappedExportCollectionDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final Collection collection;
|
||||
final List<CollectionItem> items;
|
||||
}
|
||||
|
||||
class _WrappedExportCollectionDialog extends StatefulWidget {
|
||||
const _WrappedExportCollectionDialog();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _WrappedExportCollectionDialogState();
|
||||
}
|
||||
|
||||
@npLog
|
||||
class _WrappedExportCollectionDialogState
|
||||
extends State<_WrappedExportCollectionDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<_Bloc, _State>(
|
||||
listenWhen: (previous, current) =>
|
||||
previous.result != current.result && current.result != null,
|
||||
listener: _onResult,
|
||||
),
|
||||
BlocListener<_Bloc, _State>(
|
||||
listenWhen: (previous, current) => previous.error != current.error,
|
||||
listener: (_, state) {
|
||||
if (state.error != null) {
|
||||
SnackBarManager().showSnackBar(SnackBar(
|
||||
content: Text(exception_util.toUserString(state.error!.error)),
|
||||
duration: k.snackBarDurationNormal,
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<_Bloc, _State>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.isExporting != current.isExporting,
|
||||
builder: (context, state) {
|
||||
if (state.isExporting) {
|
||||
return ProcessingDialog(
|
||||
text: L10n.global().genericProcessingDialogContent,
|
||||
);
|
||||
} else {
|
||||
return AlertDialog(
|
||||
title: const Text("Export collection"),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
constraints: const BoxConstraints.tightFor(width: 280),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
_NameTextField(),
|
||||
_ProviderDropdown(),
|
||||
SizedBox(height: 8),
|
||||
_ProviderDescription(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => _onOkPressed(context),
|
||||
child: Text(MaterialLocalizations.of(context).okButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onOkPressed(BuildContext context) async {
|
||||
if (_formKey.currentState?.validate() == true) {
|
||||
_bloc.add(const _SubmitForm());
|
||||
}
|
||||
}
|
||||
|
||||
void _onResult(BuildContext context, _State state) {
|
||||
Navigator.of(context).pop(state.result);
|
||||
}
|
||||
|
||||
late final _bloc = context.read<_Bloc>();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
}
|
||||
|
||||
class _NameTextField extends StatelessWidget {
|
||||
const _NameTextField();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.global().nameInputHint,
|
||||
),
|
||||
initialValue: context.read<_Bloc>().state.formValue.name,
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return L10n.global().albumNameInputInvalidEmpty;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: (value) {
|
||||
context.read<_Bloc>().add(_SubmitName(value));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProviderDropdown extends StatelessWidget {
|
||||
const _ProviderDropdown();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<_Bloc, _State>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.formValue.provider != current.formValue.provider,
|
||||
builder: (context, state) => DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField<_ProviderOption>(
|
||||
value: state.formValue.provider,
|
||||
items: _ProviderOption.values
|
||||
.map((e) => DropdownMenuItem<_ProviderOption>(
|
||||
value: e,
|
||||
child: Text(e.toValueString(context)),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
context.read<_Bloc>().add(_SubmitProvider(value!));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProviderDescription extends StatelessWidget {
|
||||
const _ProviderDescription();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<_Bloc, _State>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.formValue.provider != current.formValue.provider,
|
||||
builder: (context, state) => Text(
|
||||
state.formValue.provider.toDescription(context),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum _ProviderOption {
|
||||
appAlbum,
|
||||
ncAlbum;
|
||||
|
||||
String toValueString(BuildContext context) {
|
||||
switch (this) {
|
||||
case appAlbum:
|
||||
return L10n.global().createCollectionDialogAlbumLabel;
|
||||
case ncAlbum:
|
||||
return "Nextcloud Album";
|
||||
}
|
||||
}
|
||||
|
||||
String toDescription(BuildContext context) {
|
||||
switch (this) {
|
||||
case appAlbum:
|
||||
return L10n.global().createCollectionDialogAlbumDescription;
|
||||
case ncAlbum:
|
||||
return "Server-side album, require Nextcloud 25 or above";
|
||||
}
|
||||
}
|
||||
}
|
113
app/lib/widget/export_collection_dialog.g.dart
Normal file
113
app/lib/widget/export_collection_dialog.g.dart
Normal file
|
@ -0,0 +1,113 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'export_collection_dialog.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// CopyWithLintRuleGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: library_private_types_in_public_api, duplicate_ignore
|
||||
|
||||
// **************************************************************************
|
||||
// CopyWithGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class $_FormValueCopyWithWorker {
|
||||
_FormValue call({String? name, _ProviderOption? provider});
|
||||
}
|
||||
|
||||
class _$_FormValueCopyWithWorkerImpl implements $_FormValueCopyWithWorker {
|
||||
_$_FormValueCopyWithWorkerImpl(this.that);
|
||||
|
||||
@override
|
||||
_FormValue call({dynamic name, dynamic provider}) {
|
||||
return _FormValue(
|
||||
name: name as String? ?? that.name,
|
||||
provider: provider as _ProviderOption? ?? that.provider);
|
||||
}
|
||||
|
||||
final _FormValue that;
|
||||
}
|
||||
|
||||
extension $_FormValueCopyWith on _FormValue {
|
||||
$_FormValueCopyWithWorker get copyWith => _$copyWith;
|
||||
$_FormValueCopyWithWorker get _$copyWith =>
|
||||
_$_FormValueCopyWithWorkerImpl(this);
|
||||
}
|
||||
|
||||
abstract class $_StateCopyWithWorker {
|
||||
_State call(
|
||||
{_FormValue? formValue,
|
||||
Collection? result,
|
||||
bool? isExporting,
|
||||
ExceptionEvent? error});
|
||||
}
|
||||
|
||||
class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||
_$_StateCopyWithWorkerImpl(this.that);
|
||||
|
||||
@override
|
||||
_State call(
|
||||
{dynamic formValue,
|
||||
dynamic result = copyWithNull,
|
||||
dynamic isExporting,
|
||||
dynamic error = copyWithNull}) {
|
||||
return _State(
|
||||
formValue: formValue as _FormValue? ?? that.formValue,
|
||||
result: result == copyWithNull ? that.result : result as Collection?,
|
||||
isExporting: isExporting as bool? ?? that.isExporting,
|
||||
error: error == copyWithNull ? that.error : error as ExceptionEvent?);
|
||||
}
|
||||
|
||||
final _State that;
|
||||
}
|
||||
|
||||
extension $_StateCopyWith on _State {
|
||||
$_StateCopyWithWorker get copyWith => _$copyWith;
|
||||
$_StateCopyWithWorker get _$copyWith => _$_StateCopyWithWorkerImpl(this);
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$_WrappedExportCollectionDialogStateNpLog
|
||||
on _WrappedExportCollectionDialogState {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger(
|
||||
"widget.export_collection_dialog._WrappedExportCollectionDialogState");
|
||||
}
|
||||
|
||||
extension _$_BlocNpLog on _Bloc {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("widget.export_collection_dialog._Bloc");
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// ToStringGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$_SubmitNameToString on _SubmitName {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_SubmitName {value: $value}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$_SubmitProviderToString on _SubmitProvider {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_SubmitProvider {value: ${value.name}}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$_SubmitFormToString on _SubmitForm {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_SubmitForm {}";
|
||||
}
|
||||
}
|
63
app/lib/widget/export_collection_dialog/bloc.dart
Normal file
63
app/lib/widget/export_collection_dialog/bloc.dart
Normal file
|
@ -0,0 +1,63 @@
|
|||
part of '../export_collection_dialog.dart';
|
||||
|
||||
@npLog
|
||||
class _Bloc extends Bloc<_Event, _State> {
|
||||
_Bloc({
|
||||
required this.account,
|
||||
required this.collectionsController,
|
||||
required this.collection,
|
||||
required this.items,
|
||||
}) : super(_State.init()) {
|
||||
on<_FormEvent>(_onFormEvent);
|
||||
}
|
||||
|
||||
Future<void> _onFormEvent(_FormEvent ev, Emitter<_State> emit) async {
|
||||
_log.info("$ev");
|
||||
if (ev is _SubmitName) {
|
||||
_onSubmitName(ev, emit);
|
||||
} else if (ev is _SubmitProvider) {
|
||||
_onSubmitProvider(ev, emit);
|
||||
} else if (ev is _SubmitForm) {
|
||||
await _onSubmitForm(ev, emit);
|
||||
}
|
||||
}
|
||||
|
||||
void _onSubmitName(_SubmitName ev, Emitter<_State> emit) {
|
||||
emit(state.copyWith(
|
||||
formValue: state.formValue.copyWith(name: ev.value),
|
||||
));
|
||||
}
|
||||
|
||||
void _onSubmitProvider(_SubmitProvider ev, Emitter<_State> emit) {
|
||||
emit(state.copyWith(
|
||||
formValue: state.formValue.copyWith(provider: ev.value),
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _onSubmitForm(_SubmitForm ev, Emitter<_State> emit) async {
|
||||
emit(state.copyWith(isExporting: true));
|
||||
try {
|
||||
final exporter = CollectionExporter(account, collectionsController,
|
||||
collection, items, state.formValue.name);
|
||||
final Collection result;
|
||||
switch (state.formValue.provider) {
|
||||
case _ProviderOption.appAlbum:
|
||||
result = await exporter.asAlbum();
|
||||
break;
|
||||
case _ProviderOption.ncAlbum:
|
||||
result = await exporter.asNcAlbum();
|
||||
break;
|
||||
}
|
||||
emit(state.copyWith(result: result));
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[_onSubmitForm] Failed while exporting", e, stackTrace);
|
||||
} finally {
|
||||
emit(state.copyWith(isExporting: false));
|
||||
}
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final CollectionsController collectionsController;
|
||||
final Collection collection;
|
||||
final List<CollectionItem> items;
|
||||
}
|
71
app/lib/widget/export_collection_dialog/state_event.dart
Normal file
71
app/lib/widget/export_collection_dialog/state_event.dart
Normal file
|
@ -0,0 +1,71 @@
|
|||
part of '../export_collection_dialog.dart';
|
||||
|
||||
@genCopyWith
|
||||
class _FormValue {
|
||||
const _FormValue({
|
||||
this.name = "",
|
||||
this.provider = _ProviderOption.appAlbum,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final _ProviderOption provider;
|
||||
}
|
||||
|
||||
@genCopyWith
|
||||
class _State {
|
||||
const _State({
|
||||
required this.formValue,
|
||||
this.result,
|
||||
required this.isExporting,
|
||||
this.error,
|
||||
});
|
||||
|
||||
factory _State.init() {
|
||||
return const _State(
|
||||
formValue: _FormValue(),
|
||||
isExporting: false,
|
||||
);
|
||||
}
|
||||
|
||||
final _FormValue formValue;
|
||||
final Collection? result;
|
||||
final bool isExporting;
|
||||
|
||||
final ExceptionEvent? error;
|
||||
}
|
||||
|
||||
abstract class _Event {
|
||||
const _Event();
|
||||
}
|
||||
|
||||
abstract class _FormEvent implements _Event {
|
||||
const _FormEvent();
|
||||
}
|
||||
|
||||
@toString
|
||||
class _SubmitName extends _FormEvent {
|
||||
const _SubmitName(this.value);
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
final String value;
|
||||
}
|
||||
|
||||
@toString
|
||||
class _SubmitProvider extends _FormEvent {
|
||||
const _SubmitProvider(this.value);
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
final _ProviderOption value;
|
||||
}
|
||||
|
||||
@toString
|
||||
class _SubmitForm extends _FormEvent {
|
||||
const _SubmitForm();
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
}
|
Loading…
Reference in a new issue