This commit is contained in:
Thibault Deckers 2019-11-20 08:26:18 +09:00
parent 993f189377
commit 6203b98ff4
10 changed files with 100 additions and 30 deletions

View file

@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:screen/screen.dart';
void main() {
// initialize binding/plugins to configure Skia before `runApp`
@ -60,6 +61,7 @@ class _HomePageState extends State<HomePage> {
super.initState();
imageCache.maximumSizeBytes = 100 * 1024 * 1024;
setup();
Screen.keepOn(true);
}
setup() async {

View file

@ -17,6 +17,7 @@ class ImageFileService {
static Future<Uint8List> getImageBytes(ImageEntry entry, int width, int height) async {
if (width > 0 && height > 0) {
// debugPrint('getImageBytes width=$width path=${entry.path}');
try {
final result = await platform.invokeMethod('getImageBytes', <String, dynamic>{
'entry': entry.toMap(),

View file

@ -1,5 +1,8 @@
import 'dart:ui';
import 'package:aves/model/image_collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
final Settings settings = Settings._private();
@ -19,15 +22,35 @@ class Settings {
static const infoMapZoomKey = 'info_map_zoom';
static const catalogTimeZoneKey = 'catalog_time_zone';
// state
static const windowMetricsKey = 'window_metrics';
init() async {
prefs = await SharedPreferences.getInstance();
// TODO TLAD try this as an alternative to MediaQuery, in order to rebuild only on specific property change
// window.onMetricsChanged = onMetricsChanged;
}
void addListener(SettingsCallback listener) => _listeners.add(listener);
WindowMetrics _metrics;
void removeListener(SettingsCallback listener) => _listeners.remove(listener);
onMetricsChanged() {
final newValue = WindowMetrics(
devicePixelRatio: window.devicePixelRatio,
physicalSize: window.physicalSize,
viewInsets: window.viewInsets,
viewPadding: window.viewPadding,
systemGestureInsets: window.systemGestureInsets,
padding: window.padding,
);
notifyListeners(windowMetricsKey, _metrics, newValue);
_metrics = newValue;
}
void notifyListeners(String key, dynamic oldValue, dynamic newValue) {
addListener(SettingsCallback listener) => _listeners.add(listener);
removeListener(SettingsCallback listener) => _listeners.remove(listener);
notifyListeners(String key, dynamic oldValue, dynamic newValue) {
debugPrint('$runtimeType notifyListeners key=$key, old=$oldValue, new=$newValue');
if (_listeners != null) {
final List<SettingsCallback> localListeners = _listeners.toList();
@ -95,3 +118,21 @@ class Settings {
}
}
}
class WindowMetrics {
final double devicePixelRatio;
final Size physicalSize;
final WindowPadding viewInsets;
final WindowPadding viewPadding;
final WindowPadding systemGestureInsets;
final WindowPadding padding;
const WindowMetrics({
this.devicePixelRatio,
this.physicalSize,
this.viewInsets,
this.viewPadding,
this.systemGestureInsets,
this.padding,
});
}

View file

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:aves/model/image_collection.dart';
import 'package:aves/model/image_entry.dart';
import 'package:aves/widgets/album/filtered_collection_page.dart';
@ -16,7 +18,7 @@ class AllCollectionDrawer extends StatelessWidget {
final tags = collection.sortedTags;
return Drawer(
child: ListView(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
padding: EdgeInsets.only(bottom: window.viewInsets.bottom),
children: [
DrawerHeader(
child: SafeArea(

View file

@ -27,15 +27,30 @@ class Thumbnail extends StatelessWidget {
builder: (bytes) {
return Hero(
tag: entry.uri,
child: LayoutBuilder(builder: (context, constraints) {
final dim = min(constraints.maxWidth, constraints.maxHeight);
return Image.memory(
bytes,
width: dim,
height: dim,
fit: BoxFit.cover,
);
}),
flightShuttleBuilder: (
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
// use LayoutBuilder only during hero animation
return LayoutBuilder(builder: (context, constraints) {
final dim = min(constraints.maxWidth, constraints.maxHeight);
return Image.memory(
bytes,
width: dim,
height: dim,
fit: BoxFit.cover,
);
});
},
child: Image.memory(
bytes,
width: extent,
height: extent,
fit: BoxFit.cover,
),
);
},
);

View file

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:aves/model/image_collection.dart';
import 'package:aves/model/image_entry.dart';
import 'package:aves/widgets/album/sections.dart';
@ -23,6 +25,7 @@ class ThumbnailCollection extends AnimatedWidget {
return ThumbnailCollectionContent(
collection: collection,
appBar: appBar,
screenWidth: MediaQuery.of(context).size.width,
);
}
}
@ -30,14 +33,16 @@ class ThumbnailCollection extends AnimatedWidget {
class ThumbnailCollectionContent extends StatelessWidget {
final ImageCollection collection;
final Widget appBar;
final double screenWidth;
final Map<dynamic, List<ImageEntry>> _sections;
final ScrollController _scrollController = ScrollController();
ThumbnailCollectionContent({
Key key,
this.collection,
this.appBar,
@required this.collection,
@required this.appBar,
@required this.screenWidth,
}) : _sections = collection.sections,
super(key: key);
@ -69,6 +74,7 @@ class ThumbnailCollectionContent extends StatelessWidget {
collection: collection,
sections: _sections,
sectionKey: sectionKey,
screenWidth: screenWidth,
);
if (sectionKey == sectionKeys.last) {
sliver = SliverPadding(
@ -94,12 +100,14 @@ 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
@ -113,28 +121,29 @@ class SectionSliver extends StatelessWidget {
),
sliver: SliverGrid(
delegate: SliverChildBuilderDelegate(
// TODO TLAD find out why thumbnails are rebuilt when config change (show/hide status bar)
(sliverContext, index) {
final sectionEntries = sections[sectionKey];
if (index >= sectionEntries.length) return null;
final entry = sectionEntries[index];
final mediaQuery = MediaQuery.of(sliverContext);
return GestureDetector(
onTap: () => _showFullscreen(sliverContext, entry),
child: Thumbnail(
entry: entry,
extent: mediaQuery.size.width / columnCount,
devicePixelRatio: mediaQuery.devicePixelRatio,
extent: screenWidth / columnCount,
devicePixelRatio: window.devicePixelRatio,
),
);
},
childCount: sections[sectionKey].length,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addRepaintBoundaries: true,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columnCount,
),
),
overlapsContent: false,
);
}

View file

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:aves/model/image_entry.dart';
import 'package:aves/utils/android_app_service.dart';
import 'package:aves/utils/android_file_utils.dart';
@ -104,7 +106,7 @@ class IconUtils {
return AppIcon(
packageName: packageName,
size: IconTheme.of(context).size,
devicePixelRatio: MediaQuery.of(context).devicePixelRatio,
devicePixelRatio: window.devicePixelRatio,
);
}
return null;

View file

@ -10,9 +10,9 @@ import 'package:aves/widgets/fullscreen/overlay/bottom.dart';
import 'package:aves/widgets/fullscreen/overlay/top.dart';
import 'package:aves/widgets/fullscreen/overlay/video.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:photo_view/photo_view.dart';
import 'package:screen/screen.dart';
import 'package:tuple/tuple.dart';
import 'package:video_player/video_player.dart';
@ -122,15 +122,13 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
showInfo: () => goToVerticalPage(1),
);
initVideoController();
Screen.keepOn(true);
initOverlay();
}
initOverlay() async {
// wait for MaterialPageRoute.transitionDuration
// to show overlay after hero animation is complete
await Future.delayed(Duration(milliseconds: 300));
await Future.delayed(Duration(milliseconds: (300 * timeDilation).toInt()));
onOverlayVisibleChange();
}
@ -150,7 +148,6 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
goToVerticalPage(0);
return Future.value(false);
}
Screen.keepOn(false);
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
return Future.value(true);
},

View file

@ -1,4 +1,5 @@
import 'dart:math';
import 'dart:ui';
import 'package:aves/model/image_entry.dart';
import 'package:aves/widgets/common/image_preview.dart';
@ -62,7 +63,7 @@ class AvesVideoState extends State<AvesVideo> {
entry: entry,
width: width,
height: width / entry.aspectRatio,
devicePixelRatio: mediaQuery.devicePixelRatio,
devicePixelRatio: window.devicePixelRatio,
builder: (bytes) => Image.memory(bytes),
);
}

View file

@ -100,7 +100,7 @@ packages:
name: flutter_svg
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.3"
version: "0.14.4"
flutter_test:
dependency: "direct dev"
description: flutter
@ -175,7 +175,7 @@ packages:
name: pdf
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.23"
version: "1.3.24"
pedantic:
dependency: transitive
description:
@ -189,7 +189,7 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.0"
version: "4.0.0"
petitparser:
dependency: transitive
description:
@ -203,7 +203,7 @@ packages:
name: photo_view
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0"
version: "0.8.0"
printing:
dependency: "direct main"
description: