Remove obsolete files

This commit is contained in:
Ming Ming 2023-05-18 01:43:19 +08:00
parent 05e1aecbf3
commit c6aced336e
14 changed files with 0 additions and 2272 deletions

View file

@ -1,96 +0,0 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/entity/share/data_source.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:to_string/to_string.dart';
part 'list_share.g.dart';
abstract class ListShareBlocEvent {
const ListShareBlocEvent();
}
@toString
class ListShareBlocQuery extends ListShareBlocEvent {
const ListShareBlocQuery(this.account, this.file);
@override
String toString() => _$toString();
final Account account;
final File file;
}
@toString
abstract class ListShareBlocState {
const ListShareBlocState(this.account, this.file, this.items);
@override
String toString() => _$toString();
final Account? account;
final File file;
final List<Share> items;
}
class ListShareBlocInit extends ListShareBlocState {
ListShareBlocInit() : super(null, File(path: ""), const []);
}
class ListShareBlocLoading extends ListShareBlocState {
const ListShareBlocLoading(Account? account, File file, List<Share> items)
: super(account, file, items);
}
class ListShareBlocSuccess extends ListShareBlocState {
const ListShareBlocSuccess(Account? account, File file, List<Share> items)
: super(account, file, items);
}
@toString
class ListShareBlocFailure extends ListShareBlocState {
const ListShareBlocFailure(
Account? account, File file, List<Share> items, this.exception)
: super(account, file, items);
@override
String toString() => _$toString();
final dynamic exception;
}
/// List all shares from a given file
@npLog
class ListShareBloc extends Bloc<ListShareBlocEvent, ListShareBlocState> {
ListShareBloc() : super(ListShareBlocInit()) {
on<ListShareBlocEvent>(_onEvent);
}
Future<void> _onEvent(
ListShareBlocEvent event, Emitter<ListShareBlocState> emit) async {
_log.info("[_onEvent] $event");
if (event is ListShareBlocQuery) {
await _onEventQuery(event, emit);
}
}
Future<void> _onEventQuery(
ListShareBlocQuery ev, Emitter<ListShareBlocState> emit) async {
try {
emit(ListShareBlocLoading(ev.account, ev.file, state.items));
emit(ListShareBlocSuccess(ev.account, ev.file, await _query(ev)));
} catch (e, stackTrace) {
_log.severe("[_onEventQuery] Exception while request", e, stackTrace);
emit(ListShareBlocFailure(ev.account, ev.file, state.items, e));
}
}
Future<List<Share>> _query(ListShareBlocQuery ev) {
final shareRepo = ShareRepo(ShareRemoteDataSource());
return shareRepo.list(ev.account, ev.file);
}
}

View file

@ -1,39 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'list_share.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$ListShareBlocNpLog on ListShareBloc {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("bloc.list_share.ListShareBloc");
}
// **************************************************************************
// ToStringGenerator
// **************************************************************************
extension _$ListShareBlocQueryToString on ListShareBlocQuery {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "ListShareBlocQuery {account: $account, file: ${file.path}}";
}
}
extension _$ListShareBlocStateToString on ListShareBlocState {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "${objectRuntimeType(this, "ListShareBlocState")} {account: $account, file: ${file.path}, items: [length: ${items.length}]}";
}
}
extension _$ListShareBlocFailureToString on ListShareBlocFailure {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "ListShareBlocFailure {account: $account, file: ${file.path}, items: [length: ${items.length}], exception: $exception}";
}
}

View file

