2021-12-10 19:44:56 +01:00
|
|
|
import 'package:flutter/material.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_album.dart';
|
|
|
|
import 'package:nc_photos/entity/album.dart';
|
2022-01-27 20:40:56 +01:00
|
|
|
import 'package:nc_photos/entity/album/provider.dart';
|
2021-12-10 19:44:56 +01:00
|
|
|
import 'package:nc_photos/entity/album_util.dart' as album_util;
|
|
|
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
|
|
|
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/widget/album_grid_item.dart';
|
|
|
|
import 'package:nc_photos/widget/builder/album_grid_item_builder.dart';
|
|
|
|
import 'package:nc_photos/widget/new_album_dialog.dart';
|
|
|
|
import 'package:nc_photos/widget/page_visibility_mixin.dart';
|
2022-12-16 16:01:04 +01:00
|
|
|
import 'package:np_codegen/np_codegen.dart';
|
|
|
|
|
|
|
|
part 'album_picker.g.dart';
|
2021-12-10 19:44:56 +01:00
|
|
|
|
|
|
|
class AlbumPickerArguments {
|
|
|
|
AlbumPickerArguments(this.account);
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
}
|
|
|
|
|
|
|
|
class AlbumPicker extends StatefulWidget {
|
|
|
|
static const routeName = "/album-picker";
|
|
|
|
|
|
|
|
static Route buildRoute(AlbumPickerArguments args) =>
|
|
|
|
MaterialPageRoute<Album>(
|
|
|
|
builder: (context) => AlbumPicker.fromArgs(args),
|
|
|
|
);
|
|
|
|
|
|
|
|
const AlbumPicker({
|
|
|
|
Key? key,
|
|
|
|
required this.account,
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
AlbumPicker.fromArgs(AlbumPickerArguments args, {Key? key})
|
|
|
|
: this(
|
|
|
|
key: key,
|
|
|
|
account: args.account,
|
|
|
|
);
|
|
|
|
|
|
|
|
@override
|
|
|
|
createState() => _AlbumPickerState();
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
}
|
|
|
|
|
2022-12-16 16:01:04 +01:00
|
|
|
@npLog
|
2021-12-10 19:44:56 +01:00
|
|
|
class _AlbumPickerState extends State<AlbumPicker>
|
|
|
|
with RouteAware, PageVisibilityMixin {
|
|
|
|
@override
|
|
|
|
initState() {
|
|
|
|
super.initState();
|
|
|
|
_initBloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
build(BuildContext context) {
|
2022-11-12 10:55:33 +01:00
|
|
|
return Scaffold(
|
2022-11-19 06:10:40 +01:00
|
|
|
body: BlocConsumer<ListAlbumBloc, ListAlbumBlocState>(
|
2022-11-12 10:55:33 +01:00
|
|
|
bloc: _bloc,
|
|
|
|
listener: (context, state) => _onStateChange(context, state),
|
2022-11-19 06:10:40 +01:00
|
|
|
builder: (context, state) => _buildContent(context, state),
|
2021-12-10 19:44:56 +01:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _initBloc() {
|
|
|
|
if (_bloc.state is ListAlbumBlocInit) {
|
|
|
|
_log.info("[_initBloc] Initialize bloc");
|
|
|
|
_reqQuery();
|
|
|
|
} else {
|
|
|
|
// process the current state
|
2022-06-20 13:49:58 +02:00
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
2022-12-11 06:01:13 +01:00
|
|
|
if (mounted) {
|
|
|
|
setState(() {
|
|
|
|
_onStateChange(context, _bloc.state);
|
|
|
|
});
|
|
|
|
}
|
2021-12-10 19:44:56 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildContent(BuildContext context, ListAlbumBlocState state) {
|
|
|
|
return CustomScrollView(
|
|
|
|
slivers: [
|
|
|
|
SliverAppBar(
|
|
|
|
title: Text(L10n.global().addToAlbumTooltip),
|
|
|
|
floating: true,
|
|
|
|
),
|
|
|
|
if (state is ListAlbumBlocLoading)
|
|
|
|
const SliverToBoxAdapter(
|
|
|
|
child: LinearProgressIndicator(),
|
|
|
|
),
|
|
|
|
SliverPadding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
sliver: SliverStaggeredGrid.extentBuilder(
|
|
|
|
maxCrossAxisExtent: 256,
|
|
|
|
mainAxisSpacing: 8,
|
|
|
|
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
if (index == 0) {
|
|
|
|
return _buildNewAlbumItem(context);
|
|
|
|
} else {
|
|
|
|
return _buildItem(context, index - 1);
|
|
|
|
}
|
|
|
|
},
|
2022-01-01 17:25:22 +01:00
|
|
|
itemCount: _sortedAlbums.length + 1,
|
2021-12-10 19:44:56 +01:00
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildNewAlbumItem(BuildContext context) {
|
2022-11-19 06:10:40 +01:00
|
|
|
return _NewAlbumView(
|
|
|
|
onTap: () => _onNewAlbumPressed(context),
|
2021-12-10 19:44:56 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildItem(BuildContext context, int index) {
|
|
|
|
final item = _sortedAlbums[index];
|
2022-11-19 06:10:40 +01:00
|
|
|
return _AlbumView(
|
|
|
|
account: widget.account,
|
|
|
|
album: item,
|
|
|
|
onTap: () => _onItemPressed(context, item),
|
2021-12-10 19:44:56 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _onStateChange(BuildContext context, ListAlbumBlocState state) {
|
|
|
|
if (state is ListAlbumBlocInit) {
|
|
|
|
_sortedAlbums = [];
|
|
|
|
} else if (state is ListAlbumBlocSuccess || state is ListAlbumBlocLoading) {
|
|
|
|
_transformItems(state.items);
|
|
|
|
} else if (state is ListAlbumBlocFailure) {
|
|
|
|
_transformItems(state.items);
|
|
|
|
if (isPageVisible()) {
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(exception_util.toUserString(state.exception)),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
} else if (state is ListAlbumBlocInconsistent) {
|
|
|
|
_reqQuery();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onNewAlbumPressed(BuildContext context) async {
|
|
|
|
try {
|
|
|
|
final album = await showDialog<Album>(
|
|
|
|
context: context,
|
|
|
|
builder: (_) => NewAlbumDialog(
|
|
|
|
account: widget.account,
|
|
|
|
isAllowDynamic: false,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
if (album == null) {
|
|
|
|
// user canceled
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Navigator.of(context).pop(album);
|
|
|
|
} catch (e, stacktrace) {
|
|
|
|
_log.shout("[_onNewAlbumPressed] Failed while showDialog", e, stacktrace);
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(exception_util.toUserString(e)),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _onItemPressed(BuildContext context, Album album) {
|
|
|
|
Navigator.of(context).pop(album);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _transformItems(List<ListAlbumBlocItem> items) {
|
|
|
|
_sortedAlbums = album_util.sorted(
|
2022-01-27 20:40:56 +01:00
|
|
|
items
|
|
|
|
.map((e) => e.album)
|
|
|
|
.where((a) => a.provider is AlbumStaticProvider)
|
|
|
|
.toList(),
|
|
|
|
_getSortFromPref());
|
2021-12-10 19:44:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void _reqQuery() {
|
|
|
|
_bloc.add(ListAlbumBlocQuery(widget.account));
|
|
|
|
}
|
|
|
|
|
|
|
|
late final _bloc = ListAlbumBloc.of(widget.account);
|
|
|
|
var _sortedAlbums = <Album>[];
|
|
|
|
}
|
|
|
|
|
2022-11-19 06:10:40 +01:00
|
|
|
class _NewAlbumView extends StatelessWidget {
|
|
|
|
const _NewAlbumView({
|
|
|
|
this.onTap,
|
|
|
|
});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
AlbumGridItem(
|
|
|
|
cover: ClipRRect(
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
child: Container(
|
|
|
|
color: Theme.of(context).listPlaceholderBackgroundColor,
|
|
|
|
constraints: const BoxConstraints.expand(),
|
|
|
|
child: Icon(
|
|
|
|
Icons.add,
|
|
|
|
color: Theme.of(context).listPlaceholderForegroundColor,
|
|
|
|
size: 88,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
title: L10n.global().createAlbumTooltip,
|
|
|
|
),
|
|
|
|
Positioned.fill(
|
|
|
|
child: Material(
|
|
|
|
type: MaterialType.transparency,
|
|
|
|
child: InkWell(
|
|
|
|
onTap: onTap,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final VoidCallback? onTap;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _AlbumView extends StatelessWidget {
|
|
|
|
const _AlbumView({
|
|
|
|
required this.account,
|
|
|
|
required this.album,
|
|
|
|
this.onTap,
|
|
|
|
});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
AlbumGridItemBuilder(
|
|
|
|
account: account,
|
|
|
|
album: album,
|
|
|
|
isShared: album.shares?.isNotEmpty == true,
|
|
|
|
).build(context),
|
|
|
|
Positioned.fill(
|
|
|
|
child: Material(
|
|
|
|
type: MaterialType.transparency,
|
|
|
|
child: InkWell(
|
|
|
|
onTap: onTap,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
final Album album;
|
|
|
|
final VoidCallback? onTap;
|
|
|
|
}
|
|
|
|
|
2021-12-10 19:44:56 +01:00
|
|
|
album_util.AlbumSort _getSortFromPref() {
|
|
|
|
try {
|
|
|
|
return album_util.AlbumSort.values[Pref().getHomeAlbumsSort()!];
|
|
|
|
} catch (_) {
|
|
|
|
// default
|
|
|
|
return album_util.AlbumSort.dateDescending;
|
|
|
|
}
|
|
|
|
}
|