fullscreen: fixed route transition
This commit is contained in:
parent
68766d0e17
commit
aafcc1da63
24 changed files with 186 additions and 175 deletions
|
@ -4,8 +4,8 @@ import 'package:aves/widgets/album/all_collection_drawer.dart';
|
||||||
import 'package:aves/widgets/album/all_collection_page.dart';
|
import 'package:aves/widgets/album/all_collection_page.dart';
|
||||||
import 'package:aves/widgets/common/fake_app_bar.dart';
|
import 'package:aves/widgets/common/fake_app_bar.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:aves/widgets/common/media_store_collection_provider.dart';
|
import 'package:aves/widgets/common/providers/media_store_collection_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:pedantic/pedantic.dart';
|
import 'package:pedantic/pedantic.dart';
|
||||||
|
@ -64,7 +64,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
// TODO reduce permission check time
|
// TODO reduce permission check time
|
||||||
// TODO TLAD ask android.permission.ACCESS_MEDIA_LOCATION (unredacted EXIF with scoped storage)
|
// TODO TLAD ask android.permission.ACCESS_MEDIA_LOCATION (unredacted EXIF with scoped storage)
|
||||||
final permissions = await PermissionHandler().requestPermissions([
|
final permissions = await PermissionHandler().requestPermissions([
|
||||||
PermissionGroup.storage
|
PermissionGroup.storage,
|
||||||
]); // 350ms
|
]); // 350ms
|
||||||
if (permissions[PermissionGroup.storage] != PermissionStatus.granted) {
|
if (permissions[PermissionGroup.storage] != PermissionStatus.granted) {
|
||||||
unawaited(SystemNavigator.pop());
|
unawaited(SystemNavigator.pop());
|
||||||
|
|
|
@ -60,7 +60,7 @@ class ImageCollection with ChangeNotifier {
|
||||||
break;
|
break;
|
||||||
case SortFactor.size:
|
case SortFactor.size:
|
||||||
sections = Map.fromEntries([
|
sections = Map.fromEntries([
|
||||||
MapEntry('All', _rawEntries)
|
MapEntry('All', _rawEntries),
|
||||||
]);
|
]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,7 @@ class ImageEntry {
|
||||||
return {
|
return {
|
||||||
addressDetails.countryName,
|
addressDetails.countryName,
|
||||||
addressDetails.adminArea,
|
addressDetails.adminArea,
|
||||||
addressDetails.locality
|
addressDetails.locality,
|
||||||
}.where((part) => part != null && part.isNotEmpty).join(', ');
|
}.where((part) => part != null && part.isNotEmpty).join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ String _decimal2sexagesimal(final double dec) {
|
||||||
final List<String> tmp = NumberFormat('0.0#####').format(_round(value, decimals: 10)).split('.');
|
final List<String> tmp = NumberFormat('0.0#####').format(_round(value, decimals: 10)).split('.');
|
||||||
return <int>[
|
return <int>[
|
||||||
int.parse(tmp[0]).abs(),
|
int.parse(tmp[0]).abs(),
|
||||||
int.parse(tmp[1])
|
int.parse(tmp[1]),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,6 @@ List<String> toDMS(Tuple2<double, double> latLng) {
|
||||||
final lng = latLng.item2;
|
final lng = latLng.item2;
|
||||||
return [
|
return [
|
||||||
'${_decimal2sexagesimal(lat)} ${lat < 0 ? 'S' : 'N'}',
|
'${_decimal2sexagesimal(lat)} ${lat < 0 ? 'S' : 'N'}',
|
||||||
'${_decimal2sexagesimal(lng)} ${lng < 0 ? 'W' : 'E'}'
|
'${_decimal2sexagesimal(lng)} ${lng < 0 ? 'W' : 'E'}',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,22 +60,22 @@ class AllCollectionDrawer extends StatelessWidget {
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Icon(Icons.photo_library),
|
Icon(Icons.photo_library),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text('${collection.imageCount}')
|
Text('${collection.imageCount}'),
|
||||||
]),
|
]),
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Icon(Icons.video_library),
|
Icon(Icons.video_library),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text('${collection.videoCount}')
|
Text('${collection.videoCount}'),
|
||||||
]),
|
]),
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Icon(Icons.photo_album),
|
Icon(Icons.photo_album),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text('${collection.albumCount}')
|
Text('${collection.albumCount}'),
|
||||||
]),
|
]),
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Icon(Icons.label),
|
Icon(Icons.label),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text('${collection.tagCount}')
|
Text('${collection.tagCount}'),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
121
lib/widgets/album/collection_section.dart
Normal file
121
lib/widgets/album/collection_section.dart
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import 'package:aves/model/image_collection.dart';
|
||||||
|
import 'package:aves/model/image_entry.dart';
|
||||||
|
import 'package:aves/widgets/album/sections.dart';
|
||||||
|
import 'package:aves/widgets/album/thumbnail.dart';
|
||||||
|
import 'package:aves/widgets/album/transparent_material_page_route.dart';
|
||||||
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||||
|
|
||||||
|
class SectionSliver extends StatelessWidget {
|
||||||
|
final ImageCollection collection;
|
||||||
|
final Map<dynamic, List<ImageEntry>> sections;
|
||||||
|
final dynamic sectionKey;
|
||||||
|
final double screenWidth;
|
||||||
|
|
||||||
|
const SectionSliver({
|
||||||
|
Key key,
|
||||||
|
@required this.collection,
|
||||||
|
@required this.sections,
|
||||||
|
@required this.sectionKey,
|
||||||
|
@required this.screenWidth,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
const columnCount = 4;
|
||||||
|
return SliverStickyHeader(
|
||||||
|
header: SectionHeader(
|
||||||
|
collection: collection,
|
||||||
|
sections: sections,
|
||||||
|
sectionKey: sectionKey,
|
||||||
|
),
|
||||||
|
sliver: SliverGrid(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
// TODO TLAD find out why thumbnails are rebuilt (with `initState`) when:
|
||||||
|
// - config change (show/hide status bar)
|
||||||
|
// - navigating away/back
|
||||||
|
(sliverContext, index) {
|
||||||
|
final sectionEntries = sections[sectionKey];
|
||||||
|
if (index >= sectionEntries.length) return null;
|
||||||
|
final entry = sectionEntries[index];
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _showFullscreen(sliverContext, entry),
|
||||||
|
child: Thumbnail(
|
||||||
|
entry: entry,
|
||||||
|
extent: screenWidth / columnCount,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: sections[sectionKey].length,
|
||||||
|
addAutomaticKeepAlives: false,
|
||||||
|
addRepaintBoundaries: true,
|
||||||
|
),
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: columnCount,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
overlapsContent: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showFullscreen(BuildContext context, ImageEntry entry) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
TransparentMaterialPageRoute(
|
||||||
|
pageBuilder: (context, _, __) => FullscreenPage(
|
||||||
|
collection: collection,
|
||||||
|
initialUri: entry.uri,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SectionHeader extends StatelessWidget {
|
||||||
|
final ImageCollection collection;
|
||||||
|
final Map<dynamic, List<ImageEntry>> sections;
|
||||||
|
final dynamic sectionKey;
|
||||||
|
|
||||||
|
const SectionHeader({
|
||||||
|
Key key,
|
||||||
|
@required this.collection,
|
||||||
|
@required this.sections,
|
||||||
|
@required this.sectionKey,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Widget header = const SizedBox.shrink();
|
||||||
|
if (collection.sortFactor == SortFactor.date) {
|
||||||
|
switch (collection.groupFactor) {
|
||||||
|
case GroupFactor.album:
|
||||||
|
Widget albumIcon = IconUtils.getAlbumIcon(context, sectionKey as String);
|
||||||
|
if (albumIcon != null) {
|
||||||
|
albumIcon = Material(
|
||||||
|
type: MaterialType.circle,
|
||||||
|
elevation: 3,
|
||||||
|
color: Colors.transparent,
|
||||||
|
shadowColor: Colors.black,
|
||||||
|
child: albumIcon,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
header = TitleSectionHeader(
|
||||||
|
leading: albumIcon,
|
||||||
|
title: collection.getUniqueAlbumName(sectionKey as String, sections.keys.cast<String>()),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case GroupFactor.month:
|
||||||
|
header = MonthSectionHeader(date: sectionKey as DateTime);
|
||||||
|
break;
|
||||||
|
case GroupFactor.day:
|
||||||
|
header = DaySectionHeader(date: sectionKey as DateTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IgnorePointer(
|
||||||
|
child: header,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/album/thumbnail_collection.dart';
|
import 'package:aves/widgets/album/thumbnail_collection.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class FilteredCollectionPage extends StatelessWidget {
|
class FilteredCollectionPage extends StatelessWidget {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/album/thumbnail_collection.dart';
|
import 'package:aves/widgets/album/thumbnail_collection.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ImageSearchDelegate extends SearchDelegate<ImageEntry> {
|
class ImageSearchDelegate extends SearchDelegate<ImageEntry> {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
import 'package:aves/widgets/common/outlined_text.dart';
|
import 'package:aves/widgets/common/fx/outlined_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/album/sections.dart';
|
import 'package:aves/widgets/album/collection_section.dart';
|
||||||
import 'package:aves/widgets/album/thumbnail.dart';
|
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
|
||||||
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
|
||||||
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ThumbnailCollection extends AnimatedWidget {
|
class ThumbnailCollection extends AnimatedWidget {
|
||||||
|
@ -103,126 +99,3 @@ class ThumbnailCollectionContent extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SectionSliver extends StatelessWidget {
|
|
||||||
final ImageCollection collection;
|
|
||||||
final Map<dynamic, List<ImageEntry>> sections;
|
|
||||||
final dynamic sectionKey;
|
|
||||||
final double screenWidth;
|
|
||||||
|
|
||||||
const SectionSliver({
|
|
||||||
Key key,
|
|
||||||
@required this.collection,
|
|
||||||
@required this.sections,
|
|
||||||
@required this.sectionKey,
|
|
||||||
@required this.screenWidth,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
const columnCount = 4;
|
|
||||||
return SliverStickyHeader(
|
|
||||||
header: SectionHeader(
|
|
||||||
collection: collection,
|
|
||||||
sections: sections,
|
|
||||||
sectionKey: sectionKey,
|
|
||||||
),
|
|
||||||
sliver: SliverGrid(
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
// TODO TLAD find out why thumbnails are rebuilt (with `initState`) when:
|
|
||||||
// - config change (show/hide status bar)
|
|
||||||
// - navigating away/back
|
|
||||||
(sliverContext, index) {
|
|
||||||
final sectionEntries = sections[sectionKey];
|
|
||||||
if (index >= sectionEntries.length) return null;
|
|
||||||
final entry = sectionEntries[index];
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => _showFullscreen(sliverContext, entry),
|
|
||||||
child: Thumbnail(
|
|
||||||
entry: entry,
|
|
||||||
extent: screenWidth / columnCount,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
childCount: sections[sectionKey].length,
|
|
||||||
addAutomaticKeepAlives: false,
|
|
||||||
addRepaintBoundaries: true,
|
|
||||||
),
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: columnCount,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
overlapsContent: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showFullscreen(BuildContext context, ImageEntry entry) {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => FullscreenPage(
|
|
||||||
// collection: collection,
|
|
||||||
// initialUri: entry.uri,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// TODO TLAD consider the following to have transparency while popping fullscreen by drag down
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
PageRouteBuilder(
|
|
||||||
opaque: false,
|
|
||||||
pageBuilder: (BuildContext context, _, __) => FullscreenPage(
|
|
||||||
collection: collection,
|
|
||||||
initialUri: entry.uri,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SectionHeader extends StatelessWidget {
|
|
||||||
final ImageCollection collection;
|
|
||||||
final Map<dynamic, List<ImageEntry>> sections;
|
|
||||||
final dynamic sectionKey;
|
|
||||||
|
|
||||||
const SectionHeader({
|
|
||||||
Key key,
|
|
||||||
@required this.collection,
|
|
||||||
@required this.sections,
|
|
||||||
@required this.sectionKey,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Widget header = const SizedBox.shrink();
|
|
||||||
if (collection.sortFactor == SortFactor.date) {
|
|
||||||
switch (collection.groupFactor) {
|
|
||||||
case GroupFactor.album:
|
|
||||||
Widget albumIcon = IconUtils.getAlbumIcon(context, sectionKey as String);
|
|
||||||
if (albumIcon != null) {
|
|
||||||
albumIcon = Material(
|
|
||||||
type: MaterialType.circle,
|
|
||||||
elevation: 3,
|
|
||||||
color: Colors.transparent,
|
|
||||||
shadowColor: Colors.black,
|
|
||||||
child: albumIcon,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
header = TitleSectionHeader(
|
|
||||||
leading: albumIcon,
|
|
||||||
title: collection.getUniqueAlbumName(sectionKey as String, sections.keys.cast<String>()),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case GroupFactor.month:
|
|
||||||
header = MonthSectionHeader(date: sectionKey as DateTime);
|
|
||||||
break;
|
|
||||||
case GroupFactor.day:
|
|
||||||
header = DaySectionHeader(date: sectionKey as DateTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IgnorePointer(
|
|
||||||
child: header,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
16
lib/widgets/album/transparent_material_page_route.dart
Normal file
16
lib/widgets/album/transparent_material_page_route.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TransparentMaterialPageRoute<T> extends PageRouteBuilder<T> {
|
||||||
|
TransparentMaterialPageRoute({
|
||||||
|
@required RoutePageBuilder pageBuilder,
|
||||||
|
}) : super(pageBuilder: pageBuilder);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get opaque => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
|
||||||
|
final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme;
|
||||||
|
return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child);
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ class ImagePreviewState extends State<ImagePreview> with AfterInitMixin {
|
||||||
super.initState();
|
super.initState();
|
||||||
_entryChangeNotifier = Listenable.merge([
|
_entryChangeNotifier = Listenable.merge([
|
||||||
entry.imageChangeNotifier,
|
entry.imageChangeNotifier,
|
||||||
entry.metadataChangeNotifier
|
entry.metadataChangeNotifier,
|
||||||
]);
|
]);
|
||||||
_entryChangeNotifier.addListener(_onEntryChange);
|
_entryChangeNotifier.addListener(_onEntryChange);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:aves/model/image_metadata.dart';
|
||||||
import 'package:aves/model/metadata_db.dart';
|
import 'package:aves/model/metadata_db.dart';
|
||||||
import 'package:aves/model/settings.dart';
|
import 'package:aves/model/settings.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:aves/widgets/fullscreen/fullscreen_action_delegate.dart';
|
import 'package:aves/widgets/fullscreen/fullscreen_action_delegate.dart';
|
||||||
import 'package:aves/widgets/fullscreen/image_page.dart';
|
import 'package:aves/widgets/fullscreen/image_page.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
||||||
|
@ -298,7 +298,7 @@ class FullscreenVerticalPageView extends StatefulWidget {
|
||||||
|
|
||||||
class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView> {
|
class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView> {
|
||||||
bool _isInitialScale = true;
|
bool _isInitialScale = true;
|
||||||
Color _background = Colors.black;
|
ValueNotifier<Color> _backgroundColorNotifier = ValueNotifier(Colors.black);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -328,24 +328,25 @@ class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onVerticalPageControllerChange() {
|
void _onVerticalPageControllerChange() {
|
||||||
setState(() => _background = _background.withOpacity(min(1.0, widget.verticalPager.page)));
|
_backgroundColorNotifier.value = _backgroundColorNotifier.value.withOpacity(min(1.0, widget.verticalPager.page));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return PageView(
|
return ValueListenableBuilder(
|
||||||
scrollDirection: Axis.vertical,
|
valueListenable: _backgroundColorNotifier,
|
||||||
controller: widget.verticalPager,
|
builder: (context, backgroundColor, child) => Container(
|
||||||
physics: _isInitialScale ? const PageScrollPhysics() : const NeverScrollableScrollPhysics(),
|
color: backgroundColor,
|
||||||
onPageChanged: widget.onVerticalPageChanged,
|
child: child,
|
||||||
children: [
|
),
|
||||||
Container(
|
child: PageView(
|
||||||
color: _background,
|
scrollDirection: Axis.vertical,
|
||||||
child: const SizedBox(),
|
controller: widget.verticalPager,
|
||||||
),
|
physics: _isInitialScale ? const PageScrollPhysics() : const NeverScrollableScrollPhysics(),
|
||||||
Container(
|
onPageChanged: widget.onVerticalPageChanged,
|
||||||
color: _background,
|
children: [
|
||||||
child: ImagePage(
|
const SizedBox(),
|
||||||
|
ImagePage(
|
||||||
collection: widget.collection,
|
collection: widget.collection,
|
||||||
pageController: widget.horizontalPager,
|
pageController: widget.horizontalPager,
|
||||||
onTap: widget.onImageTap,
|
onTap: widget.onImageTap,
|
||||||
|
@ -353,15 +354,15 @@ class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView>
|
||||||
onScaleChanged: (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial),
|
onScaleChanged: (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial),
|
||||||
videoControllers: widget.videoControllers,
|
videoControllers: widget.videoControllers,
|
||||||
),
|
),
|
||||||
),
|
NotificationListener(
|
||||||
NotificationListener(
|
onNotification: (notification) {
|
||||||
onNotification: (notification) {
|
if (notification is BackUpNotification) widget.onImagePageRequested();
|
||||||
if (notification is BackUpNotification) widget.onImagePageRequested();
|
return false;
|
||||||
return false;
|
},
|
||||||
},
|
child: InfoPage(collection: widget.collection, entry: widget.entry),
|
||||||
child: InfoPage(collection: widget.collection, entry: widget.entry),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class BasicSection extends StatelessWidget {
|
||||||
if (rotation != null) InfoRow('Rotation', '$rotation°');
|
if (rotation != null) InfoRow('Rotation', '$rotation°');
|
||||||
return [
|
return [
|
||||||
InfoRow('Duration', entry.durationText),
|
InfoRow('Duration', entry.durationText),
|
||||||
if (rotation != null) InfoRow('Rotation', '$rotation°')
|
if (rotation != null) InfoRow('Rotation', '$rotation°'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/common/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/basic_section.dart';
|
import 'package:aves/widgets/fullscreen/info/basic_section.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/location_section.dart';
|
import 'package:aves/widgets/fullscreen/info/location_section.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/metadata_section.dart';
|
import 'package:aves/widgets/fullscreen/info/metadata_section.dart';
|
||||||
|
|
|
@ -17,7 +17,7 @@ class LocationSection extends AnimatedWidget {
|
||||||
key: key,
|
key: key,
|
||||||
listenable: Listenable.merge([
|
listenable: Listenable.merge([
|
||||||
entry.metadataChangeNotifier,
|
entry.metadataChangeNotifier,
|
||||||
entry.addressChangeNotifier
|
entry.addressChangeNotifier,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:aves/model/image_metadata.dart';
|
||||||
import 'package:aves/model/metadata_service.dart';
|
import 'package:aves/model/metadata_service.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/utils/geo_utils.dart';
|
import 'package:aves/utils/geo_utils.dart';
|
||||||
import 'package:aves/widgets/common/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:aves/widgets/common/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class OverlayButton extends StatelessWidget {
|
class OverlayButton extends StatelessWidget {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/utils/android_app_service.dart';
|
import 'package:aves/utils/android_app_service.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
import 'package:aves/widgets/common/blurred.dart';
|
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||||
import 'package:aves/widgets/fullscreen/overlay/common.dart';
|
import 'package:aves/widgets/fullscreen/overlay/common.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
Loading…
Reference in a new issue