@ -1,111 +0,0 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/bloc/bloc_util.dart' as bloc_util;
import 'package:nc_photos/entity/sharee.dart';
import 'package:nc_photos/entity/sharee/data_source.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:to_string/to_string.dart';
part 'list_sharee.g.dart';
abstract class ListShareeBlocEvent {
const ListShareeBlocEvent();
}
@toString
class ListShareeBlocQuery extends ListShareeBlocEvent {
const ListShareeBlocQuery(this.account);
@override
String toString() => _$toString();
final Account account;
}
@toString
abstract class ListShareeBlocState {
const ListShareeBlocState(this.account, this.items);
@override
String toString() => _$toString();
final Account? account;
final List<Sharee> items;
}
class ListShareeBlocInit extends ListShareeBlocState {
ListShareeBlocInit() : super(null, const []);
}
class ListShareeBlocLoading extends ListShareeBlocState {
const ListShareeBlocLoading(Account? account, List<Sharee> items)
: super(account, items);
}
class ListShareeBlocSuccess extends ListShareeBlocState {
const ListShareeBlocSuccess(Account? account, List<Sharee> items)
: super(account, items);
}
@toString
class ListShareeBlocFailure extends ListShareeBlocState {
const ListShareeBlocFailure(
Account? account, List<Sharee> items, this.exception)
: super(account, items);
@override
String toString() => _$toString();
final dynamic exception;
}
/// List all sharees of this account
@npLog
class ListShareeBloc extends Bloc<ListShareeBlocEvent, ListShareeBlocState> {
ListShareeBloc() : super(ListShareeBlocInit()) {
on<ListShareeBlocEvent>(_onEvent);
}
static ListShareeBloc of(Account account) {
final name = bloc_util.getInstNameForAccount("ListShareeBloc", account);
try {
_log.fine("[of] Resolving bloc for '$name'");
return KiwiContainer().resolve<ListShareeBloc>(name);
} catch (_) {
// no created instance for this account, make a new one
_log.info("[of] New bloc instance for account: $account");
final bloc = ListShareeBloc();
KiwiContainer().registerInstance<ListShareeBloc>(bloc, name: name);
return bloc;
}
}
Future<void> _onEvent(
ListShareeBlocEvent event, Emitter<ListShareeBlocState> emit) async {
_log.info("[_onEvent] $event");
if (event is ListShareeBlocQuery) {
await _onEventQuery(event, emit);
}
}
Future<void> _onEventQuery(
ListShareeBlocQuery ev, Emitter<ListShareeBlocState> emit) async {
try {
emit(ListShareeBlocLoading(ev.account, state.items));
emit(ListShareeBlocSuccess(ev.account, await _query(ev)));
} catch (e, stackTrace) {
_log.shout("[_onEventQuery] Exception while request", e, stackTrace);
emit(ListShareeBlocFailure(ev.account, state.items, e));
}
}
Future<List<Sharee>> _query(ListShareeBlocQuery ev) {
final shareeRepo = ShareeRepo(ShareeRemoteDataSource());
return shareeRepo.list(ev.account);
}
static final _log = _$ListShareeBlocNpLog.log;
}

View file

@ -1,39 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'list_sharee.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$ListShareeBlocNpLog on ListShareeBloc {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("bloc.list_sharee.ListShareeBloc");
}
// **************************************************************************
// ToStringGenerator
// **************************************************************************
extension _$ListShareeBlocQueryToString on ListShareeBlocQuery {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "ListShareeBlocQuery {account: $account}";
}
}
extension _$ListShareeBlocStateToString on ListShareeBlocState {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "${objectRuntimeType(this, "ListShareeBlocState")} {account: $account, items: [length: ${items.length}]}";
}
}
extension _$ListShareeBlocFailureToString on ListShareeBlocFailure {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "ListShareeBlocFailure {account: $account, items: [length: ${items.length}], exception: $exception}";
}
}

View file

@ -1,37 +0,0 @@
import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/entity/share.dart';
class ListDirShareItem {
const ListDirShareItem(this.file, this.shares);
/// The File returned contains only fileId and path. If you need other fields,
/// you must query the file again
final File file;
final List<Share> shares;
}
class ListDirShare {
const ListDirShare(this.shareRepo);
/// List all shares from a given dir
Future<List<ListDirShareItem>> call(Account account, File dir) async {
final shares = await shareRepo.listDir(account, dir);
final shareGroups = <int, List<Share>>{};
for (final s in shares) {
shareGroups[s.itemSource] ??= <Share>[];
shareGroups[s.itemSource]!.add(s);
}
return shareGroups.entries
.map((e) => ListDirShareItem(
File(
path: file_util.unstripPath(account, e.value.first.path),
fileId: e.key,
),
e.value))
.toList();
}
final ShareRepo shareRepo;
}

File diff suppressed because it is too large Load diff

View file

@ -1,25 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'album_browser.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$_AlbumBrowserStateNpLog on _AlbumBrowserState {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("widget.album_browser._AlbumBrowserState");
}
// **************************************************************************
// ToStringGenerator
// **************************************************************************
extension _$_ListItemToString on _ListItem {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "${objectRuntimeType(this, "_ListItem")} {index: $index}";
}
}

View file

