mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-03-03 15:26:47 +00:00
parent
849102dd3b
commit
8ecae72d80
15 changed files with 184 additions and 59 deletions
|
|
@ -1,5 +1,11 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.0.86
|
||||||
|
|
||||||
|
- Allows to reopen send images (if send without time limit or enabled auth)
|
||||||
|
- Added support for front camera zoom
|
||||||
|
- Several bug fixes
|
||||||
|
|
||||||
## 0.0.83
|
## 0.0.83
|
||||||
|
|
||||||
- Improved view of the diagnostic log
|
- Improved view of the diagnostic log
|
||||||
|
|
|
||||||
|
|
@ -508,6 +508,12 @@ abstract class AppLocalizations {
|
||||||
/// **'Unpin'**
|
/// **'Unpin'**
|
||||||
String get contextMenuUnpin;
|
String get contextMenuUnpin;
|
||||||
|
|
||||||
|
/// No description provided for @contextMenuViewAgain.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'View again'**
|
||||||
|
String get contextMenuViewAgain;
|
||||||
|
|
||||||
/// No description provided for @mediaViewerAuthReason.
|
/// No description provided for @mediaViewerAuthReason.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -2943,6 +2949,12 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Currently, group size is limited to {size} people!'**
|
/// **'Currently, group size is limited to {size} people!'**
|
||||||
String groupSizeLimitError(Object size);
|
String groupSizeLimitError(Object size);
|
||||||
|
|
||||||
|
/// No description provided for @authRequestReopenImage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'You must authenticate to reopen the image.'**
|
||||||
|
String get authRequestReopenImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get contextMenuUnpin => 'Lösen';
|
String get contextMenuUnpin => 'Lösen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contextMenuViewAgain => 'Nochmal anschauen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get mediaViewerAuthReason =>
|
String get mediaViewerAuthReason =>
|
||||||
'Bitte authentifiziere dich, um diesen twonly zu sehen!';
|
'Bitte authentifiziere dich, um diesen twonly zu sehen!';
|
||||||
|
|
@ -1642,4 +1645,8 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String groupSizeLimitError(Object size) {
|
String groupSizeLimitError(Object size) {
|
||||||
return 'Derzeit ist die Gruppengröße auf $size Personen begrenzt!';
|
return 'Derzeit ist die Gruppengröße auf $size Personen begrenzt!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequestReopenImage =>
|
||||||
|
'Um das Bild erneut zu öffnen, musst du dich authentifizieren.';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get contextMenuUnpin => 'Unpin';
|
String get contextMenuUnpin => 'Unpin';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contextMenuViewAgain => 'View again';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get mediaViewerAuthReason => 'Please authenticate to see this twonly!';
|
String get mediaViewerAuthReason => 'Please authenticate to see this twonly!';
|
||||||
|
|
||||||
|
|
@ -1630,4 +1633,8 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String groupSizeLimitError(Object size) {
|
String groupSizeLimitError(Object size) {
|
||||||
return 'Currently, group size is limited to $size people!';
|
return 'Currently, group size is limited to $size people!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequestReopenImage =>
|
||||||
|
'You must authenticate to reopen the image.';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,9 @@ class AppLocalizationsSv extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get contextMenuUnpin => 'Unpin';
|
String get contextMenuUnpin => 'Unpin';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contextMenuViewAgain => 'View again';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get mediaViewerAuthReason => 'Please authenticate to see this twonly!';
|
String get mediaViewerAuthReason => 'Please authenticate to see this twonly!';
|
||||||
|
|
||||||
|
|
@ -1630,4 +1633,8 @@ class AppLocalizationsSv extends AppLocalizations {
|
||||||
String groupSizeLimitError(Object size) {
|
String groupSizeLimitError(Object size) {
|
||||||
return 'Currently, group size is limited to $size people!';
|
return 'Currently, group size is limited to $size people!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequestReopenImage =>
|
||||||
|
'You must authenticate to reopen the image.';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c1dc14a53ff2854389a50f4aaeb26946ff925367
|
Subproject commit 20f3c2f0a49e4c9be452ecbc84d98054c92974e1
|
||||||
|
|
@ -59,6 +59,7 @@ class MediaFileService {
|
||||||
} else if (service.mediaFile.requiresAuthentication ||
|
} else if (service.mediaFile.requiresAuthentication ||
|
||||||
service.mediaFile.displayLimitInMilliseconds != null) {
|
service.mediaFile.displayLimitInMilliseconds != null) {
|
||||||
// Message was opened by all persons, and they can not reopen the image.
|
// Message was opened by all persons, and they can not reopen the image.
|
||||||
|
// This branch will prevent to reach the next if condition, with would otherwise store the image for two days
|
||||||
// delete = true; // do not overwrite a previous delete = false
|
// delete = true; // do not overwrite a previous delete = false
|
||||||
// this is just to make it easier to understand :)
|
// this is just to make it easier to understand :)
|
||||||
} else if (message.openedAt!
|
} else if (message.openedAt!
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
CameraLensDirection.front;
|
CameraLensDirection.front;
|
||||||
|
|
||||||
Future<void> onPanUpdate(dynamic details) async {
|
Future<void> onPanUpdate(dynamic details) async {
|
||||||
if (isFront || details == null) {
|
if (details == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mc.cameraController == null ||
|
if (mc.cameraController == null ||
|
||||||
|
|
@ -603,9 +603,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
bottomNavigation: Container(),
|
bottomNavigation: Container(),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onPanStart: (details) async {
|
onPanStart: (details) async {
|
||||||
if (isFront) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_basePanY = details.localPosition.dy;
|
_basePanY = details.localPosition.dy;
|
||||||
_baseScaleFactor = mc.selectedCameraDetails.scaleFactor;
|
_baseScaleFactor = mc.selectedCameraDetails.scaleFactor;
|
||||||
|
|
@ -721,12 +718,11 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
children: [
|
children: [
|
||||||
if (mc.cameraController!.value.isInitialized &&
|
if (mc.cameraController!.value.isInitialized &&
|
||||||
mc.selectedCameraDetails.isZoomAble &&
|
mc.selectedCameraDetails.isZoomAble &&
|
||||||
!isFront &&
|
|
||||||
!_isVideoRecording)
|
!_isVideoRecording)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 120,
|
width: 120,
|
||||||
child: CameraZoomButtons(
|
child: CameraZoomButtons(
|
||||||
key: widget.key,
|
key: mc.zoomButtonKey,
|
||||||
scaleFactor: mc.selectedCameraDetails.scaleFactor,
|
scaleFactor: mc.selectedCameraDetails.scaleFactor,
|
||||||
updateScaleFactor: updateScaleFactor,
|
updateScaleFactor: updateScaleFactor,
|
||||||
selectCamera: mc.selectCamera,
|
selectCamera: mc.selectCamera,
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class MainCameraController {
|
||||||
Map<int, ScannedVerifiedContact> contactsVerified = {};
|
Map<int, ScannedVerifiedContact> contactsVerified = {};
|
||||||
Map<int, ScannedNewProfile> scannedNewProfiles = {};
|
Map<int, ScannedNewProfile> scannedNewProfiles = {};
|
||||||
String? scannedUrl;
|
String? scannedUrl;
|
||||||
|
GlobalKey zoomButtonKey = GlobalKey();
|
||||||
|
|
||||||
Future<void> closeCamera() async {
|
Future<void> closeCamera() async {
|
||||||
contactsVerified = {};
|
contactsVerified = {};
|
||||||
|
|
@ -76,6 +77,7 @@ class MainCameraController {
|
||||||
CameraLensDirection.back) {
|
CameraLensDirection.back) {
|
||||||
await cameraController?.startImageStream(_processCameraImage);
|
await cameraController?.startImageStream(_processCameraImage);
|
||||||
}
|
}
|
||||||
|
zoomButtonKey = GlobalKey();
|
||||||
setState();
|
setState();
|
||||||
return cameraController;
|
return cameraController;
|
||||||
}
|
}
|
||||||
|
|
@ -89,10 +91,11 @@ class MainCameraController {
|
||||||
try {
|
try {
|
||||||
await cameraController!.stopImageStream();
|
await cameraController!.stopImageStream();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.warn(e);
|
// Log.warn(e);
|
||||||
}
|
}
|
||||||
await cameraController!.dispose();
|
final tmp = cameraController;
|
||||||
cameraController = null;
|
cameraController = null;
|
||||||
|
await tmp!.dispose();
|
||||||
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false);
|
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'package:clock/clock.dart';
|
||||||
|
import 'package:drift/drift.dart' show Value;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
class SaveToGalleryButton extends StatefulWidget {
|
class SaveToGalleryButton extends StatefulWidget {
|
||||||
const SaveToGalleryButton({
|
const SaveToGalleryButton({
|
||||||
required this.storeImageAsOriginal,
|
|
||||||
required this.isLoading,
|
required this.isLoading,
|
||||||
required this.displayButtonLabel,
|
required this.displayButtonLabel,
|
||||||
required this.mediaService,
|
required this.mediaService,
|
||||||
|
this.storeImageAsOriginal,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final Future<Uint8List?> Function() storeImageAsOriginal;
|
final Future<Uint8List?> Function()? storeImageAsOriginal;
|
||||||
final bool displayButtonLabel;
|
final bool displayButtonLabel;
|
||||||
final MediaFileService mediaService;
|
final MediaFileService mediaService;
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
|
|
@ -44,8 +48,32 @@ class SaveToGalleryButtonState extends State<SaveToGalleryButton> {
|
||||||
_imageSaving = true;
|
_imageSaving = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
await widget.storeImageAsOriginal();
|
if (widget.storeImageAsOriginal != null) {
|
||||||
await widget.mediaService.storeMediaFile();
|
await widget.storeImageAsOriginal!();
|
||||||
|
}
|
||||||
|
|
||||||
|
final newMediaFile = await twonlyDB.mediaFilesDao.insertMedia(
|
||||||
|
MediaFilesCompanion(
|
||||||
|
type: Value(widget.mediaService.mediaFile.type),
|
||||||
|
createdAt: Value(clock.now()),
|
||||||
|
stored: const Value(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newMediaFile != null) {
|
||||||
|
final newService = MediaFileService(newMediaFile);
|
||||||
|
|
||||||
|
if (widget.mediaService.tempPath.existsSync()) {
|
||||||
|
widget.mediaService.tempPath.copySync(
|
||||||
|
newService.tempPath.path,
|
||||||
|
);
|
||||||
|
} else if (widget.mediaService.originalPath.existsSync()) {
|
||||||
|
widget.mediaService.originalPath.copySync(
|
||||||
|
newService.originalPath.path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await newService.storeMediaFile();
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_imageSaved = true;
|
_imageSaved = true;
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,16 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
_wideCameraIndex = index;
|
_wideCameraIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showWideAngleZoom && Platform.isIOS && _wideCameraIndex != null) {
|
final isFront = widget.controller.description.lensDirection ==
|
||||||
|
CameraLensDirection.front;
|
||||||
|
|
||||||
|
if (!showWideAngleZoom &&
|
||||||
|
Platform.isIOS &&
|
||||||
|
_wideCameraIndex != null &&
|
||||||
|
!isFront) {
|
||||||
showWideAngleZoomIOS = true;
|
showWideAngleZoomIOS = true;
|
||||||
|
} else {
|
||||||
|
showWideAngleZoomIOS = false;
|
||||||
}
|
}
|
||||||
if (_isDisposed) return;
|
if (_isDisposed) return;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'package:clock/clock.dart';
|
|
||||||
import 'package:drift/drift.dart' show Value;
|
import 'package:drift/drift.dart' show Value;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
@ -487,20 +486,6 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case the image was already stored, then rename the stored image.
|
|
||||||
if (mediaService.storedPath.existsSync()) {
|
|
||||||
final mediaFile = await twonlyDB.mediaFilesDao.insertMedia(
|
|
||||||
MediaFilesCompanion(
|
|
||||||
type: Value(mediaService.mediaFile.type),
|
|
||||||
createdAt: Value(clock.now()),
|
|
||||||
stored: const Value(true),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (mediaFile != null) {
|
|
||||||
mediaService.storedPath
|
|
||||||
.renameSync(MediaFileService(mediaFile).storedPath.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,7 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
||||||
group: widget.group,
|
group: widget.group,
|
||||||
onResponseTriggered: widget.onResponseTriggered!,
|
onResponseTriggered: widget.onResponseTriggered!,
|
||||||
galleryItems: widget.galleryItems,
|
galleryItems: widget.galleryItems,
|
||||||
|
mediaFileService: mediaService,
|
||||||
child: Container(
|
child: Container(
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,14 @@ import 'package:twonly/src/model/memory_item.model.dart';
|
||||||
import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dart'
|
import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dart'
|
||||||
as pb;
|
as pb;
|
||||||
import 'package:twonly/src/services/api/messages.dart';
|
import 'package:twonly/src/services/api/messages.dart';
|
||||||
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
|
import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
|
||||||
import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart';
|
import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart';
|
||||||
import 'package:twonly/src/views/chats/message_info.view.dart';
|
import 'package:twonly/src/views/chats/message_info.view.dart';
|
||||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||||
import 'package:twonly/src/views/components/context_menu.component.dart';
|
import 'package:twonly/src/views/components/context_menu.component.dart';
|
||||||
|
import 'package:twonly/src/views/memories/memories_photo_slider.view.dart';
|
||||||
|
|
||||||
class MessageContextMenu extends StatelessWidget {
|
class MessageContextMenu extends StatelessWidget {
|
||||||
const MessageContextMenu({
|
const MessageContextMenu({
|
||||||
|
|
@ -26,16 +28,55 @@ class MessageContextMenu extends StatelessWidget {
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.onResponseTriggered,
|
required this.onResponseTriggered,
|
||||||
required this.galleryItems,
|
required this.galleryItems,
|
||||||
|
required this.mediaFileService,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final Group group;
|
final Group group;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Message message;
|
final Message message;
|
||||||
final List<MemoryItem> galleryItems;
|
final List<MemoryItem> galleryItems;
|
||||||
|
final MediaFileService? mediaFileService;
|
||||||
final VoidCallback onResponseTriggered;
|
final VoidCallback onResponseTriggered;
|
||||||
|
|
||||||
|
Future<void> reopenMediaFile(BuildContext context) async {
|
||||||
|
final isAuth = await authenticateUser(
|
||||||
|
context.lang.authRequestReopenImage,
|
||||||
|
force: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isAuth && context.mounted && mediaFileService != null) {
|
||||||
|
final galleryItems = [
|
||||||
|
MemoryItem(mediaService: mediaFileService!, messages: []),
|
||||||
|
];
|
||||||
|
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
PageRouteBuilder(
|
||||||
|
opaque: false,
|
||||||
|
pageBuilder: (context, a1, a2) => MemoriesPhotoSliderView(
|
||||||
|
galleryItems: galleryItems,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var canBeOpenedAgain = false;
|
||||||
|
// in case this is a media send from this user...
|
||||||
|
if (mediaFileService != null && message.senderId == null) {
|
||||||
|
// and the media was send with unlimited display limit time and without auth required...
|
||||||
|
if (!mediaFileService!.mediaFile.requiresAuthentication &&
|
||||||
|
mediaFileService!.mediaFile.displayLimitInMilliseconds == null) {
|
||||||
|
// and the temp media file still exists
|
||||||
|
if (mediaFileService!.tempPath.existsSync()) {
|
||||||
|
// the media file can be opened again...
|
||||||
|
canBeOpenedAgain = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ContextMenu(
|
return ContextMenu(
|
||||||
items: [
|
items: [
|
||||||
if (!message.isDeletedFromSender)
|
if (!message.isDeletedFromSender)
|
||||||
|
|
@ -70,6 +111,12 @@ class MessageContextMenu extends StatelessWidget {
|
||||||
},
|
},
|
||||||
icon: FontAwesomeIcons.faceLaugh,
|
icon: FontAwesomeIcons.faceLaugh,
|
||||||
),
|
),
|
||||||
|
if (canBeOpenedAgain)
|
||||||
|
ContextMenuItem(
|
||||||
|
title: context.lang.contextMenuViewAgain,
|
||||||
|
onTap: () => reopenMediaFile(context),
|
||||||
|
icon: FontAwesomeIcons.clockRotateLeft,
|
||||||
|
),
|
||||||
if (!message.isDeletedFromSender)
|
if (!message.isDeletedFromSender)
|
||||||
ContextMenuItem(
|
ContextMenuItem(
|
||||||
title: context.lang.reply,
|
title: context.lang.reply,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:twonly/src/model/memory_item.model.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/views/camera/camera_preview_components/save_to_gallery.dart';
|
||||||
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
||||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||||
import 'package:twonly/src/views/components/media_view_sizing.dart';
|
import 'package:twonly/src/views/components/media_view_sizing.dart';
|
||||||
|
|
@ -92,8 +93,36 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> shareMediaFile() async {
|
||||||
|
final orgMediaService = widget.galleryItems[currentIndex].mediaService;
|
||||||
|
|
||||||
|
final newMediaService = await initializeMediaUpload(
|
||||||
|
orgMediaService.mediaFile.type,
|
||||||
|
gUser.defaultShowTime,
|
||||||
|
);
|
||||||
|
if (newMediaService == null) {
|
||||||
|
Log.error('Could not create new mediaFIle');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
orgMediaService.storedPath.copySync(newMediaService.originalPath.path);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ShareImageEditorView(
|
||||||
|
mediaFileService: newMediaService,
|
||||||
|
sharedFromGallery: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final orgMediaService = widget.galleryItems[currentIndex].mediaService;
|
||||||
return Dismissible(
|
return Dismissible(
|
||||||
key: key,
|
key: key,
|
||||||
direction: DismissDirection.vertical,
|
direction: DismissDirection.vertical,
|
||||||
|
|
@ -117,36 +146,18 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
if (!orgMediaService.storedPath.existsSync())
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 12),
|
||||||
|
child: SaveToGalleryButton(
|
||||||
|
isLoading: false,
|
||||||
|
displayButtonLabel: true,
|
||||||
|
mediaService: orgMediaService,
|
||||||
|
),
|
||||||
|
),
|
||||||
FilledButton.icon(
|
FilledButton.icon(
|
||||||
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
onPressed: () async {
|
onPressed: shareMediaFile,
|
||||||
final orgMediaService =
|
|
||||||
widget.galleryItems[currentIndex].mediaService;
|
|
||||||
|
|
||||||
final newMediaService = await initializeMediaUpload(
|
|
||||||
orgMediaService.mediaFile.type,
|
|
||||||
gUser.defaultShowTime,
|
|
||||||
);
|
|
||||||
if (newMediaService == null) {
|
|
||||||
Log.error('Could not create new mediaFIle');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
orgMediaService.storedPath
|
|
||||||
.copySync(newMediaService.originalPath.path);
|
|
||||||
|
|
||||||
if (!context.mounted) return;
|
|
||||||
|
|
||||||
await Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => ShareImageEditorView(
|
|
||||||
mediaFileService: newMediaService,
|
|
||||||
sharedFromGallery: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all<EdgeInsets>(
|
padding: WidgetStateProperty.all<EdgeInsets>(
|
||||||
const EdgeInsets.symmetric(
|
const EdgeInsets.symmetric(
|
||||||
|
|
@ -217,10 +228,16 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
|
||||||
|
|
||||||
PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
|
PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
|
||||||
final item = widget.galleryItems[index];
|
final item = widget.galleryItems[index];
|
||||||
|
|
||||||
|
var filePath = item.mediaService.storedPath;
|
||||||
|
if (!filePath.existsSync()) {
|
||||||
|
filePath = item.mediaService.tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
return item.mediaService.mediaFile.type == MediaType.video
|
return item.mediaService.mediaFile.type == MediaType.video
|
||||||
? PhotoViewGalleryPageOptions.customChild(
|
? PhotoViewGalleryPageOptions.customChild(
|
||||||
child: VideoPlayerWrapper(
|
child: VideoPlayerWrapper(
|
||||||
videoPath: item.mediaService.storedPath,
|
videoPath: filePath,
|
||||||
),
|
),
|
||||||
// childSize: const Size(300, 300),
|
// childSize: const Size(300, 300),
|
||||||
initialScale: PhotoViewComputedScale.contained,
|
initialScale: PhotoViewComputedScale.contained,
|
||||||
|
|
@ -231,7 +248,7 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: PhotoViewGalleryPageOptions(
|
: PhotoViewGalleryPageOptions(
|
||||||
imageProvider: FileImage(item.mediaService.storedPath),
|
imageProvider: FileImage(filePath),
|
||||||
initialScale: PhotoViewComputedScale.contained,
|
initialScale: PhotoViewComputedScale.contained,
|
||||||
minScale: PhotoViewComputedScale.contained,
|
minScale: PhotoViewComputedScale.contained,
|
||||||
maxScale: PhotoViewComputedScale.covered * 4.1,
|
maxScale: PhotoViewComputedScale.covered * 4.1,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue