mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Fix face not focused in PeopleBrowser
This commit is contained in:
parent
f66345cded
commit
97d2513ded
7 changed files with 170 additions and 140 deletions
|
@ -1,25 +1,19 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/widget/network_thumbnail.dart';
|
||||
|
||||
class CollectionListSmall extends StatelessWidget {
|
||||
const CollectionListSmall({
|
||||
Key? key,
|
||||
required this.account,
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.coverUrl,
|
||||
required this.fallbackBuilder,
|
||||
required this.child,
|
||||
this.onTap,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
build(BuildContext context) {
|
||||
Widget build(BuildContext context) {
|
||||
Widget content = Stack(
|
||||
children: [
|
||||
SizedBox.expand(
|
||||
child: _buildCoverImage(context),
|
||||
),
|
||||
SizedBox.expand(child: child),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
|
@ -82,27 +76,7 @@ class CollectionListSmall extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildCoverImage(BuildContext context) {
|
||||
Widget buildPlaceholder() => Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: fallbackBuilder(context),
|
||||
);
|
||||
try {
|
||||
return NetworkRectThumbnail(
|
||||
account: account,
|
||||
imageUrl: coverUrl!,
|
||||
errorBuilder: (_) => buildPlaceholder(),
|
||||
);
|
||||
} catch (_) {
|
||||
return FittedBox(
|
||||
child: buildPlaceholder(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final String label;
|
||||
final String? coverUrl;
|
||||
final Widget Function(BuildContext context) fallbackBuilder;
|
||||
final Widget? child;
|
||||
final VoidCallback? onTap;
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ 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/theme.dart';
|
||||
import 'package:nc_photos/widget/collection_browser.dart';
|
||||
import 'package:nc_photos/widget/collection_list_item.dart';
|
||||
import 'package:nc_photos/widget/page_visibility_mixin.dart';
|
||||
import 'package:nc_photos/widget/person_thumbnail.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
|
@ -186,14 +186,16 @@ class _ItemView extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CollectionListSmall(
|
||||
account: account,
|
||||
label: item.name,
|
||||
coverUrl: item.coverUrl,
|
||||
fallbackBuilder: (context) => Icon(
|
||||
Icons.person,
|
||||
color: Theme.of(context).listPlaceholderForegroundColor,
|
||||
),
|
||||
onTap: onTap,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => PersonThumbnail(
|
||||
account: account,
|
||||
coverUrl: item.coverUrl,
|
||||
person: item.person,
|
||||
dimension: constraints.maxWidth,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@ part of '../people_browser.dart';
|
|||
class _Item {
|
||||
_Item(this.person) {
|
||||
try {
|
||||
_coverUrl = person.getCoverUrl(k.coverSize, k.coverSize);
|
||||
_coverUrl = person.getCoverUrl(
|
||||
k.photoLargeSize,
|
||||
k.photoLargeSize,
|
||||
isKeepAspectRatio: true,
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
_log.warning("[_Item] Failed while getCoverUrl", e, stackTrace);
|
||||
}
|
||||
|
|
97
app/lib/widget/person_thumbnail.dart
Normal file
97
app/lib/widget/person_thumbnail.dart
Normal file
|
@ -0,0 +1,97 @@
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/entity/person.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/widget/network_thumbnail.dart';
|
||||
|
||||
class PersonThumbnail extends StatefulWidget {
|
||||
const PersonThumbnail({
|
||||
super.key,
|
||||
required this.dimension,
|
||||
required this.account,
|
||||
required this.coverUrl,
|
||||
required this.person,
|
||||
});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _PersonThumbnailState();
|
||||
|
||||
final double dimension;
|
||||
final Account account;
|
||||
final String? coverUrl;
|
||||
final Person person;
|
||||
}
|
||||
|
||||
class _PersonThumbnailState extends State<PersonThumbnail> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget content;
|
||||
try {
|
||||
var m = Matrix4.identity();
|
||||
if (_layoutSize != null) {
|
||||
final ratio = widget.dimension /
|
||||
math.min(_layoutSize!.width, _layoutSize!.height);
|
||||
final mm = widget.person.getCoverTransform(
|
||||
widget.dimension.toInt(),
|
||||
(_layoutSize!.width * ratio).toInt(),
|
||||
(_layoutSize!.height * ratio).toInt(),
|
||||
);
|
||||
if (mm != null) {
|
||||
m = mm;
|
||||
}
|
||||
}
|
||||
content = Transform(
|
||||
transform: m,
|
||||
child: NetworkRectThumbnail(
|
||||
account: widget.account,
|
||||
imageUrl: widget.coverUrl!,
|
||||
errorBuilder: (_) => const _Placeholder(),
|
||||
onSize: (size) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
_layoutSize = size;
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
if (_layoutSize == null) {
|
||||
content = Opacity(opacity: 0, child: content);
|
||||
}
|
||||
} catch (_) {
|
||||
content = const FittedBox(
|
||||
child: _Placeholder(),
|
||||
);
|
||||
}
|
||||
|
||||
return ClipRRect(
|
||||
child: SizedBox.square(
|
||||
dimension: widget.dimension,
|
||||
child: Container(
|
||||
color: Theme.of(context).listPlaceholderBackgroundColor,
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Size? _layoutSize;
|
||||
}
|
||||
|
||||
class _Placeholder extends StatelessWidget {
|
||||
const _Placeholder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: Theme.of(context).listPlaceholderForegroundColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -243,14 +243,12 @@ class _PlaceItem {
|
|||
});
|
||||
|
||||
Widget buildWidget(BuildContext context) => CollectionListSmall(
|
||||
account: account,
|
||||
label: place,
|
||||
coverUrl: thumbUrl,
|
||||
fallbackBuilder: (context) => Icon(
|
||||
Icons.location_on,
|
||||
color: Theme.of(context).listPlaceholderForegroundColor,
|
||||
),
|
||||
onTap: onTap,
|
||||
child: _PlaceThumbnail(
|
||||
account: account,
|
||||
coverUrl: thumbUrl,
|
||||
),
|
||||
);
|
||||
|
||||
final Account account;
|
||||
|
@ -337,3 +335,43 @@ class _CountryItemView extends StatelessWidget {
|
|||
final String text;
|
||||
final VoidCallback? onTap;
|
||||
}
|
||||
|
||||
class _PlaceThumbnail extends StatelessWidget {
|
||||
const _PlaceThumbnail({
|
||||
required this.account,
|
||||
required this.coverUrl,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
try {
|
||||
return NetworkRectThumbnail(
|
||||
account: account,
|
||||
imageUrl: coverUrl!,
|
||||
errorBuilder: (_) => const _Placeholder(),
|
||||
);
|
||||
} catch (_) {
|
||||
return const FittedBox(
|
||||
child: _Placeholder(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final String? coverUrl;
|
||||
}
|
||||
|
||||
class _Placeholder extends StatelessWidget {
|
||||
const _Placeholder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Icon(
|
||||
Icons.location_on,
|
||||
color: Theme.of(context).listPlaceholderForegroundColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
@ -23,6 +21,7 @@ import 'package:nc_photos/use_case/list_location_group.dart';
|
|||
import 'package:nc_photos/widget/collection_browser.dart';
|
||||
import 'package:nc_photos/widget/network_thumbnail.dart';
|
||||
import 'package:nc_photos/widget/people_browser.dart';
|
||||
import 'package:nc_photos/widget/person_thumbnail.dart';
|
||||
import 'package:nc_photos/widget/places_browser.dart';
|
||||
import 'package:nc_photos/widget/settings/account_settings.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
|
@ -342,11 +341,14 @@ class _LandingPersonWidget extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Center(
|
||||
child: _PersonCoverImage(
|
||||
dimension: 72,
|
||||
account: account,
|
||||
person: person,
|
||||
coverUrl: coverUrl,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(72 / 2),
|
||||
child: PersonThumbnail(
|
||||
dimension: 72,
|
||||
account: account,
|
||||
person: person,
|
||||
coverUrl: coverUrl,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
|
|
@ -1,92 +1,5 @@
|
|||
part of '../search_landing.dart';
|
||||
|
||||
class _PersonCoverPlaceholder extends StatelessWidget {
|
||||
const _PersonCoverPlaceholder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: Theme.of(context).listPlaceholderForegroundColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PersonCoverImage extends StatefulWidget {
|
||||
const _PersonCoverImage({
|
||||
required this.dimension,
|
||||
required this.account,
|
||||
required this.coverUrl,
|
||||
required this.person,
|
||||
});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _PersonCoverImageState();
|
||||
|
||||
final double dimension;
|
||||
final Account account;
|
||||
final String? coverUrl;
|
||||
final Person person;
|
||||
}
|
||||
|
||||
class _PersonCoverImageState extends State<_PersonCoverImage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget cover;
|
||||
try {
|
||||
var m = Matrix4.identity();
|
||||
if (_layoutSize != null) {
|
||||
final ratio = widget.dimension /
|
||||
math.min(_layoutSize!.width, _layoutSize!.height);
|
||||
final mm = widget.person.getCoverTransform(
|
||||
widget.dimension.toInt(),
|
||||
(_layoutSize!.width * ratio).toInt(),
|
||||
(_layoutSize!.height * ratio).toInt(),
|
||||
);
|
||||
if (mm != null) {
|
||||
m = mm;
|
||||
}
|
||||
}
|
||||
cover = Transform(
|
||||
transform: m,
|
||||
child: NetworkRectThumbnail(
|
||||
account: widget.account,
|
||||
imageUrl: widget.coverUrl!,
|
||||
errorBuilder: (_) => const _PersonCoverPlaceholder(),
|
||||
onSize: (size) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
_layoutSize = size;
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
cover = const FittedBox(
|
||||
child: _PersonCoverPlaceholder(),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox.square(
|
||||
dimension: widget.dimension,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(widget.dimension / 2),
|
||||
child: Container(
|
||||
color: Theme.of(context).listPlaceholderBackgroundColor,
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: cover,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Size? _layoutSize;
|
||||
}
|
||||
|
||||
class _LocationCoverPlaceholder extends StatelessWidget {
|
||||
const _LocationCoverPlaceholder();
|
||||
|
||||
|
|
Loading…
Reference in a new issue