@ -1,141 +0,0 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
import 'package:flutter/material.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/cache_manager_util.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/np_api_util.dart';
class AlbumBrowserAppBar extends StatelessWidget {
const AlbumBrowserAppBar({
Key? key,
required this.account,
required this.album,
this.coverPreviewUrl,
this.actions,
}) : super(key: key);
@override
build(BuildContext context) {
return SliverAppBar(
floating: true,
expandedHeight: 160,
flexibleSpace: FlexibleSpaceBar(
background: _getAppBarCover(context, account, coverPreviewUrl),
title: Text(
album.name,
style:
TextStyle(color: Theme.of(context).appBarTheme.foregroundColor),
),
),
actions: actions,
);
}
final Account account;
final Album album;
final String? coverPreviewUrl;
final List<Widget>? actions;
}
class AlbumBrowserEditAppBar extends StatefulWidget {
const AlbumBrowserEditAppBar({
Key? key,
required this.account,
required this.album,
this.coverPreviewUrl,
this.actions,
required this.onDonePressed,
required this.onAlbumNameSaved,
}) : super(key: key);
@override
createState() => _AlbumBrowserEditAppBarState();
final Account account;
final Album album;
final String? coverPreviewUrl;
final List<Widget>? actions;
final VoidCallback? onDonePressed;
final ValueChanged<String>? onAlbumNameSaved;
}
class _AlbumBrowserEditAppBarState extends State<AlbumBrowserEditAppBar> {
@override
initState() {
super.initState();
_controller = TextEditingController(text: widget.album.name);
}
@override
build(BuildContext context) {
return SliverAppBar(
floating: true,
expandedHeight: 160,
flexibleSpace: FlexibleSpaceBar(
background:
_getAppBarCover(context, widget.account, widget.coverPreviewUrl),
title: TextFormField(
controller: _controller,
decoration: InputDecoration(
hintText: L10n.global().nameInputHint,
),
validator: (_) {
// use _controller.text here because the value might be wrong if
// user scrolled the app bar off screen
if (_controller.text.isNotEmpty == true) {
return null;
} else {
return L10n.global().nameInputInvalidEmpty;
}
},
onSaved: (_) {
widget.onAlbumNameSaved?.call(_controller.text);
},
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
),
leading: IconButton(
icon: const Icon(Icons.check),
color: Theme.of(context).colorScheme.primary,
tooltip: L10n.global().doneButtonTooltip,
onPressed: widget.onDonePressed,
),
actions: widget.actions,
);
}
late TextEditingController _controller;
}
Widget? _getAppBarCover(
BuildContext context, Account account, String? coverPreviewUrl) {
try {
if (coverPreviewUrl != null) {
return Opacity(
opacity: Theme.of(context).brightness == Brightness.light ? 0.25 : 0.35,
child: FittedBox(
clipBehavior: Clip.hardEdge,
fit: BoxFit.cover,
child: CachedNetworkImage(
cacheManager: CoverCacheManager.inst,
imageUrl: coverPreviewUrl,
httpHeaders: {
"Authorization": AuthUtil.fromAccount(account).toHeaderValue(),
},
filterQuality: FilterQuality.high,
errorWidget: (context, url, error) {
// just leave it empty
return Container();
},
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
),
),
);
}
} catch (_) {}
return null;
}

View file

@ -1,262 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/debug_util.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/data_source.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/notified_action.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/use_case/import_pending_shared_album.dart';
import 'package:nc_photos/use_case/update_album.dart';
import 'package:nc_photos/widget/album_browser_app_bar.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
import 'package:nc_photos/widget/photo_list_util.dart' as photo_list_util;
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
import 'package:nc_photos/widget/selection_app_bar.dart';
import 'package:nc_photos/widget/zoom_menu_button.dart';
import 'package:np_codegen/np_codegen.dart';
part 'album_browser_mixin.g.dart';
@npLog
mixin AlbumBrowserMixin<T extends StatefulWidget>
on SelectableItemStreamListMixin<T> {
@override
initState() {
super.initState();
_thumbZoomLevel = Pref().getAlbumBrowserZoomLevelOr(0);
}
@protected
void initCover(Account account, Album album) {
try {
final coverFile = album.coverProvider.getCover(album);
_coverPreviewUrl = api_util.getFilePreviewUrl(account, coverFile!,
width: k.coverSize, height: k.coverSize, isKeepAspectRatio: false);
} catch (_) {}
}
@protected
Widget buildNormalAppBar(
BuildContext context,
Account account,
Album album, {
List<Widget>? actions,
List<PopupMenuEntry<int>> Function(BuildContext)? menuItemBuilder,
void Function(int)? onSelectedMenuItem,
}) {
final menuItems = [
if (canEdit)
PopupMenuItem(
value: _menuValueEdit,
child: Text(L10n.global().editAlbumMenuLabel),
),
if (canEdit && album.coverProvider is AlbumManualCoverProvider)
PopupMenuItem(
value: _menuValueUnsetCover,
child: Text(L10n.global().unsetAlbumCoverTooltip),
),
];
return AlbumBrowserAppBar(
account: account,
album: album,
coverPreviewUrl: _coverPreviewUrl,
actions: [
ZoomMenuButton(
initialZoom: _thumbZoomLevel,
minZoom: 0,
maxZoom: 2,
onZoomChanged: (value) {
setState(() {
_thumbZoomLevel = value.round();
});
Pref().setAlbumBrowserZoomLevel(_thumbZoomLevel);
},
),
if (album.albumFile?.path.startsWith(
remote_storage_util.getRemotePendingSharedAlbumsDir(account)) ==
true)
IconButton(
onPressed: () => _onAddToCollectionPressed(context, account, album),
icon: const Icon(Icons.library_add),
tooltip: L10n.global().addToCollectionsViewTooltip,
),
...(actions ?? []),
if (menuItemBuilder != null || menuItems.isNotEmpty)
PopupMenuButton<int>(
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
itemBuilder: (context) => [
...menuItems,
...(menuItemBuilder?.call(context) ?? []),
],
onSelected: (option) => _onMenuOptionSelected(
option, account, album, onSelectedMenuItem),
),
],
);
}
@protected
Widget buildSelectionAppBar(BuildContext context, List<Widget> actions) {
return SelectionAppBar(
count: selectedListItems.length,
onClosePressed: () {
setState(() {
clearSelectedItems();
});
},
actions: actions,
);
}
@protected
Widget buildEditAppBar(
BuildContext context,
Account account,
Album album, {
List<Widget>? actions,
}) {
return AlbumBrowserEditAppBar(
account: account,
album: album,
coverPreviewUrl: _coverPreviewUrl,
actions: actions,
onDonePressed: () {
if (validateEditMode()) {
setState(() {
_isEditMode = false;
});
doneEditMode();
}
},
onAlbumNameSaved: (value) {
_editFormValue.name = value;
},
);
}
@protected
bool get isEditMode => _isEditMode;
@protected
bool get canEdit => true;
@protected
@mustCallSuper
void enterEditMode() {}
/// Validates the pending modifications
@protected
bool validateEditMode() => true;
@protected
void doneEditMode() {}
/// Return a new album with the edits
@protected
Album makeEdited(Album album) {
return album.copyWith(
name: _editFormValue.name,
);
}
@protected
int get thumbSize => photo_list_util.getThumbSize(_thumbZoomLevel);
void _onMenuOptionSelected(int option, Account account, Album album,
void Function(int)? onSelectedMenuItem) {
if (option >= 0) {
onSelectedMenuItem?.call(option);
} else {
switch (option) {
case _menuValueEdit:
_onAppBarEditPressed(album);
break;
case _menuValueUnsetCover:
_onUnsetCoverPressed(account, album);
break;
default:
_log.shout("[_onMenuOptionSelected] Unknown value: $option");
break;
}
}
}
void _onAppBarEditPressed(Album album) {
setState(() {
_isEditMode = true;
enterEditMode();
_editFormValue = _EditFormValue();
});
}
Future<void> _onUnsetCoverPressed(Account account, Album album) async {
_log.info("[_onUnsetCoverPressed] Unset album cover for '${album.name}'");
final c = KiwiContainer().resolve<DiContainer>();
try {
await NotifiedAction(
() async {
final albumRepo = AlbumRepo(AlbumCachedDataSource(c));
await UpdateAlbum(albumRepo)(
account,
album.copyWith(
coverProvider: const AlbumAutoCoverProvider(),
));
},
L10n.global().unsetAlbumCoverProcessingNotification,
L10n.global().unsetAlbumCoverSuccessNotification,
failureText: L10n.global().setCollectionCoverFailureNotification,
)();
} catch (e, stackTrace) {
_log.shout(
"[_onUnsetCoverPressed] Failed while updating album", e, stackTrace);
}
}
Future<void> _onAddToCollectionPressed(
BuildContext context, Account account, Album album) async {
Album? newAlbum;
try {
await NotifiedAction(
() async {
newAlbum = await ImportPendingSharedAlbum(
KiwiContainer().resolve<DiContainer>())(account, album);
},
L10n.global().addToCollectionsViewProcessingNotification(album.name),
L10n.global().addToCollectionsViewSuccessNotification(album.name),
)();
} catch (e, stackTrace) {
_log.shout(
"[_onAddToCollectionPressed] Failed while _onAddToCollectionPressed: ${logFilename(album.albumFile?.path)}",
e,
stackTrace);
}
if (newAlbum != null && mounted) {
album_browser_util.pushReplacement(context, account, newAlbum!);
}
}
String? _coverPreviewUrl;
var _thumbZoomLevel = 0;
var _isEditMode = false;
var _editFormValue = _EditFormValue();
static const _menuValueEdit = -1;
static const _menuValueUnsetCover = -2;
}
class _EditFormValue {
late String name;
}

View file

@ -1,14 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'album_browser_mixin.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$AlbumBrowserMixinNpLog on AlbumBrowserMixin {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("widget.album_browser_mixin.AlbumBrowserMixin");
}

