💄 Optimize attachment zoom page

This commit is contained in:
LittleSheep 2025-01-19 01:00:00 +08:00
parent 1625a957f8
commit ddc1dc7daf
3 changed files with 205 additions and 188 deletions

View File

@ -17,6 +17,7 @@
android:label="Solian" android:label="Solian"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true"
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -52,5 +52,15 @@ Future<ThemeData> createAppTheme(
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary, foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
), ),
scaffoldBackgroundColor: Colors.transparent, scaffoldBackgroundColor: Colors.transparent,
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
TargetPlatform.iOS: ZoomPageTransitionsBuilder(),
TargetPlatform.macOS: ZoomPageTransitionsBuilder(),
TargetPlatform.fuchsia: ZoomPageTransitionsBuilder(),
TargetPlatform.linux: ZoomPageTransitionsBuilder(),
TargetPlatform.windows: ZoomPageTransitionsBuilder(),
},
),
); );
} }

View File

@ -144,218 +144,224 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
onDismissed: () { onDismissed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
direction: DismissiblePageDismissDirection.down, direction: DismissiblePageDismissDirection.none,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isFullScreen: true, isFullScreen: true,
child: Scaffold( child: GestureDetector(
body: Stack( behavior: HitTestBehavior.translucent,
children: [ child: Scaffold(
Builder(builder: (context) { body: Stack(
if (widget.data.length == 1) { children: [
final heroTag = widget.heroTags?.first ?? uuid.v4(); Builder(builder: (context) {
return Hero( if (widget.data.length == 1) {
tag: 'attachment-${widget.data.first.rid}-$heroTag', final heroTag = widget.heroTags?.first ?? uuid.v4();
child: PhotoView( return Hero(
key: Key('attachment-detail-${widget.data.first.rid}-$heroTag'), tag: 'attachment-${widget.data.first.rid}-$heroTag',
backgroundDecoration: BoxDecoration(color: Colors.transparent), child: PhotoView(
imageProvider: UniversalImage.provider( key: Key('attachment-detail-${widget.data.first.rid}-$heroTag'),
sn.getAttachmentUrl(widget.data.first.rid), backgroundDecoration: BoxDecoration(color: Colors.transparent),
), imageProvider: UniversalImage.provider(
), sn.getAttachmentUrl(widget.data.first.rid),
); ),
}
return PhotoViewGallery.builder(
pageController: _pageController,
scrollPhysics: const BouncingScrollPhysics(),
builder: (context, idx) {
final heroTag = widget.heroTags?.elementAt(idx) ?? uuid.v4();
return PhotoViewGalleryPageOptions(
imageProvider: UniversalImage.provider(
sn.getAttachmentUrl(widget.data.elementAt(idx).rid),
),
heroAttributes: PhotoViewHeroAttributes(
tag: 'attachment-${widget.data.first.rid}-$heroTag',
), ),
); );
}, }
itemCount: widget.data.length,
loadingBuilder: (context, event) => Center( return PhotoViewGallery.builder(
child: SizedBox( pageController: _pageController,
width: 20.0, scrollPhysics: const BouncingScrollPhysics(),
height: 20.0, builder: (context, idx) {
child: CircularProgressIndicator( final heroTag = widget.heroTags?.elementAt(idx) ?? uuid.v4();
value: event == null ? 0 : event.cumulativeBytesLoaded / (event.expectedTotalBytes ?? 1), return PhotoViewGalleryPageOptions(
imageProvider: UniversalImage.provider(
sn.getAttachmentUrl(widget.data.elementAt(idx).rid),
),
heroAttributes: PhotoViewHeroAttributes(
tag: 'attachment-${widget.data.first.rid}-$heroTag',
),
);
},
itemCount: widget.data.length,
loadingBuilder: (context, event) => Center(
child: SizedBox(
width: 20.0,
height: 20.0,
child: CircularProgressIndicator(
value: event == null ? 0 : event.cumulativeBytesLoaded / (event.expectedTotalBytes ?? 1),
),
), ),
), ),
), backgroundDecoration: BoxDecoration(color: Colors.transparent),
backgroundDecoration: BoxDecoration(color: Colors.transparent), );
); }),
}), Align(
Align( alignment: Alignment.bottomCenter,
alignment: Alignment.bottomCenter, child: IgnorePointer(
child: IgnorePointer( child: Container(
child: Container( height: 300,
height: 300, decoration: BoxDecoration(
decoration: BoxDecoration( gradient: LinearGradient(
gradient: LinearGradient( begin: Alignment.bottomCenter,
begin: Alignment.bottomCenter, end: Alignment.topCenter,
end: Alignment.topCenter, colors: [
colors: [ Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surface, Colors.transparent,
Colors.transparent, ],
], ),
), ),
), ),
), ),
), ),
), Positioned(
Positioned( left: 16,
left: 16, right: 16,
right: 16, bottom: 16 + MediaQuery.of(context).padding.bottom,
bottom: 16 + MediaQuery.of(context).padding.bottom, child: Material(
child: Material( color: Colors.transparent,
color: Colors.transparent, child: Builder(builder: (context) {
child: Builder(builder: (context) { final ud = context.read<UserDirectoryProvider>();
final ud = context.read<UserDirectoryProvider>(); final item = widget.data.elementAt(
final item = widget.data.elementAt( widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0,
widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0, );
); final account = ud.getAccountFromCache(item.accountId);
final account = ud.getAccountFromCache(item.accountId);
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (item.accountId > 0) if (item.accountId > 0)
Row( Row(
children: [ children: [
IgnorePointer( IgnorePointer(
child: AccountImage( child: AccountImage(
content: account?.avatar, content: account?.avatar,
radius: 19, radius: 19,
),
),
const Gap(8),
Expanded(
child: IgnorePointer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'attachmentUploadBy'.tr(),
style: Theme.of(context).textTheme.bodySmall,
),
Text(
account?.nick ?? 'unknown'.tr(),
style: Theme.of(context).textTheme.bodyMedium,
),
],
), ),
), ),
), const Gap(8),
if (widget.data.length > 1) Expanded(
IgnorePointer( child: IgnorePointer(
child: Text( child: Column(
'${(_pageController.page?.round() ?? 0) + 1}/${widget.data.length}', crossAxisAlignment: CrossAxisAlignment.start,
style: GoogleFonts.robotoMono(fontSize: 13), children: [
).padding(right: 8), Text(
), 'attachmentUploadBy'.tr(),
InkWell( style: Theme.of(context).textTheme.bodySmall,
borderRadius: const BorderRadius.all(Radius.circular(16)),
onTap: _isDownloading
? null
: () => _saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
child: Container(
padding: const EdgeInsets.all(6),
child: !_isDownloading
? !_isCompletedDownload
? const Icon(Symbols.save_alt)
: const Icon(Symbols.download_done)
: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
value: _progressOfDownload,
strokeWidth: 3,
),
), ),
Text(
account?.nick ?? 'unknown'.tr(),
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
), ),
if (widget.data.length > 1)
IgnorePointer(
child: Text(
'${(_pageController.page?.round() ?? 0) + 1}/${widget.data.length}',
style: GoogleFonts.robotoMono(fontSize: 13),
).padding(right: 8),
),
InkWell(
borderRadius: const BorderRadius.all(Radius.circular(16)),
onTap: _isDownloading
? null
: () => _saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
child: Container(
padding: const EdgeInsets.all(6),
child: !_isDownloading
? !_isCompletedDownload
? const Icon(Symbols.save_alt)
: const Icon(Symbols.download_done)
: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
value: _progressOfDownload,
strokeWidth: 3,
),
),
),
),
],
),
const Gap(4),
IgnorePointer(
child: Text(
item.alt,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
), ),
],
),
const Gap(4),
IgnorePointer(
child: Text(
item.alt,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
), ),
), ),
), const Gap(2),
const Gap(2), IgnorePointer(
IgnorePointer( child: Wrap(
child: Wrap( spacing: 6,
spacing: 6, children: [
children: [ if (item.metadata['exif'] == null)
if (item.metadata['exif'] == null) Text(
'#${item.rid}',
style: metaTextStyle,
),
if (item.metadata['exif']?['Model'] != null)
Text(
'attachmentShotOn'.tr(args: [
item.metadata['exif']?['Model'],
]),
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['ISO'] != null)
Text(
'ISO${item.metadata['exif']?['ISO']}',
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['Aperture'] != null)
Text(
'f/${item.metadata['exif']?['Aperture']}',
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['Megapixels'] != null && item.metadata['exif']?['Model'] != null)
Text(
'${item.metadata['exif']?['Megapixels']}MP',
style: metaTextStyle,
)
else
Text(
item.size.formatBytes(),
style: metaTextStyle,
),
if (item.metadata['width'] != null && item.metadata['height'] != null)
Text(
'${item.metadata['width']}x${item.metadata['height']}',
style: metaTextStyle,
),
if (item.metadata['ratio'] != null)
Text(
(item.metadata['ratio'] as num).toStringAsFixed(2),
style: metaTextStyle,
),
Text( Text(
'#${item.rid}', item.mimetype,
style: metaTextStyle, style: metaTextStyle,
), ),
if (item.metadata['exif']?['Model'] != null) ],
Text( ),
'attachmentShotOn'.tr(args: [
item.metadata['exif']?['Model'],
]),
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['ISO'] != null)
Text(
'ISO${item.metadata['exif']?['ISO']}',
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['Aperture'] != null)
Text(
'f/${item.metadata['exif']?['Aperture']}',
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['Megapixels'] != null && item.metadata['exif']?['Model'] != null)
Text(
'${item.metadata['exif']?['Megapixels']}MP',
style: metaTextStyle,
)
else
Text(
item.size.formatBytes(),
style: metaTextStyle,
),
if (item.metadata['width'] != null && item.metadata['height'] != null)
Text(
'${item.metadata['width']}x${item.metadata['height']}',
style: metaTextStyle,
),
if (item.metadata['ratio'] != null)
Text(
(item.metadata['ratio'] as num).toStringAsFixed(2),
style: metaTextStyle,
),
Text(
item.mimetype,
style: metaTextStyle,
),
],
), ),
), ],
], );
); }),
}), ),
), ),
), ],
], ),
), ),
onTap: () {
Navigator.of(context).pop();
},
), ),
); );
} }