2021-08-20 19:02:13 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:nc_photos/account.dart';
|
|
|
|
import 'package:nc_photos/app_localizations.dart';
|
|
|
|
import 'package:nc_photos/bloc/list_pending_shared_album.dart';
|
|
|
|
import 'package:nc_photos/entity/album.dart';
|
|
|
|
import 'package:nc_photos/entity/file.dart';
|
|
|
|
import 'package:nc_photos/entity/file/data_source.dart';
|
|
|
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
|
|
|
import 'package:nc_photos/iterable_extension.dart';
|
|
|
|
import 'package:nc_photos/k.dart' as k;
|
|
|
|
import 'package:nc_photos/pref.dart';
|
|
|
|
import 'package:nc_photos/snack_bar_manager.dart';
|
|
|
|
import 'package:nc_photos/theme.dart';
|
|
|
|
import 'package:nc_photos/use_case/import_potential_shared_album.dart';
|
|
|
|
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
|
|
|
|
import 'package:nc_photos/widget/builder/album_grid_item_builder.dart';
|
|
|
|
import 'package:nc_photos/widget/empty_list_indicator.dart';
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
class PendingAlbumsArguments {
|
|
|
|
PendingAlbumsArguments(this.account);
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
}
|
|
|
|
|
|
|
|
class PendingAlbums extends StatefulWidget {
|
|
|
|
static const routeName = "/pending-albums";
|
|
|
|
|
2021-08-22 13:13:53 +02:00
|
|
|
static Route buildRoute(PendingAlbumsArguments args) => MaterialPageRoute(
|
2021-08-20 19:02:13 +02:00
|
|
|
builder: (context) => PendingAlbums.fromArgs(args),
|
|
|
|
);
|
|
|
|
|
|
|
|
PendingAlbums({
|
|
|
|
Key? key,
|
|
|
|
required this.account,
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
PendingAlbums.fromArgs(PendingAlbumsArguments args, {Key? key})
|
|
|
|
: this(
|
|
|
|
key: key,
|
|
|
|
account: args.account,
|
|
|
|
);
|
|
|
|
|
|
|
|
@override
|
|
|
|
createState() => _PendingAlbumsState();
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _PendingAlbumsState extends State<PendingAlbums> {
|
|
|
|
@override
|
|
|
|
initState() {
|
|
|
|
super.initState();
|
|
|
|
_importPotentialSharedAlbum().then((_) {
|
|
|
|
_bloc.add(ListPendingSharedAlbumBlocQuery(widget.account));
|
|
|
|
});
|
|
|
|
Pref.inst().setNewSharedAlbum(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
build(BuildContext context) {
|
|
|
|
return AppTheme(
|
|
|
|
child: Scaffold(
|
|
|
|
body: BlocListener<ListPendingSharedAlbumBloc,
|
|
|
|
ListPendingSharedAlbumBlocState>(
|
|
|
|
bloc: _bloc,
|
|
|
|
listener: (context, state) => _onStateChange(context, state),
|
|
|
|
child: BlocBuilder<ListPendingSharedAlbumBloc,
|
|
|
|
ListPendingSharedAlbumBlocState>(
|
|
|
|
bloc: _bloc,
|
|
|
|
builder: (context, state) => _buildContent(context, state),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildContent(
|
|
|
|
BuildContext context, ListPendingSharedAlbumBlocState state) {
|
|
|
|
if (state is ListPendingSharedAlbumBlocSuccess && _items.isEmpty) {
|
|
|
|
return Column(
|
|
|
|
children: [
|
|
|
|
AppBar(
|
|
|
|
title: Text("Sharing with you"),
|
|
|
|
elevation: 0,
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: EmptyListIndicator(
|
|
|
|
icon: Icons.share_outlined,
|
|
|
|
text: L10n.of(context).listEmptyText,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
Theme(
|
|
|
|
data: Theme.of(context).copyWith(
|
|
|
|
accentColor: AppTheme.getOverscrollIndicatorColor(context),
|
|
|
|
),
|
|
|
|
child: CustomScrollView(
|
|
|
|
slivers: [
|
|
|
|
SliverAppBar(
|
|
|
|
title: Text("Sharing with you"),
|
|
|
|
),
|
|
|
|
SliverPadding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
sliver: SliverStaggeredGrid.extentBuilder(
|
|
|
|
maxCrossAxisExtent: 256,
|
|
|
|
mainAxisSpacing: 8,
|
|
|
|
itemCount: _items.length,
|
|
|
|
itemBuilder: _buildItem,
|
|
|
|
staggeredTileBuilder: (_) =>
|
|
|
|
const StaggeredTile.count(1, 1),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (!_isReady || state is ListPendingSharedAlbumBlocLoading)
|
|
|
|
Align(
|
|
|
|
alignment: Alignment.bottomCenter,
|
|
|
|
child: const LinearProgressIndicator(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildItem(BuildContext context, int index) {
|
|
|
|
final item = _items[index];
|
2021-08-22 22:24:13 +02:00
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
AlbumGridItemBuilder(
|
|
|
|
account: widget.account,
|
|
|
|
album: item.album,
|
|
|
|
).build(context),
|
|
|
|
Positioned.fill(
|
|
|
|
child: Material(
|
|
|
|
type: MaterialType.transparency,
|
|
|
|
child: InkWell(
|
|
|
|
onTap: () => _onItemTap(context, item),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
2021-08-20 19:02:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void _onStateChange(
|
|
|
|
BuildContext context, ListPendingSharedAlbumBlocState state) {
|
|
|
|
if (state is ListPendingSharedAlbumBlocSuccess ||
|
|
|
|
state is ListPendingSharedAlbumBlocLoading) {
|
|
|
|
_transformItems(state.items);
|
|
|
|
} else if (state is ListPendingSharedAlbumBlocFailure) {
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(exception_util.toUserString(state.exception, context)),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
} else if (state is ListPendingSharedAlbumBlocInconsistent) {
|
|
|
|
_bloc.add(ListPendingSharedAlbumBlocQuery(widget.account));
|
|
|
|
}
|
|
|
|
_isReady = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _onItemTap(BuildContext context, _GridItem item) {
|
|
|
|
album_browser_util.open(context, widget.account, item.album);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _transformItems(List<ListPendingSharedAlbumBlocItem> items) {
|
|
|
|
final sortedAlbums = items
|
|
|
|
.map((e) => Tuple2(
|
|
|
|
e.album.provider.latestItemTime ?? e.album.lastUpdated, e.album))
|
|
|
|
.sorted((a, b) {
|
|
|
|
// then sort in descending order
|
|
|
|
final tmp = b.item1.compareTo(a.item1);
|
|
|
|
if (tmp != 0) {
|
|
|
|
return tmp;
|
|
|
|
} else {
|
|
|
|
return a.item2.name.compareTo(b.item2.name);
|
|
|
|
}
|
|
|
|
}).map((e) => e.item2);
|
|
|
|
_items.clear();
|
|
|
|
_items.addAll(sortedAlbums.map((e) => _GridItem(e)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _importPotentialSharedAlbum() async {
|
|
|
|
final fileRepo = FileRepo(FileWebdavDataSource());
|
|
|
|
// don't want the potential albums to be cached at this moment
|
|
|
|
final albumRepo = AlbumRepo(AlbumRemoteDataSource());
|
|
|
|
try {
|
|
|
|
await ImportPotentialSharedAlbum(fileRepo, albumRepo)(widget.account);
|
|
|
|
} catch (e, stacktrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[_importPotentialSharedAlbum] Failed while ImportPotentialSharedAlbum",
|
|
|
|
e,
|
|
|
|
stacktrace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
final _bloc = ListPendingSharedAlbumBloc();
|
|
|
|
bool _isReady = false;
|
|
|
|
|
|
|
|
var _items = <_GridItem>[];
|
|
|
|
|
2021-08-22 13:13:53 +02:00
|
|
|
static final _log = Logger("widget.pending_albums._PendingAlbumsState");
|
2021-08-20 19:02:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class _GridItem {
|
|
|
|
_GridItem(this.album);
|
|
|
|
|
|
|
|
Album album;
|
|
|
|
}
|