View file

@ -1,22 +0,0 @@
import 'package:flutter/widgets.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/widget/album_browser.dart';
/// Push the corresponding browser route for this album
void push(BuildContext context, Account account, Album album) {
if (album.provider is AlbumStaticProvider) {
Navigator.of(context).pushNamed(AlbumBrowser.routeName,
arguments: AlbumBrowserArguments(account, album));
}
}
/// Push the corresponding browser route for this album and replace the current
/// route
void pushReplacement(BuildContext context, Account account, Album album) {
if (album.provider is AlbumStaticProvider) {
Navigator.of(context).pushReplacementNamed(AlbumBrowser.routeName,
arguments: AlbumBrowserArguments(account, album));
}
}

View file

@ -1,59 +0,0 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:nc_photos/widget/draggable.dart' as my;
import 'package:nc_photos/widget/measurable_item_list.dart';
abstract class DraggableItem {
Widget buildWidget(BuildContext context);
/// The widget to show under the pointer when a drag is under way.
///
/// Return null if you wish to just use the same widget as display
Widget? buildDragFeedbackWidget(BuildContext context) => null;
bool get isDraggable => false;
DragTargetAccept<DraggableItem>? get onDropBefore => null;
DragTargetAccept<DraggableItem>? get onDropAfter => null;
VoidCallback? get onDragStarted => null;
VoidCallback? get onDragEndedAny => null;
StaggeredTile get staggeredTile => const StaggeredTile.count(1, 1);
}
mixin DraggableItemListMixin<T extends StatefulWidget> on State<T> {
@protected
Widget buildDraggableItemList({
required double maxCrossAxisExtent,
ValueChanged<double?>? onMaxExtentChanged,
}) {
_maxCrossAxisExtent = maxCrossAxisExtent;
return MeasurableItemList(
maxCrossAxisExtent: maxCrossAxisExtent,
itemCount: _items.length,
itemBuilder: _buildItem,
staggeredTileBuilder: (index) => _items[index].staggeredTile,
onMaxExtentChanged: onMaxExtentChanged,
);
}
@protected
set draggableItemList(List<DraggableItem> newItems) {
_items = newItems;
}
Widget _buildItem(BuildContext context, int index) {
final item = _items[index];
return my.Draggable(
data: item,
feedback: item.buildDragFeedbackWidget(context),
onDropBefore: item.onDropBefore,
onDropAfter: item.onDropAfter,
onDragStarted: item.onDragStarted,
onDragEndedAny: item.onDragEndedAny,
feedbackSize: Size(_maxCrossAxisExtent * .65, _maxCrossAxisExtent * .65),
child: item.buildWidget(context),
);
}
var _items = <DraggableItem>[];
late double _maxCrossAxisExtent;
}

View file

@ -1,346 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:mutex/mutex.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/async_util.dart' as async_util;
import 'package:nc_photos/bloc/list_sharee.dart';
import 'package:nc_photos/bloc/search_suggestion.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/sharee.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/use_case/album/share_album_with_user.dart';
import 'package:nc_photos/use_case/album/unshare_album_with_user.dart';
import 'package:nc_photos/widget/album_share_outlier_browser.dart';
import 'package:nc_photos/widget/dialog_scaffold.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_common/ci_string.dart';
part 'share_album_dialog.g.dart';
class ShareAlbumDialog extends StatefulWidget {
ShareAlbumDialog({
Key? key,
required this.account,
required this.album,
}) : assert(album.albumFile != null),
super(key: key);
@override
createState() => _ShareAlbumDialogState();
final Account account;
final Album album;
}
@npLog
class _ShareAlbumDialogState extends State<ShareAlbumDialog> {
_ShareAlbumDialogState() {
final c = KiwiContainer().resolve<DiContainer>();
assert(require(c));
_c = c;
}
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.shareRepo);
@override
initState() {
super.initState();
_album = widget.album;
_items = _album.shares
?.map((s) =>
_ShareItem(s.userId, s.displayName ?? s.userId.toString()))
.toList() ??
[];
_initBloc();
}
@override
build(BuildContext context) {
return DialogScaffold(
canPop: _processingSharee.isEmpty,
body: BlocListener<ListShareeBloc, ListShareeBlocState>(
bloc: _shareeBloc,
listener: _onShareeStateChange,
child: Builder(
builder: _buildContent,
),
),
);
}
Widget _buildContent(BuildContext context) {
return SimpleDialog(
title: Text(L10n.global().shareAlbumDialogTitle),
children: [
..._items.map((i) => _buildItem(context, i)),
_buildCreateShareItem(context),
],
);
}
Widget _buildItem(BuildContext context, _ShareItem share) {
final isProcessing = _processingSharee.any((s) => s == share.shareWith);
final Widget trailing;
if (isProcessing) {
trailing = const Padding(
padding: EdgeInsetsDirectional.only(end: 12),
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(),
),
);
} else {
trailing = Checkbox(
value: true,
onChanged: (_) {},
);
}
return SimpleDialogOption(
onPressed: isProcessing ? () {} : () => _onShareItemPressed(share),
child: ListTile(
title: Text(share.displayName),
subtitle: Text(share.shareWith.toString()),
// pass through the tap event
trailing: IgnorePointer(
child: trailing,
),
),
);
}
Widget _buildCreateShareItem(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: TypeAheadField<Sharee>(
textFieldConfiguration: TextFieldConfiguration(
controller: _searchController,
decoration: InputDecoration(
hintText: L10n.global().addUserInputHint,
),
),
suggestionsCallback: _onSearch,
itemBuilder: (context, suggestion) => ListTile(
title: Text(suggestion.label),
subtitle: Text(suggestion.shareWith.toString()),
),
onSuggestionSelected: _onSearchSuggestionSelected,
hideOnEmpty: true,
hideOnLoading: true,
autoFlipDirection: true,
),
);
}
void _onShareeStateChange(BuildContext context, ListShareeBlocState state) {
if (state is ListShareeBlocSuccess) {
_transformShareeItems(state.items);
} else if (state is ListShareeBlocFailure) {
SnackBarManager().showSnackBar(SnackBar(
content: Text(exception_util.toUserString(state.exception)),
duration: k.snackBarDurationNormal,
));
}
}
Future<void> _onShareItemPressed(_ShareItem share) async {
setState(() {
_processingSharee.add(share.shareWith);
});
try {
if (await _removeShare(share)) {
if (mounted) {
setState(() {
_items.remove(share);
_onShareItemListUpdated();
});
}
}
} finally {
if (mounted) {
setState(() {
_processingSharee.remove(share.shareWith);
});
}
}
}
Future<Iterable<Sharee>> _onSearch(String pattern) async {
_suggestionBloc.add(SearchSuggestionBlocSearchEvent(pattern.toCi()));
await Future.delayed(const Duration(milliseconds: 500));
await async_util
.wait(() => _suggestionBloc.state is! SearchSuggestionBlocLoading);
if (_suggestionBloc.state is SearchSuggestionBlocSuccess) {
return _suggestionBloc.state.results;
} else {
return [];
}
}
Future<void> _onSearchSuggestionSelected(Sharee sharee) async {
_searchController.clear();
final item = _ShareItem(sharee.shareWith, sharee.label);
var isGood = false;
setState(() {
_items.add(item);
_onShareItemListUpdated();
_processingSharee.add(sharee.shareWith);
});
try {
isGood = await _createShare(sharee);
} finally {
if (mounted) {
setState(() {
if (!isGood) {
_items.remove(item);
_onShareItemListUpdated();
}
_processingSharee.remove(sharee.shareWith);
});
}
}
}
void _onShareItemListUpdated() {
if (_shareeBloc.state is ListShareeBlocSuccess) {
_transformShareeItems(_shareeBloc.state.items);
}
}
void _onFixPressed() {
Navigator.of(context).pushNamed(AlbumShareOutlierBrowser.routeName,
arguments: AlbumShareOutlierBrowserArguments(widget.account, _album));
}
void _transformShareeItems(List<Sharee> sharees) {
final candidates = sharees
.where((s) =>
s.shareWith != widget.account.userId &&
// remove users already shared with
!_items.any((i) => i.shareWith == s.shareWith))
.toList();
_suggestionBloc
.add(SearchSuggestionBlocUpdateItemsEvent<Sharee>(candidates));
}
Future<bool> _createShare(Sharee sharee) async {
var hasFailure = false;
try {
_album = await _editMutex.protect(() async {
return await ShareAlbumWithUser(_c.shareRepo, _c.albumRepo)(
widget.account,
_album,
sharee,
onShareFileFailed: (_, __, ___) {
hasFailure = true;
},
);
});
} catch (e, stackTrace) {
_log.shout(
"[_createShare] Failed while ShareAlbumWithUser", e, stackTrace);
SnackBarManager().showSnackBar(SnackBar(
content: Text(exception_util.toUserString(e)),
duration: k.snackBarDurationNormal,
));
return false;
}
SnackBarManager().showSnackBar(SnackBar(
content: Text(hasFailure
? L10n.global()
.shareAlbumSuccessWithErrorNotification(sharee.shareWith)
: L10n.global().shareAlbumSuccessNotification(sharee.shareWith)),
action: hasFailure
? SnackBarAction(
label: L10n.global().fixButtonLabel,
onPressed: _onFixPressed,
)
: null,
duration: k.snackBarDurationNormal,
));
return true;
}
Future<bool> _removeShare(_ShareItem share) async {
var hasFailure = false;
try {
_album = await _editMutex.protect(() async {
return await UnshareAlbumWithUser(
KiwiContainer().resolve<DiContainer>())(
widget.account,
_album,
share.shareWith,
onUnshareFileFailed: (_, __, ___) {
hasFailure = true;
},
);
});
} catch (e, stackTrace) {
_log.shout(
"[_removeShare] Failed while UnshareAlbumWithUser", e, stackTrace);
SnackBarManager().showSnackBar(SnackBar(
content: Text(exception_util.toUserString(e)),
duration: k.snackBarDurationNormal,
));
return false;
}
SnackBarManager().showSnackBar(SnackBar(
content: Text(hasFailure
? L10n.global()
.unshareAlbumSuccessWithErrorNotification(share.shareWith)
: L10n.global().unshareAlbumSuccessNotification(share.shareWith)),
action: hasFailure
? SnackBarAction(
label: L10n.global().fixButtonLabel,
onPressed: _onFixPressed,
)
: null,
duration: k.snackBarDurationNormal,
));
return true;
}
Future<void> _initBloc() async {
if (_shareeBloc.state is ListShareeBlocSuccess) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_onShareeStateChange(context, _shareeBloc.state);
});
}
});
} else {
_log.info("[_initBloc] Initialize bloc");
_shareeBloc.add(ListShareeBlocQuery(widget.account));
}
}
late final DiContainer _c;
late final _shareeBloc = ListShareeBloc.of(widget.account);
final _suggestionBloc = SearchSuggestionBloc<Sharee>(
itemToKeywords: (item) => [item.shareWith, item.label.toCi()],
);
late Album _album;
final _editMutex = Mutex();
late final List<_ShareItem> _items;
final _processingSharee = <CiString>[];
final _searchController = TextEditingController();
}
class _ShareItem {
_ShareItem(this.shareWith, this.displayName);
final CiString shareWith;
final String displayName;
}

View file

@ -1,14 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'share_album_dialog.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$_ShareAlbumDialogStateNpLog on _ShareAlbumDialogState {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("widget.share_album_dialog._ShareAlbumDialogState");
}