|
@@ -1,10 +1,11 @@
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
-import 'package:flutter_swiper/flutter_swiper.dart';
|
|
|
|
import 'package:photos/memories_service.dart';
|
|
import 'package:photos/memories_service.dart';
|
|
|
|
+import 'package:photos/models/file.dart';
|
|
import 'package:photos/models/file_type.dart';
|
|
import 'package:photos/models/file_type.dart';
|
|
import 'package:photos/models/memory.dart';
|
|
import 'package:photos/models/memory.dart';
|
|
import 'package:photos/ui/blurred_file_backdrop.dart';
|
|
import 'package:photos/ui/blurred_file_backdrop.dart';
|
|
|
|
+import 'package:photos/ui/extents_page_view.dart';
|
|
import 'package:photos/ui/thumbnail_widget.dart';
|
|
import 'package:photos/ui/thumbnail_widget.dart';
|
|
import 'package:photos/ui/video_widget.dart';
|
|
import 'package:photos/ui/video_widget.dart';
|
|
import 'package:photos/ui/zoomable_image.dart';
|
|
import 'package:photos/ui/zoomable_image.dart';
|
|
@@ -189,6 +190,7 @@ class FullScreenMemory extends StatefulWidget {
|
|
class _FullScreenMemoryState extends State<FullScreenMemory> {
|
|
class _FullScreenMemoryState extends State<FullScreenMemory> {
|
|
int _index = 0;
|
|
int _index = 0;
|
|
double _opacity = 1;
|
|
double _opacity = 1;
|
|
|
|
+ PageController _pageController;
|
|
|
|
|
|
@override
|
|
@override
|
|
void initState() {
|
|
void initState() {
|
|
@@ -206,17 +208,18 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
|
|
|
|
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
|
|
+ final file = widget.memories[_index].file;
|
|
return Scaffold(
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
appBar: AppBar(
|
|
- title: Text(getFormattedDate(DateTime.fromMicrosecondsSinceEpoch(
|
|
|
|
- widget.memories[_index].file.creationTime))),
|
|
|
|
|
|
+ title: Text(getFormattedDate(
|
|
|
|
+ DateTime.fromMicrosecondsSinceEpoch(file.creationTime))),
|
|
backgroundColor: Color(0x00000000),
|
|
backgroundColor: Color(0x00000000),
|
|
elevation: 0,
|
|
elevation: 0,
|
|
actions: [
|
|
actions: [
|
|
IconButton(
|
|
IconButton(
|
|
icon: Icon(Icons.share),
|
|
icon: Icon(Icons.share),
|
|
onPressed: () {
|
|
onPressed: () {
|
|
- share(context, widget.memories[_index].file);
|
|
|
|
|
|
+ share(context, file);
|
|
},
|
|
},
|
|
),
|
|
),
|
|
],
|
|
],
|
|
@@ -225,78 +228,101 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
|
|
body: Container(
|
|
body: Container(
|
|
color: Colors.black,
|
|
color: Colors.black,
|
|
child: Stack(children: [
|
|
child: Stack(children: [
|
|
|
|
+ BlurredFileBackdrop(file),
|
|
_buildSwiper(),
|
|
_buildSwiper(),
|
|
- Hero(
|
|
|
|
- tag: widget.title,
|
|
|
|
- child: Container(
|
|
|
|
- alignment: Alignment.bottomCenter,
|
|
|
|
- padding: EdgeInsets.fromLTRB(0, 0, 0, 160),
|
|
|
|
- child: AnimatedOpacity(
|
|
|
|
- opacity: _opacity,
|
|
|
|
- duration: Duration(milliseconds: 500),
|
|
|
|
- child: Material(
|
|
|
|
- type: MaterialType.transparency,
|
|
|
|
- child: Text(
|
|
|
|
- widget.title,
|
|
|
|
- style: TextStyle(
|
|
|
|
- fontSize: 40,
|
|
|
|
- fontWeight: FontWeight.bold,
|
|
|
|
- decoration: TextDecoration.none),
|
|
|
|
- ),
|
|
|
|
- ),
|
|
|
|
- ),
|
|
|
|
|
|
+ _buildTitleText(),
|
|
|
|
+ _buildIndexText(),
|
|
|
|
+ ]),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Hero _buildTitleText() {
|
|
|
|
+ return Hero(
|
|
|
|
+ tag: widget.title,
|
|
|
|
+ child: Container(
|
|
|
|
+ alignment: Alignment.bottomCenter,
|
|
|
|
+ padding: EdgeInsets.fromLTRB(0, 0, 0, 160),
|
|
|
|
+ child: AnimatedOpacity(
|
|
|
|
+ opacity: _opacity,
|
|
|
|
+ duration: Duration(milliseconds: 500),
|
|
|
|
+ child: Material(
|
|
|
|
+ type: MaterialType.transparency,
|
|
|
|
+ child: Text(
|
|
|
|
+ widget.title,
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 40,
|
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
|
+ decoration: TextDecoration.none),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
- ]),
|
|
|
|
|
|
+ ),
|
|
),
|
|
),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
- Swiper _buildSwiper() {
|
|
|
|
- return Swiper(
|
|
|
|
|
|
+ Widget _buildIndexText() {
|
|
|
|
+ return Container(
|
|
|
|
+ alignment: Alignment.bottomCenter,
|
|
|
|
+ padding: EdgeInsets.fromLTRB(0, 0, 0, 20),
|
|
|
|
+ child: Text(
|
|
|
|
+ (_index + 1).toString() + " / " + widget.memories.length.toString(),
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 24,
|
|
|
|
+ decoration: TextDecoration.none,
|
|
|
|
+ color: Colors.white60,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Widget _buildSwiper() {
|
|
|
|
+ _pageController = PageController(initialPage: _index);
|
|
|
|
+ return ExtentsPageView.extents(
|
|
itemBuilder: (BuildContext context, int index) {
|
|
itemBuilder: (BuildContext context, int index) {
|
|
|
|
+ if (index < widget.memories.length - 1) {
|
|
|
|
+ final nextFile = widget.memories[index + 1].file;
|
|
|
|
+ preloadLocalFileThumbnail(nextFile);
|
|
|
|
+ }
|
|
final file = widget.memories[index].file;
|
|
final file = widget.memories[index].file;
|
|
- final view = file.fileType == FileType.image
|
|
|
|
- ? ZoomableImage(
|
|
|
|
- file,
|
|
|
|
- tagPrefix: "memories",
|
|
|
|
- backgroundDecoration: BoxDecoration(
|
|
|
|
- color: Colors.transparent,
|
|
|
|
- ),
|
|
|
|
- )
|
|
|
|
- : VideoWidget(
|
|
|
|
- file,
|
|
|
|
- tagPrefix: "memories",
|
|
|
|
- autoPlay: true,
|
|
|
|
- );
|
|
|
|
- return Stack(children: [
|
|
|
|
- BlurredFileBackdrop(file),
|
|
|
|
- view,
|
|
|
|
- ]);
|
|
|
|
|
|
+ return MemoryItem(file);
|
|
},
|
|
},
|
|
itemCount: widget.memories.length,
|
|
itemCount: widget.memories.length,
|
|
- pagination: SwiperPagination(
|
|
|
|
- alignment: Alignment.bottomCenter,
|
|
|
|
- margin: EdgeInsets.all(36),
|
|
|
|
- builder: FractionPaginationBuilder(
|
|
|
|
- activeColor: Colors.white,
|
|
|
|
- color: Colors.grey,
|
|
|
|
- )),
|
|
|
|
- loop: false,
|
|
|
|
- control: SwiperControl(
|
|
|
|
- color: _opacity == 1 ? Colors.white54 : Colors.transparent,
|
|
|
|
- ),
|
|
|
|
- index: _index,
|
|
|
|
- onIndexChanged: (index) async {
|
|
|
|
|
|
+ controller: _pageController,
|
|
|
|
+ extents: 2,
|
|
|
|
+ onPageChanged: (index) async {
|
|
await MemoriesService.instance.markMemoryAsSeen(widget.memories[index]);
|
|
await MemoriesService.instance.markMemoryAsSeen(widget.memories[index]);
|
|
setState(() {
|
|
setState(() {
|
|
_index = index;
|
|
_index = index;
|
|
});
|
|
});
|
|
- if (index < widget.memories.length - 1) {
|
|
|
|
- preloadFile(widget.memories[index + 1].file);
|
|
|
|
- }
|
|
|
|
return index;
|
|
return index;
|
|
},
|
|
},
|
|
);
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+class MemoryItem extends StatelessWidget {
|
|
|
|
+ final File file;
|
|
|
|
+ const MemoryItem(this.file, {Key key}) : super(key: key);
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ Widget build(BuildContext context) {
|
|
|
|
+ final view = file.fileType == FileType.image
|
|
|
|
+ ? ZoomableImage(
|
|
|
|
+ file,
|
|
|
|
+ tagPrefix: "memories",
|
|
|
|
+ backgroundDecoration: BoxDecoration(
|
|
|
|
+ color: Colors.transparent,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ : VideoWidget(
|
|
|
|
+ file,
|
|
|
|
+ tagPrefix: "memories",
|
|
|
|
+ autoPlay: false,
|
|
|
|
+ );
|
|
|
|
+ return Stack(children: [
|
|
|
|
+ // BlurredFileBackdrop(file),
|
|
|
|
+ view,
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+}
|