mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-22 06:59:21 +01:00
Add a button to list all people in a dedicated view
This commit is contained in:
parent
bc16dc1530
commit
7fe757ad5e
6 changed files with 352 additions and 20 deletions
|
@ -92,7 +92,7 @@ class ListPersonBloc extends Bloc<ListPersonBlocEvent, ListPersonBlocState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Person>> _query(ListPersonBlocQuery ev) =>
|
Future<List<Person>> _query(ListPersonBlocQuery ev) =>
|
||||||
ListPerson(_c)(ev.account);
|
ListPerson(_c.withLocalRepo())(ev.account);
|
||||||
|
|
||||||
final DiContainer _c;
|
final DiContainer _c;
|
||||||
|
|
||||||
|
|
|
@ -1370,6 +1370,10 @@
|
||||||
"@searchFilterBubbleFavoriteFalseText": {
|
"@searchFilterBubbleFavoriteFalseText": {
|
||||||
"description": "List of active search filters shown in the result page (by favorites, false)"
|
"description": "List of active search filters shown in the result page (by favorites, false)"
|
||||||
},
|
},
|
||||||
|
"showAllButtonLabel": "SHOW ALL",
|
||||||
|
"@showAllButtonLabel": {
|
||||||
|
"description": "A button to show all items of a certain item group (e.g., show all recognized faces)"
|
||||||
|
},
|
||||||
|
|
||||||
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
||||||
"@errorUnauthenticated": {
|
"@errorUnauthenticated": {
|
||||||
|
|
|
@ -142,6 +142,7 @@
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText",
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel",
|
||||||
"errorAlbumDowngrade"
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -302,6 +303,7 @@
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText",
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel",
|
||||||
"errorAlbumDowngrade"
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -342,12 +344,14 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
"settingsLanguageOptionSystemDefaultLabel",
|
"settingsLanguageOptionSystemDefaultLabel",
|
||||||
"rootPickerSkipConfirmationDialogContent2"
|
"rootPickerSkipConfirmationDialogContent2",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fi": [
|
"fi": [
|
||||||
|
@ -368,7 +372,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fr": [
|
"fr": [
|
||||||
|
@ -433,7 +438,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pl": [
|
"pl": [
|
||||||
|
@ -515,7 +521,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pt": [
|
"pt": [
|
||||||
|
@ -576,7 +583,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
|
@ -637,7 +645,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh": [
|
"zh": [
|
||||||
|
@ -698,7 +707,8 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh_Hant": [
|
"zh_Hant": [
|
||||||
|
@ -759,6 +769,7 @@
|
||||||
"searchFilterBubbleTypeVideoText",
|
"searchFilterBubbleTypeVideoText",
|
||||||
"searchFilterFavoriteLabel",
|
"searchFilterFavoriteLabel",
|
||||||
"searchFilterBubbleFavoriteTrueText",
|
"searchFilterBubbleFavoriteTrueText",
|
||||||
"searchFilterBubbleFavoriteFalseText"
|
"searchFilterBubbleFavoriteFalseText",
|
||||||
|
"showAllButtonLabel"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import 'package:nc_photos/widget/enhanced_photo_browser.dart';
|
||||||
import 'package:nc_photos/widget/home.dart';
|
import 'package:nc_photos/widget/home.dart';
|
||||||
import 'package:nc_photos/widget/image_editor.dart';
|
import 'package:nc_photos/widget/image_editor.dart';
|
||||||
import 'package:nc_photos/widget/local_file_viewer.dart';
|
import 'package:nc_photos/widget/local_file_viewer.dart';
|
||||||
|
import 'package:nc_photos/widget/people_browser.dart';
|
||||||
import 'package:nc_photos/widget/person_browser.dart';
|
import 'package:nc_photos/widget/person_browser.dart';
|
||||||
import 'package:nc_photos/widget/root_picker.dart';
|
import 'package:nc_photos/widget/root_picker.dart';
|
||||||
import 'package:nc_photos/widget/settings.dart';
|
import 'package:nc_photos/widget/settings.dart';
|
||||||
|
@ -165,6 +166,7 @@ class _MyAppState extends State<MyApp>
|
||||||
route ??= _handleImageEditorRoute(settings);
|
route ??= _handleImageEditorRoute(settings);
|
||||||
route ??= _handleChangelogRoute(settings);
|
route ??= _handleChangelogRoute(settings);
|
||||||
route ??= _handleTagBrowserRoute(settings);
|
route ??= _handleTagBrowserRoute(settings);
|
||||||
|
route ??= _handlePeopleBrowserRoute(settings);
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +557,19 @@ class _MyAppState extends State<MyApp>
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Route<dynamic>? _handlePeopleBrowserRoute(RouteSettings settings) {
|
||||||
|
try {
|
||||||
|
if (settings.name == PeopleBrowser.routeName &&
|
||||||
|
settings.arguments != null) {
|
||||||
|
final args = settings.arguments as PeopleBrowserArguments;
|
||||||
|
return PeopleBrowser.buildRoute(args);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_log.severe("[_handlePeopleBrowserRoute] Failed while handling route", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
final _navigatorKey = GlobalKey<NavigatorState>();
|
final _navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
|
292
app/lib/widget/people_browser.dart
Normal file
292
app/lib/widget/people_browser.dart
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
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:kiwi/kiwi.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:nc_photos/account.dart';
|
||||||
|
import 'package:nc_photos/api/api.dart';
|
||||||
|
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||||
|
import 'package:nc_photos/app_localizations.dart';
|
||||||
|
import 'package:nc_photos/bloc/list_person.dart';
|
||||||
|
import 'package:nc_photos/cache_manager_util.dart';
|
||||||
|
import 'package:nc_photos/di_container.dart';
|
||||||
|
import 'package:nc_photos/entity/person.dart';
|
||||||
|
import 'package:nc_photos/exception.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/theme.dart';
|
||||||
|
import 'package:nc_photos/widget/person_browser.dart';
|
||||||
|
|
||||||
|
class PeopleBrowserArguments {
|
||||||
|
const PeopleBrowserArguments(this.account);
|
||||||
|
|
||||||
|
final Account account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show a list of all people associated with this account
|
||||||
|
class PeopleBrowser extends StatefulWidget {
|
||||||
|
static const routeName = "/people-browser";
|
||||||
|
|
||||||
|
static Route buildRoute(PeopleBrowserArguments args) => MaterialPageRoute(
|
||||||
|
builder: (context) => PeopleBrowser.fromArgs(args),
|
||||||
|
);
|
||||||
|
|
||||||
|
const PeopleBrowser({
|
||||||
|
Key? key,
|
||||||
|
required this.account,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
PeopleBrowser.fromArgs(PeopleBrowserArguments args, {Key? key})
|
||||||
|
: this(
|
||||||
|
key: key,
|
||||||
|
account: args.account,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
createState() => _PeopleBrowserState();
|
||||||
|
|
||||||
|
final Account account;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PeopleBrowserState extends State<PeopleBrowser> {
|
||||||
|
@override
|
||||||
|
initState() {
|
||||||
|
super.initState();
|
||||||
|
_initBloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
build(BuildContext context) {
|
||||||
|
return AppTheme(
|
||||||
|
child: Scaffold(
|
||||||
|
body: BlocListener<ListPersonBloc, ListPersonBlocState>(
|
||||||
|
bloc: _bloc,
|
||||||
|
listener: (context, state) => _onStateChange(context, state),
|
||||||
|
child: BlocBuilder<ListPersonBloc, ListPersonBlocState>(
|
||||||
|
bloc: _bloc,
|
||||||
|
builder: (context, state) => _buildContent(context, state),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initBloc() {
|
||||||
|
if (_bloc.state is ListPersonBlocInit) {
|
||||||
|
_log.info("[_initBloc] Initialize bloc");
|
||||||
|
} else {
|
||||||
|
// process the current state
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
_onStateChange(context, _bloc.state);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_reqQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildContent(BuildContext context, ListPersonBlocState state) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||||
|
secondary: AppTheme.getOverscrollIndicatorColor(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
_buildAppBar(context),
|
||||||
|
if (state is ListPersonBlocLoading)
|
||||||
|
const SliverToBoxAdapter(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: LinearProgressIndicator(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
sliver: SliverStaggeredGrid.extentBuilder(
|
||||||
|
maxCrossAxisExtent: 160,
|
||||||
|
mainAxisSpacing: 8,
|
||||||
|
itemCount: _items.length,
|
||||||
|
itemBuilder: _buildItem,
|
||||||
|
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAppBar(BuildContext context) {
|
||||||
|
return SliverAppBar(
|
||||||
|
title: Text(L10n.global().collectionPeopleLabel),
|
||||||
|
floating: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildItem(BuildContext context, int index) {
|
||||||
|
final item = _items[index];
|
||||||
|
return item.buildWidget(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStateChange(BuildContext context, ListPersonBlocState state) {
|
||||||
|
if (state is ListPersonBlocInit) {
|
||||||
|
_items = [];
|
||||||
|
} else if (state is ListPersonBlocSuccess ||
|
||||||
|
state is ListPersonBlocLoading) {
|
||||||
|
_transformItems(state.items);
|
||||||
|
} else if (state is ListPersonBlocFailure) {
|
||||||
|
_transformItems(state.items);
|
||||||
|
try {
|
||||||
|
final e = state.exception as ApiException;
|
||||||
|
if (e.response.statusCode == 404) {
|
||||||
|
// face recognition app probably not installed, ignore
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
SnackBarManager().showSnackBar(SnackBar(
|
||||||
|
content: Text(exception_util.toUserString(state.exception)),
|
||||||
|
duration: k.snackBarDurationNormal,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onItemTap(Person person) {
|
||||||
|
Navigator.pushNamed(context, PersonBrowser.routeName,
|
||||||
|
arguments: PersonBrowserArguments(widget.account, person));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _transformItems(List<Person> items) {
|
||||||
|
_items = items
|
||||||
|
.sorted((a, b) => a.name.compareTo(b.name))
|
||||||
|
.map((e) => _PersonListItem(
|
||||||
|
account: widget.account,
|
||||||
|
name: e.name,
|
||||||
|
faceUrl: api_util.getFacePreviewUrl(widget.account, e.thumbFaceId,
|
||||||
|
size: k.faceThumbSize),
|
||||||
|
onTap: () => _onItemTap(e),
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _reqQuery() {
|
||||||
|
_bloc.add(ListPersonBlocQuery(widget.account));
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _bloc = ListPersonBloc(KiwiContainer().resolve<DiContainer>());
|
||||||
|
|
||||||
|
var _items = <_ListItem>[];
|
||||||
|
|
||||||
|
static final _log = Logger("widget.people_browser._PeopleBrowserState");
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _ListItem {
|
||||||
|
_ListItem({
|
||||||
|
this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget buildWidget(BuildContext context);
|
||||||
|
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PersonListItem extends _ListItem {
|
||||||
|
_PersonListItem({
|
||||||
|
required this.account,
|
||||||
|
required this.name,
|
||||||
|
required this.faceUrl,
|
||||||
|
VoidCallback? onTap,
|
||||||
|
}) : super(onTap: onTap);
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildWidget(BuildContext context) {
|
||||||
|
final content = Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: _buildFaceImage(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
name + "\n",
|
||||||
|
style: Theme.of(context).textTheme.bodyText1!.copyWith(
|
||||||
|
color: AppTheme.getPrimaryTextColor(context),
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (onTap != null) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: content,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFaceImage(BuildContext context) {
|
||||||
|
Widget cover;
|
||||||
|
try {
|
||||||
|
cover = FittedBox(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
cacheManager: ThumbnailCacheManager.inst,
|
||||||
|
imageUrl: faceUrl!,
|
||||||
|
httpHeaders: {
|
||||||
|
"Authorization": Api.getAuthorizationHeaderValue(account),
|
||||||
|
},
|
||||||
|
fadeInDuration: const Duration(),
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
|
errorWidget: (context, url, error) {
|
||||||
|
// just leave it empty
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
cover = Icon(
|
||||||
|
Icons.person,
|
||||||
|
color: Colors.white.withOpacity(.8),
|
||||||
|
size: 64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(128),
|
||||||
|
child: Container(
|
||||||
|
color: AppTheme.getListItemBackgroundColor(context),
|
||||||
|
constraints: const BoxConstraints.expand(),
|
||||||
|
child: cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Account account;
|
||||||
|
final String name;
|
||||||
|
final String? faceUrl;
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import 'package:nc_photos/pref.dart';
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
import 'package:nc_photos/theme.dart';
|
import 'package:nc_photos/theme.dart';
|
||||||
import 'package:nc_photos/url_launcher_util.dart';
|
import 'package:nc_photos/url_launcher_util.dart';
|
||||||
|
import 'package:nc_photos/widget/people_browser.dart';
|
||||||
import 'package:nc_photos/widget/person_browser.dart';
|
import 'package:nc_photos/widget/person_browser.dart';
|
||||||
|
|
||||||
class SearchLanding extends StatefulWidget {
|
class SearchLanding extends StatefulWidget {
|
||||||
|
@ -110,21 +111,30 @@ class _SearchLandingState extends State<SearchLanding> {
|
||||||
|
|
||||||
List<Widget> _buildPeopleSection(
|
List<Widget> _buildPeopleSection(
|
||||||
BuildContext context, SearchLandingBlocState state) {
|
BuildContext context, SearchLandingBlocState state) {
|
||||||
|
final isNoResult = (state is SearchLandingBlocSuccess ||
|
||||||
|
state is SearchLandingBlocFailure) &&
|
||||||
|
state.persons.isEmpty;
|
||||||
return [
|
return [
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
title: Text(L10n.global().collectionPeopleLabel),
|
title: Text(L10n.global().collectionPeopleLabel),
|
||||||
trailing: IconButton(
|
trailing: isNoResult
|
||||||
onPressed: () {
|
? IconButton(
|
||||||
launch(help_util.peopleUrl);
|
onPressed: () {
|
||||||
},
|
launch(help_util.peopleUrl);
|
||||||
tooltip: L10n.global().helpTooltip,
|
},
|
||||||
icon: const Icon(Icons.help_outline),
|
tooltip: L10n.global().helpTooltip,
|
||||||
),
|
icon: const Icon(Icons.help_outline),
|
||||||
|
)
|
||||||
|
: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pushNamed(PeopleBrowser.routeName,
|
||||||
|
arguments: PeopleBrowserArguments(widget.account));
|
||||||
|
},
|
||||||
|
child: Text(L10n.global().showAllButtonLabel),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if ((state is SearchLandingBlocSuccess ||
|
if (isNoResult)
|
||||||
state is SearchLandingBlocFailure) &&
|
|
||||||
state.persons.isEmpty)
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 48,
|
height: 48,
|
||||||
child: Center(
|
child: Center(
|
||||||
|
|
Loading…
Reference in a new issue