diff --git a/CHANGELOG.md b/CHANGELOG.md
index 580246a1..b4d58459 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog
-## 0.2.17
+## 0.2.18
- New: Adds an "Ask a Friend" button to new contact suggestions.
- New: Adds security profiles.
@@ -10,6 +10,7 @@
- Fix: Issue with receiving messages when user closed app while decrypting
- Fix: Background message fetching reliability.
- Fix: Issue with focus changing when taking a picture
+- Fix: Issues with the camera initialization
## 0.2.16
diff --git a/fastlane/Appfile b/fastlane/Appfile
new file mode 100644
index 00000000..0df77ab7
--- /dev/null
+++ b/fastlane/Appfile
@@ -0,0 +1,2 @@
+json_key_file(ENV["GOOGLE_PLAY_JSON_KEY_PATH"] || "../../local_data/accesskeys/upload_track_releases_google_play.json")
+package_name("eu.twonly") # Your application ID
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 00000000..966178d2
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,15 @@
+default_platform(:android)
+
+platform :android do
+ desc "Submit a new App Bundle to the Google Play Internal Track"
+ lane :internal do
+ # This lane assumes that `flutter build appbundle` has already been run from the flutter root.
+ upload_to_play_store(
+ track: 'internal',
+ aab: 'build/app/outputs/bundle/release/app-release.aab',
+ skip_upload_metadata: true,
+ skip_upload_images: true,
+ skip_upload_screenshots: true
+ )
+ end
+end
diff --git a/fastlane/README.md b/fastlane/README.md
new file mode 100644
index 00000000..54009708
--- /dev/null
+++ b/fastlane/README.md
@@ -0,0 +1,32 @@
+fastlane documentation
+----
+
+# Installation
+
+Make sure you have the latest version of the Xcode command line tools installed:
+
+```sh
+xcode-select --install
+```
+
+For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
+
+# Available Actions
+
+## Android
+
+### android internal
+
+```sh
+[bundle exec] fastlane android internal
+```
+
+Submit a new App Bundle to the Google Play Internal Track
+
+----
+
+This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
+
+More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
+
+The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
diff --git a/fastlane/report.xml b/fastlane/report.xml
new file mode 100644
index 00000000..388ef818
--- /dev/null
+++ b/fastlane/report.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/globals.dart b/lib/globals.dart
index 90bc7deb..35de1911 100644
--- a/lib/globals.dart
+++ b/lib/globals.dart
@@ -33,4 +33,5 @@ class AppState {
static bool allowErrorTrackingViaSentry = false;
static bool gotMessageFromServer = false;
static int latestAppVersionId = 116;
+ static bool hasCameraPermissions = false;
}
diff --git a/lib/src/visual/helpers/screenshot.helper.dart b/lib/src/visual/helpers/screenshot.helper.dart
index 02c906d9..8605a38e 100644
--- a/lib/src/visual/helpers/screenshot.helper.dart
+++ b/lib/src/visual/helpers/screenshot.helper.dart
@@ -46,24 +46,43 @@ class ScreenshotController {
}
late GlobalKey _containerKey;
- Future capture({double? pixelRatio}) async {
+ Future capture({
+ double? pixelRatio,
+ int retries = 20,
+ }) async {
try {
final findRenderObject = _containerKey.currentContext?.findRenderObject();
if (findRenderObject == null) {
return null;
}
final boundary = findRenderObject as RenderRepaintBoundary;
+
final context = _containerKey.currentContext;
var tmpPixelRatio = pixelRatio;
if (tmpPixelRatio == null) {
if (context != null && context.mounted) {
- tmpPixelRatio =
- tmpPixelRatio ?? MediaQuery.of(context).devicePixelRatio;
+ tmpPixelRatio = tmpPixelRatio ?? MediaQuery.of(context).devicePixelRatio;
}
}
final image = await boundary.toImage(pixelRatio: tmpPixelRatio ?? 1);
return ScreenshotImageHelper(image: image);
} catch (e) {
+ if (retries > 0) {
+ final completer = Completer();
+ WidgetsBinding.instance.addPostFrameCallback((_) async {
+ final result = await capture(
+ pixelRatio: pixelRatio,
+ retries: retries - 1,
+ );
+ completer.complete(result);
+ });
+ Timer(const Duration(milliseconds: 50), () {
+ if (!completer.isCompleted) {
+ WidgetsBinding.instance.scheduleFrame();
+ }
+ });
+ return completer.future;
+ }
Log.error(e);
}
return null;
diff --git a/lib/src/visual/views/camera/add_new_shortcut.view.dart b/lib/src/visual/views/camera/add_new_shortcut.view.dart
index 11a611e4..41291ace 100644
--- a/lib/src/visual/views/camera/add_new_shortcut.view.dart
+++ b/lib/src/visual/views/camera/add_new_shortcut.view.dart
@@ -203,6 +203,7 @@ class _StartNewChatView extends State {
const SizedBox(width: 8),
],
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: FilledButton.icon(
onPressed: (_selectedGroups.isEmpty || shortcutEmoji == null)
? null
diff --git a/lib/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart b/lib/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart
index 2ccec5ac..1a3e52a3 100644
--- a/lib/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart
+++ b/lib/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart
@@ -48,7 +48,7 @@ class SelectedCameraDetails {
bool cameraLoaded = false;
}
-class CameraPreviewControllerView extends StatelessWidget {
+class CameraPreviewControllerView extends StatefulWidget {
const CameraPreviewControllerView({
required this.mainController,
required this.isVisible,
@@ -62,23 +62,52 @@ class CameraPreviewControllerView extends StatelessWidget {
final bool isVisible;
final bool hideControllers;
+ @override
+ State createState() => _CameraPreviewControllerViewState();
+}
+
+class _CameraPreviewControllerViewState extends State {
+ Future? _permissionsFuture;
+
+ @override
+ void initState() {
+ super.initState();
+ if (!AppState.hasCameraPermissions) {
+ _permissionsFuture = checkPermissions().then((hasPermission) {
+ if (hasPermission) {
+ AppState.hasCameraPermissions = true;
+ }
+ return hasPermission;
+ });
+ }
+ }
+
@override
Widget build(BuildContext context) {
- return FutureBuilder(
- future: checkPermissions(),
+ if (AppState.hasCameraPermissions) {
+ return CameraPreviewView(
+ sendToGroup: widget.sendToGroup,
+ mainCameraController: widget.mainController,
+ isVisible: widget.isVisible,
+ hideControllers: widget.hideControllers,
+ );
+ }
+
+ return FutureBuilder(
+ future: _permissionsFuture,
builder: (context, snap) {
if (snap.hasData) {
if (snap.data!) {
return CameraPreviewView(
- sendToGroup: sendToGroup,
- mainCameraController: mainController,
- isVisible: isVisible,
- hideControllers: hideControllers,
+ sendToGroup: widget.sendToGroup,
+ mainCameraController: widget.mainController,
+ isVisible: widget.isVisible,
+ hideControllers: widget.hideControllers,
);
} else {
return PermissionHandlerView(
onSuccess: () {
- mainController.selectCamera(0, true);
+ widget.mainController.selectCamera(0, true);
},
);
}
@@ -210,8 +239,7 @@ class _CameraPreviewViewState extends State {
Future initAsync() async {
_hasAudioPermission = await Permission.microphone.isGranted;
- if (!_hasAudioPermission &&
- !userService.currentUser.requestedAudioPermission) {
+ if (!_hasAudioPermission && !userService.currentUser.requestedAudioPermission) {
await UserService.update((u) => u.requestedAudioPermission = true);
await requestMicrophonePermission();
}
@@ -232,8 +260,7 @@ class _CameraPreviewViewState extends State {
}
Future updateScaleFactor(double newScale) async {
- if (mc.selectedCameraDetails.scaleFactor == newScale ||
- mc.cameraController == null) {
+ if (mc.selectedCameraDetails.scaleFactor == newScale || mc.cameraController == null) {
return;
}
await mc.cameraController?.setZoomLevel(
@@ -316,9 +343,7 @@ class _CameraPreviewViewState extends State {
bool sharedFromGallery = false,
MediaType? mediaType,
}) async {
- final type =
- mediaType ??
- ((videoFilePath != null) ? MediaType.video : MediaType.image);
+ final type = mediaType ?? ((videoFilePath != null) ? MediaType.video : MediaType.image);
final mediaFileService = await initializeMediaUpload(
type,
userService.currentUser.defaultShowTime,
@@ -359,10 +384,9 @@ class _CameraPreviewViewState extends State {
mainCameraController: mc,
previewLink: mc.sharedLinkForPreview,
),
- transitionsBuilder:
- (context, animation, secondaryAnimation, child) {
- return child;
- },
+ transitionsBuilder: (context, animation, secondaryAnimation, child) {
+ return child;
+ },
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
),
@@ -392,16 +416,13 @@ class _CameraPreviewViewState extends State {
return false;
}
- bool get isFront =>
- mc.cameraController?.description.lensDirection ==
- CameraLensDirection.front;
+ bool get isFront => mc.cameraController?.description.lensDirection == CameraLensDirection.front;
Future onPanUpdate(dynamic details) async {
if (details == null) {
return;
}
- if (mc.cameraController == null ||
- !mc.cameraController!.value.isInitialized) {
+ if (mc.cameraController == null || !mc.cameraController!.value.isInitialized) {
return;
}
@@ -530,8 +551,7 @@ class _CameraPreviewViewState extends State {
}
Future startVideoRecording() async {
- if (mc.cameraController != null &&
- mc.cameraController!.value.isRecordingVideo) {
+ if (mc.cameraController != null && mc.cameraController!.value.isRecordingVideo) {
return;
}
setState(() {
@@ -551,8 +571,7 @@ class _CameraPreviewViewState extends State {
_currentTime = clock.now();
});
if (_videoRecordingStarted != null &&
- _currentTime.difference(_videoRecordingStarted!).inSeconds >=
- maxVideoRecordingTime) {
+ _currentTime.difference(_videoRecordingStarted!).inSeconds >= maxVideoRecordingTime) {
timer.cancel();
_videoRecordingTimer = null;
stopVideoRecording();
@@ -589,8 +608,7 @@ class _CameraPreviewViewState extends State {
_videoRecordingLocked = false;
});
- if (mc.cameraController == null ||
- !mc.cameraController!.value.isRecordingVideo) {
+ if (mc.cameraController == null || !mc.cameraController!.value.isRecordingVideo) {
return;
}
@@ -618,8 +636,7 @@ class _CameraPreviewViewState extends State {
@override
Widget build(BuildContext context) {
- if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
- mc.cameraController == null) {
+ if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length || mc.cameraController == null) {
return Container();
}
return StreamBuilder(
@@ -643,9 +660,7 @@ class _CameraPreviewViewState extends State {
_baseScaleFactor = mc.selectedCameraDetails.scaleFactor;
});
// Get the position of the pointer
- final renderBox =
- keyTriggerButton.currentContext!.findRenderObject()!
- as RenderBox;
+ final renderBox = keyTriggerButton.currentContext!.findRenderObject()! as RenderBox;
final localPosition = renderBox.globalToLocal(
details.globalPosition,
);
@@ -681,24 +696,18 @@ class _CameraPreviewViewState extends State {
),
),
),
- if (!mc.isSharePreviewIsShown &&
- widget.sendToGroup != null &&
- !mc.isVideoRecording)
+ if (!mc.isSharePreviewIsShown && widget.sendToGroup != null && !mc.isVideoRecording)
ShowTitleText(
title: widget.sendToGroup!.groupName,
desc: context.lang.cameraPreviewSendTo,
),
- if (!mc.isSharePreviewIsShown &&
- mc.sharedLinkForPreview != null &&
- !mc.isVideoRecording)
+ if (!mc.isSharePreviewIsShown && mc.sharedLinkForPreview != null && !mc.isVideoRecording)
ShowTitleText(
title: mc.sharedLinkForPreview?.host ?? '',
desc: 'Link',
isLink: true,
),
- if (!mc.isSharePreviewIsShown &&
- !mc.isVideoRecording &&
- !widget.hideControllers)
+ if (!mc.isSharePreviewIsShown && !mc.isVideoRecording && !widget.hideControllers)
CameraTopActions(
selectedCameraDetails: mc.selectedCameraDetails,
hasAudioPermission: _hasAudioPermission,
@@ -742,8 +751,7 @@ class _CameraPreviewViewState extends State {
videoRecordingStarted: _videoRecordingStarted,
maxVideoRecordingTime: maxVideoRecordingTime,
),
- if (!mc.isSharePreviewIsShown && widget.sendToGroup != null ||
- widget.hideControllers)
+ if (!mc.isSharePreviewIsShown && widget.sendToGroup != null || widget.hideControllers)
Positioned(
left: 5,
top: 10,
diff --git a/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart
index 3cf2c903..1a2cae41 100644
--- a/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart
+++ b/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart
@@ -87,8 +87,10 @@ class MainCameraController {
Future? _initializeFuture;
Future? _pendingDisposal;
+ int _cameraSessionId = 0;
Future closeCamera() async {
+ _cameraSessionId++;
contactsVerified = {};
scannedNewProfiles = {};
scannedUrl = null;
@@ -119,11 +121,14 @@ class MainCameraController {
}
Future selectCamera(int sCameraId, bool init) async {
- await _pendingDisposal;
initCameraStarted = true;
+ final sessionId = ++_cameraSessionId;
+ await _pendingDisposal;
+ if (sessionId != _cameraSessionId) return;
if (AppEnvironment.cameras.isEmpty) {
AppEnvironment.cameras = await availableCameras();
+ if (sessionId != _cameraSessionId) return;
}
var cameraId = sCameraId;
@@ -145,10 +150,13 @@ class MainCameraController {
selectedCameraDetails.isZoomAble = false;
if (cameraController == null) {
+ final hasMic = await Permission.microphone.isGranted;
+ if (sessionId != _cameraSessionId) return;
+
cameraController = CameraController(
AppEnvironment.cameras[cameraId],
ResolutionPreset.high,
- enableAudio: await Permission.microphone.isGranted,
+ enableAudio: hasMic,
imageFormatGroup: Platform.isAndroid ? ImageFormatGroup.nv21 : ImageFormatGroup.bgra8888,
);
try {
diff --git a/lib/src/visual/views/camera/camera_preview_components/zoom_selector.dart b/lib/src/visual/views/camera/camera_preview_components/zoom_selector.dart
index b0a22bf5..dc40aec9 100644
--- a/lib/src/visual/views/camera/camera_preview_components/zoom_selector.dart
+++ b/lib/src/visual/views/camera/camera_preview_components/zoom_selector.dart
@@ -8,7 +8,15 @@ import 'package:flutter/material.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
-class CameraZoomButtons extends StatefulWidget {
+String beautifulZoomScale(double scale) {
+ var tmp = scale.toStringAsFixed(1);
+ if (tmp[0] == '0') {
+ tmp = tmp.substring(1, tmp.length);
+ }
+ return tmp;
+}
+
+class CameraZoomButtons extends StatelessWidget {
const CameraZoomButtons({
required this.controller,
required this.updateScaleFactor,
@@ -25,32 +33,10 @@ class CameraZoomButtons extends StatefulWidget {
final Future Function(int sCameraId, bool init) selectCamera;
@override
- State createState() => _CameraZoomButtonsState();
-}
-
-String beautifulZoomScale(double scale) {
- var tmp = scale.toStringAsFixed(1);
- if (tmp[0] == '0') {
- tmp = tmp.substring(1, tmp.length);
- }
- return tmp;
-}
-
-class _CameraZoomButtonsState extends State {
- bool showWideAngleZoom = false;
- bool showWideAngleZoomIOS = false;
- bool _isDisposed = false;
- int? _wideCameraIndex;
-
- @override
- void initState() {
- super.initState();
- unawaited(initAsync());
- }
-
- Future initAsync() async {
- showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
+ Widget build(BuildContext context) {
+ final showWideAngleZoom = selectedCameraDetails.minAvailableZoom < 1;
+ int? wideCameraIndex;
var index = AppEnvironment.cameras.indexWhere(
(t) => t.lensType == CameraLensType.ultraWide,
);
@@ -60,33 +46,13 @@ class _CameraZoomButtonsState extends State {
);
}
if (index != -1) {
- _wideCameraIndex = index;
+ wideCameraIndex = index;
}
- final isFront =
- widget.controller.description.lensDirection ==
- CameraLensDirection.front;
+ final isFront = controller.description.lensDirection == CameraLensDirection.front;
- if (!showWideAngleZoom &&
- Platform.isIOS &&
- _wideCameraIndex != null &&
- !isFront) {
- showWideAngleZoomIOS = true;
- } else {
- showWideAngleZoomIOS = false;
- }
- if (_isDisposed) return;
- setState(() {});
- }
+ final showWideAngleZoomIOS = !showWideAngleZoom && Platform.isIOS && wideCameraIndex != null && !isFront;
- @override
- void dispose() {
- _isDisposed = true; // Set the flag to true when disposing
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
final zoomButtonStyle = TextButton.styleFrom(
padding: EdgeInsets.zero,
foregroundColor: Colors.white,
@@ -97,24 +63,21 @@ class _CameraZoomButtonsState extends State {
const zoomTextStyle = TextStyle(fontSize: 13);
final isSmallerFocused =
- widget.scaleFactor < 1 ||
- (showWideAngleZoomIOS &&
- widget.selectedCameraDetails.cameraId == _wideCameraIndex);
+ scaleFactor < 1 || (showWideAngleZoomIOS && selectedCameraDetails.cameraId == wideCameraIndex);
final isMiddleFocused =
- widget.scaleFactor >= 1 &&
- widget.scaleFactor < 2 &&
- !(showWideAngleZoomIOS &&
- widget.selectedCameraDetails.cameraId == _wideCameraIndex);
+ scaleFactor >= 1 &&
+ scaleFactor < 2 &&
+ !(showWideAngleZoomIOS && selectedCameraDetails.cameraId == wideCameraIndex);
final maxLevel = max(
- min(widget.selectedCameraDetails.maxAvailableZoom, 2),
- widget.scaleFactor,
+ min(selectedCameraDetails.maxAvailableZoom, 2),
+ scaleFactor,
);
final minLevel = beautifulZoomScale(
- widget.selectedCameraDetails.minAvailableZoom,
+ selectedCameraDetails.minAvailableZoom,
);
- final currentLevel = beautifulZoomScale(widget.scaleFactor);
+ final currentLevel = beautifulZoomScale(scaleFactor);
return Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(40),
@@ -132,20 +95,18 @@ class _CameraZoomButtonsState extends State {
),
onPressed: () async {
if (showWideAngleZoomIOS) {
- if (_wideCameraIndex != null) {
- await widget.selectCamera(_wideCameraIndex!, true);
+ if (wideCameraIndex != null) {
+ await selectCamera(wideCameraIndex, true);
}
} else {
- final level = await widget.controller.getMinZoomLevel();
- widget.updateScaleFactor(level);
+ final level = await controller.getMinZoomLevel();
+ updateScaleFactor(level);
}
},
child: showWideAngleZoomIOS
? const Text('0.5')
: Text(
- widget.scaleFactor < 1
- ? '${currentLevel}x'
- : '${minLevel}x',
+ scaleFactor < 1 ? '${currentLevel}x' : '${minLevel}x',
style: zoomTextStyle,
),
),
@@ -156,39 +117,33 @@ class _CameraZoomButtonsState extends State {
),
),
onPressed: () async {
- if (showWideAngleZoomIOS &&
- widget.selectedCameraDetails.cameraId ==
- _wideCameraIndex) {
- await widget.selectCamera(0, true);
+ if (showWideAngleZoomIOS && selectedCameraDetails.cameraId == wideCameraIndex) {
+ await selectCamera(0, true);
} else {
- widget.updateScaleFactor(1.0);
+ updateScaleFactor(1.0);
}
},
child: Text(
- isMiddleFocused
- ? '${beautifulZoomScale(widget.scaleFactor)}x'
- : '1.0x',
+ isMiddleFocused ? '${beautifulZoomScale(scaleFactor)}x' : '1.0x',
style: zoomTextStyle,
),
),
TextButton(
style: zoomButtonStyle.copyWith(
foregroundColor: WidgetStateProperty.all(
- (widget.scaleFactor >= 2) ? Colors.yellow : Colors.white,
+ (scaleFactor >= 2) ? Colors.yellow : Colors.white,
),
),
onPressed: () async {
final level = min(
- await widget.controller.getMaxZoomLevel(),
+ await controller.getMaxZoomLevel(),
2,
).toDouble();
- if (showWideAngleZoomIOS &&
- widget.selectedCameraDetails.cameraId ==
- _wideCameraIndex) {
- await widget.selectCamera(0, true);
+ if (showWideAngleZoomIOS && selectedCameraDetails.cameraId == wideCameraIndex) {
+ await selectCamera(0, true);
}
- widget.updateScaleFactor(level);
+ updateScaleFactor(level);
},
child: Text(
'${beautifulZoomScale(maxLevel.toDouble())}x',
diff --git a/lib/src/visual/views/camera/share_image_contact_selection.view.dart b/lib/src/visual/views/camera/share_image_contact_selection.view.dart
index c968a3c0..4a6f7a40 100644
--- a/lib/src/visual/views/camera/share_image_contact_selection.view.dart
+++ b/lib/src/visual/views/camera/share_image_contact_selection.view.dart
@@ -254,6 +254,7 @@ class _ShareImageView extends State {
),
),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: _allGroups.isEmpty
? null
: SizedBox(
diff --git a/lib/src/visual/views/camera/share_image_contact_selection_components/best_friends_selector.dart b/lib/src/visual/views/camera/share_image_contact_selection_components/best_friends_selector.dart
index 78c87516..91f8a70b 100644
--- a/lib/src/visual/views/camera/share_image_contact_selection_components/best_friends_selector.dart
+++ b/lib/src/visual/views/camera/share_image_contact_selection_components/best_friends_selector.dart
@@ -156,7 +156,7 @@ class UserCheckbox extends StatelessWidget {
Row(
children: [
Text(
- substringBy(group.groupName, 12),
+ substringBy(group.groupName, 11),
overflow: TextOverflow.ellipsis,
),
],
diff --git a/lib/src/visual/views/camera/share_image_editor.view.dart b/lib/src/visual/views/camera/share_image_editor.view.dart
index d2b29bc7..d09ad5e5 100644
--- a/lib/src/visual/views/camera/share_image_editor.view.dart
+++ b/lib/src/visual/views/camera/share_image_editor.view.dart
@@ -214,8 +214,7 @@ class _ShareImageEditorView extends State {
List get actionsAtTheRight {
if (layers.isNotEmpty &&
- (layers.first.isEditing ||
- (layers.last.isEditing && layers.last.hasCustomActionButtons))) {
+ (layers.first.isEditing || (layers.last.isEditing && layers.last.hasCustomActionButtons))) {
return [];
}
return [
@@ -291,13 +290,9 @@ class _ShareImageEditorView extends State {
if (media.type == MediaType.video) ...[
const SizedBox(height: 8),
ActionButton(
- (mediaService.removeAudio)
- ? Icons.volume_off_rounded
- : Icons.volume_up_rounded,
+ (mediaService.removeAudio) ? Icons.volume_off_rounded : Icons.volume_up_rounded,
tooltipText: 'Enable Audio in Video',
- color: (mediaService.removeAudio)
- ? Colors.white.withAlpha(160)
- : Colors.white,
+ color: (mediaService.removeAudio) ? Colors.white.withAlpha(160) : Colors.white,
onPressed: () async {
await mediaService.toggleRemoveAudio();
if (mediaService.removeAudio) {
@@ -335,9 +330,7 @@ class _ShareImageEditorView extends State {
ActionButton(
FontAwesomeIcons.shieldHeart,
tooltipText: context.lang.protectAsARealTwonly,
- color: media.requiresAuthentication
- ? Theme.of(context).colorScheme.primary
- : Colors.white,
+ color: media.requiresAuthentication ? Theme.of(context).colorScheme.primary : Colors.white,
onPressed: () async {
await mediaService.setRequiresAuth(!media.requiresAuthentication);
selectedGroupIds = HashSet();
@@ -383,8 +376,7 @@ class _ShareImageEditorView extends State {
List get actionsAtTheTop {
if (layers.isNotEmpty &&
- (layers.first.isEditing ||
- (layers.last.isEditing && layers.last.hasCustomActionButtons))) {
+ (layers.first.isEditing || (layers.last.isEditing && layers.last.hasCustomActionButtons))) {
return [];
}
return [
@@ -474,6 +466,14 @@ class _ShareImageEditorView extends State {
return (layers.first as BackgroundLayerData).image.image;
}
}
+ if (layers.length == 2) {
+ final filterLayer = layers[1];
+ if (layers.first is BackgroundLayerData && filterLayer is FilterLayerData) {
+ if (filterLayer.page == 1) {
+ return (layers.first as BackgroundLayerData).image.image;
+ }
+ }
+ }
for (final x in layers) {
x.showCustomButtons = false;
@@ -513,15 +513,15 @@ class _ShareImageEditorView extends State {
}
}
ScreenshotImageHelper? image;
- var bytes = await widget.screenshotImage?.getBytes();
if (media.type == MediaType.gif) {
+ final bytes = await widget.screenshotImage?.getBytes();
if (bytes != null) {
mediaService.originalPath.writeAsBytesSync(bytes.toList());
}
} else {
image = await getEditedImageBytes();
if (image == null) return null;
- bytes = await image.getBytes();
+ final bytes = await image.getBytes();
if (bytes == null) {
Log.error('imageBytes are empty');
return null;
@@ -657,9 +657,7 @@ class _ShareImageEditorView extends State {
await askToCloseThenClose();
},
child: Scaffold(
- backgroundColor: widget.sharedFromGallery
- ? null
- : Colors.white.withAlpha(0),
+ backgroundColor: widget.sharedFromGallery ? null : Colors.white.withAlpha(0),
resizeToAvoidBottomInset: false,
body: Stack(
fit: StackFit.expand,
diff --git a/lib/src/visual/views/chats/chat_list.view.dart b/lib/src/visual/views/chats/chat_list.view.dart
index d45536cb..4feb177f 100644
--- a/lib/src/visual/views/chats/chat_list.view.dart
+++ b/lib/src/visual/views/chats/chat_list.view.dart
@@ -283,6 +283,7 @@ class _ChatListViewState extends State {
],
),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: !_hasContacts
? null
: Padding(
diff --git a/lib/src/visual/views/groups/group_create_select_group_name.view.dart b/lib/src/visual/views/groups/group_create_select_group_name.view.dart
index 974e6fc8..1bfc7132 100644
--- a/lib/src/visual/views/groups/group_create_select_group_name.view.dart
+++ b/lib/src/visual/views/groups/group_create_select_group_name.view.dart
@@ -58,6 +58,7 @@ class _GroupCreateSelectGroupNameViewState
appBar: AppBar(
title: Text(context.lang.selectGroupName),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: FilledButton.icon(
onPressed: (textFieldGroupName.text.isEmpty || _isLoading)
? null
diff --git a/lib/src/visual/views/groups/group_create_select_members.view.dart b/lib/src/visual/views/groups/group_create_select_members.view.dart
index 5c6a0d0d..42930b06 100644
--- a/lib/src/visual/views/groups/group_create_select_members.view.dart
+++ b/lib/src/visual/views/groups/group_create_select_members.view.dart
@@ -129,6 +129,7 @@ class _StartNewChatView extends State {
: context.lang.addMember,
),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: FilledButton.icon(
onPressed: selectedUsers.isEmpty ? null : submitChanges,
label: Text(
diff --git a/lib/src/visual/views/home.view.dart b/lib/src/visual/views/home.view.dart
index b44b87f6..791106e2 100644
--- a/lib/src/visual/views/home.view.dart
+++ b/lib/src/visual/views/home.view.dart
@@ -267,15 +267,17 @@ class HomeViewState extends State {
),
),
),
- if (_offsetRatio == 0)
- Positioned.fill(
- child: GestureDetector(
- behavior: HitTestBehavior.translucent,
- onDoubleTap: _mainCameraController.onDoubleTap,
- onTapDown: _mainCameraController.onTapDown,
- ),
- ),
+ Positioned.fill(
+ child: _offsetRatio == 0
+ ? GestureDetector(
+ behavior: HitTestBehavior.translucent,
+ onDoubleTap: _mainCameraController.onDoubleTap,
+ onTapDown: _mainCameraController.onTapDown,
+ )
+ : const SizedBox.shrink(),
+ ),
Positioned(
+ key: const ValueKey('camera_controls'),
left: 0,
top: 0,
right: 0,
diff --git a/lib/src/visual/views/settings/subscription/select_additional_users.view.dart b/lib/src/visual/views/settings/subscription/select_additional_users.view.dart
index 21252dcd..051d4982 100644
--- a/lib/src/visual/views/settings/subscription/select_additional_users.view.dart
+++ b/lib/src/visual/views/settings/subscription/select_additional_users.view.dart
@@ -99,6 +99,7 @@ class _SelectAdditionalUsers extends State {
appBar: AppBar(
title: Text(context.lang.additionalUserSelectTitle),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: FilledButton.icon(
onPressed: selectedUsers.isEmpty
? null
diff --git a/lib/src/visual/views/shared/select_contacts.view.dart b/lib/src/visual/views/shared/select_contacts.view.dart
index 53684c33..80e87310 100644
--- a/lib/src/visual/views/shared/select_contacts.view.dart
+++ b/lib/src/visual/views/shared/select_contacts.view.dart
@@ -112,6 +112,7 @@ class _SelectAdditionalUsers extends State {
appBar: AppBar(
title: Text(widget.text.title),
),
+ floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,
floatingActionButton: FilledButton.icon(
onPressed: selectedUsers.isEmpty
? null
diff --git a/pubspec.yaml b/pubspec.yaml
index 2c843a3d..63b56ded 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
publish_to: 'none'
-version: 0.2.16+125
+version: 0.2.17+126
environment:
sdk: ^3.11.0