mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 15:45:26 +02:00
improvements
This commit is contained in:
parent
83f3ac8674
commit
da2d658557
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:property_change_notifier/property_change_notifier.dart';
|
import 'package:property_change_notifier/property_change_notifier.dart';
|
||||||
|
|
||||||
class MemorySlideController extends PropertyChangeNotifier<String> {
|
class MemorySlideController extends PropertyChangeNotifier<String> {
|
||||||
@ -39,6 +41,11 @@ class MemorySlideController extends PropertyChangeNotifier<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void previous() {
|
||||||
|
_index = max(_index - 1, 0);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
_completed = false;
|
_completed = false;
|
||||||
_paused = false;
|
_paused = false;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:path/path.dart';
|
||||||
import 'package:share_location/enums.dart';
|
import 'package:share_location/enums.dart';
|
||||||
|
|
||||||
class Memory {
|
class Memory {
|
||||||
@ -25,6 +26,8 @@ class Memory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get filename => basename(location);
|
||||||
|
|
||||||
MemoryType get type =>
|
MemoryType get type =>
|
||||||
location.split('.').last == 'jpg' ? MemoryType.photo : MemoryType.video;
|
filename.split('.').last == 'jpg' ? MemoryType.photo : MemoryType.video;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_location/constants/spacing.dart';
|
import 'package:share_location/constants/spacing.dart';
|
||||||
@ -20,6 +21,7 @@ enum MemoryFetchStatus {
|
|||||||
class MemoryView extends StatefulWidget {
|
class MemoryView extends StatefulWidget {
|
||||||
final String location;
|
final String location;
|
||||||
final DateTime creationDate;
|
final DateTime creationDate;
|
||||||
|
final String filename;
|
||||||
final bool loopVideo;
|
final bool loopVideo;
|
||||||
final void Function(VideoPlayerController)? onVideoControllerInitialized;
|
final void Function(VideoPlayerController)? onVideoControllerInitialized;
|
||||||
final VoidCallback? onFileDownloaded;
|
final VoidCallback? onFileDownloaded;
|
||||||
@ -28,6 +30,7 @@ class MemoryView extends StatefulWidget {
|
|||||||
Key? key,
|
Key? key,
|
||||||
required this.location,
|
required this.location,
|
||||||
required this.creationDate,
|
required this.creationDate,
|
||||||
|
required this.filename,
|
||||||
this.loopVideo = false,
|
this.loopVideo = false,
|
||||||
this.onVideoControllerInitialized,
|
this.onVideoControllerInitialized,
|
||||||
this.onFileDownloaded,
|
this.onFileDownloaded,
|
||||||
@ -131,11 +134,30 @@ class _MemoryViewState extends AuthRequiredState<MemoryView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status == MemoryFetchStatus.done) {
|
if (status == MemoryFetchStatus.done) {
|
||||||
return RawMemoryDisplay(
|
return Stack(
|
||||||
|
fit: StackFit.expand,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
if (type == MemoryType.photo)
|
||||||
|
ImageFiltered(
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||||
|
child: RawMemoryDisplay(
|
||||||
|
filename: widget.filename,
|
||||||
data: data!,
|
data: data!,
|
||||||
type: type!,
|
type: type!,
|
||||||
loopVideo: widget.loopVideo,
|
loopVideo: widget.loopVideo,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RawMemoryDisplay(
|
||||||
|
filename: widget.filename,
|
||||||
|
data: data!,
|
||||||
|
type: type!,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
loopVideo: widget.loopVideo,
|
||||||
onVideoControllerInitialized: widget.onVideoControllerInitialized,
|
onVideoControllerInitialized: widget.onVideoControllerInitialized,
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ class _MemorySlideState extends State<MemorySlide>
|
|||||||
child: MemoryView(
|
child: MemoryView(
|
||||||
creationDate: widget.memory.creationDate,
|
creationDate: widget.memory.creationDate,
|
||||||
location: widget.memory.location,
|
location: widget.memory.location,
|
||||||
|
filename: widget.memory.filename,
|
||||||
loopVideo: false,
|
loopVideo: false,
|
||||||
onFileDownloaded: () {
|
onFileDownloaded: () {
|
||||||
if (widget.memory.type == MemoryType.photo) {
|
if (widget.memory.type == MemoryType.photo) {
|
||||||
|
@ -12,12 +12,14 @@ class RawMemoryDisplay extends StatefulWidget {
|
|||||||
final bool loopVideo;
|
final bool loopVideo;
|
||||||
final String? filename;
|
final String? filename;
|
||||||
final void Function(VideoPlayerController)? onVideoControllerInitialized;
|
final void Function(VideoPlayerController)? onVideoControllerInitialized;
|
||||||
|
final BoxFit? fit;
|
||||||
|
|
||||||
const RawMemoryDisplay({
|
const RawMemoryDisplay({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required this.type,
|
required this.type,
|
||||||
this.loopVideo = false,
|
this.loopVideo = false,
|
||||||
|
this.fit = BoxFit.cover,
|
||||||
this.filename,
|
this.filename,
|
||||||
this.onVideoControllerInitialized,
|
this.onVideoControllerInitialized,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@ -41,14 +43,15 @@ class _RawMemoryDisplayState extends State<RawMemoryDisplay> {
|
|||||||
Future<File> createTempVideo() async {
|
Future<File> createTempVideo() async {
|
||||||
final tempDirectory = await getTemporaryDirectory();
|
final tempDirectory = await getTemporaryDirectory();
|
||||||
final path = '${tempDirectory.path}/${widget.filename ?? 'video.mp4'}';
|
final path = '${tempDirectory.path}/${widget.filename ?? 'video.mp4'}';
|
||||||
|
final file = File(path);
|
||||||
|
|
||||||
if (widget.filename != null) {
|
if (await file.exists()) {
|
||||||
// File already exists, so just return the path
|
// File already exists, so just return it
|
||||||
return File(path);
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
// File needs to be created
|
// File needs to be created
|
||||||
final file = await File(path).create();
|
await file.create();
|
||||||
await file.writeAsBytes(widget.data);
|
await file.writeAsBytes(widget.data);
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
@ -82,17 +85,27 @@ class _RawMemoryDisplayState extends State<RawMemoryDisplay> {
|
|||||||
case MemoryType.photo:
|
case MemoryType.photo:
|
||||||
return Image.memory(
|
return Image.memory(
|
||||||
widget.data,
|
widget.data,
|
||||||
fit: BoxFit.cover,
|
fit: widget.fit,
|
||||||
);
|
);
|
||||||
case MemoryType.video:
|
case MemoryType.video:
|
||||||
if (videoController == null) {
|
if (videoController == null) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (widget.fit) {
|
||||||
|
case BoxFit.contain:
|
||||||
|
return Align(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: videoController!.value.aspectRatio,
|
||||||
|
child: VideoPlayer(videoController!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
default:
|
||||||
return AspectRatio(
|
return AspectRatio(
|
||||||
aspectRatio: videoController!.value.aspectRatio,
|
aspectRatio: videoController!.value.aspectRatio,
|
||||||
child: VideoPlayer(videoController!),
|
child: VideoPlayer(videoController!),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw Exception('Unknown memory type: ${widget.type}');
|
throw Exception('Unknown memory type: ${widget.type}');
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,13 @@ import 'package:share_location/controllers/memory_slide_controller.dart';
|
|||||||
import 'package:share_location/foreign_types/memory.dart';
|
import 'package:share_location/foreign_types/memory.dart';
|
||||||
import 'package:share_location/widgets/memory_slide.dart';
|
import 'package:share_location/widgets/memory_slide.dart';
|
||||||
|
|
||||||
class MemoryPage extends StatefulWidget {
|
class TimelinePage extends StatefulWidget {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final List<Memory> memories;
|
final List<Memory> memories;
|
||||||
final VoidCallback onPreviousTimeline;
|
final VoidCallback onPreviousTimeline;
|
||||||
final VoidCallback onNextTimeline;
|
final VoidCallback onNextTimeline;
|
||||||
|
|
||||||
const MemoryPage({
|
const TimelinePage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.date,
|
required this.date,
|
||||||
required this.memories,
|
required this.memories,
|
||||||
@ -20,10 +20,11 @@ class MemoryPage extends StatefulWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MemoryPage> createState() => _MemoryPageState();
|
State<TimelinePage> createState() => _TimelinePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MemoryPageState extends State<MemoryPage> {
|
class _TimelinePageState extends State<TimelinePage> {
|
||||||
|
final pageController = PageController();
|
||||||
late final MemorySlideController controller;
|
late final MemorySlideController controller;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -34,8 +35,11 @@ class _MemoryPageState extends State<MemoryPage> {
|
|||||||
controller.addListener(() {
|
controller.addListener(() {
|
||||||
if (controller.done) {
|
if (controller.done) {
|
||||||
controller.next();
|
controller.next();
|
||||||
// Force UI update
|
|
||||||
setState(() {});
|
pageController.nextPage(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.linearToEaseOut,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, ['done']);
|
}, ['done']);
|
||||||
controller.addListener(() {
|
controller.addListener(() {
|
||||||
@ -61,14 +65,40 @@ class _MemoryPageState extends State<MemoryPage> {
|
|||||||
onTapUp: (_) {
|
onTapUp: (_) {
|
||||||
controller.setPaused(false);
|
controller.setPaused(false);
|
||||||
},
|
},
|
||||||
|
onTapCancel: () {
|
||||||
|
controller.setPaused(false);
|
||||||
|
},
|
||||||
|
onHorizontalDragEnd: (details) {
|
||||||
|
if (details.primaryVelocity! < 0) {
|
||||||
|
controller.next();
|
||||||
|
|
||||||
|
pageController.nextPage(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.linearToEaseOut,
|
||||||
|
);
|
||||||
|
} else if (details.primaryVelocity! > 0) {
|
||||||
|
controller.previous();
|
||||||
|
|
||||||
|
pageController.previousPage(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.linearToEaseOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
child: Stack(
|
child: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
MemorySlide(
|
PageView.builder(
|
||||||
|
controller: pageController,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemBuilder: (_, __) => MemorySlide(
|
||||||
key: Key(controller.index.toString()),
|
key: Key(controller.index.toString()),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
memory: widget.memories[controller.index],
|
memory: widget.memories[controller.index],
|
||||||
),
|
),
|
||||||
|
itemCount: widget.memories.length,
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: LARGE_SPACE, left: MEDIUM_SPACE, right: MEDIUM_SPACE),
|
top: LARGE_SPACE, left: MEDIUM_SPACE, right: MEDIUM_SPACE),
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:share_location/foreign_types/memory.dart';
|
import 'package:share_location/foreign_types/memory.dart';
|
||||||
import 'package:share_location/utils/loadable.dart';
|
import 'package:share_location/utils/loadable.dart';
|
||||||
import 'package:share_location/widgets/memory_page.dart';
|
import 'package:share_location/widgets/timeline_page.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
|
|
||||||
final supabase = Supabase.instance.client;
|
final supabase = Supabase.instance.client;
|
||||||
@ -71,7 +71,7 @@ class _TimelineScrollState extends State<TimelineScroll> with Loadable {
|
|||||||
controller: pageController,
|
controller: pageController,
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
itemCount: timeline.length,
|
itemCount: timeline.length,
|
||||||
itemBuilder: (_, index) => MemoryPage(
|
itemBuilder: (_, index) => TimelinePage(
|
||||||
date: DateTime.parse(timeline.keys.toList()[index]),
|
date: DateTime.parse(timeline.keys.toList()[index]),
|
||||||
memories: timeline.values.toList()[index],
|
memories: timeline.values.toList()[index],
|
||||||
onNextTimeline: () {
|
onNextTimeline: () {
|
||||||
|
@ -311,7 +311,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
@ -44,6 +44,7 @@ dependencies:
|
|||||||
path_provider: ^2.0.11
|
path_provider: ^2.0.11
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
property_change_notifier: ^0.3.0
|
property_change_notifier: ^0.3.0
|
||||||
|
path: ^1.8.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user