diff --git a/README.md b/README.md
index b6229df..e8ac43c 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,14 @@
This repository contains the complete source code of the [twonly](https://twonly.eu) apps.
+
+
+
+
+
+
+
## Features
- Offer a Snapchat™ like experience
@@ -54,11 +62,11 @@ run-as eu.twonly.testing ls /data/user/0/eu.twonly.testing/
## Signing Keys
-When you download the app **via GitHub** you can verify the signing keys using for example the [AppVerifyer](https://github.com/soupslurpr/AppVerifier) and the following SHA-256 fingerprint of the signing certificate.
+When you download the app **via GitHub or F-Droid** you can verify the signing keys using for example the [AppVerifyer](https://github.com/soupslurpr/AppVerifier) and the following SHA-256 fingerprint of the signing certificate.
eu.twonly
E3:C4:4D:56:8C:67:F9:32:AC:8C:33:90:99:8A:B9:5E:E8:FF:2D:7A:07:3C:24:E3:66:77:93:E6:EA:CD:77:0A
## License
-This project is licensed under the [GNU AGPL 3.0](LICENSE) license.
\ No newline at end of file
+This project is licensed under the [GNU AGPL 3.0](LICENSE) license.
diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift
index 9fb06e1..d3db8e5 100644
--- a/ios/NotificationService/NotificationService.swift
+++ b/ios/NotificationService/NotificationService.swift
@@ -238,7 +238,7 @@ func getPushNotificationText(pushNotification: PushNotification) -> (String, Str
.text: "sent a message{inGroup}.",
.twonly: "sent a twonly{inGroup}.",
.video: "sent a video{inGroup}.",
- .image: "sent a image{inGroup}.",
+ .image: "sent an image{inGroup}.",
.audio: "sent a voice message{inGroup}.",
.contactRequest: "wants to connect with you.",
.acceptRequest: "is now connected with you.",
diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart
index 5fd2fe6..048c0d9 100644
--- a/lib/src/database/daos/groups.dao.dart
+++ b/lib/src/database/daos/groups.dao.dart
@@ -287,7 +287,7 @@ class GroupsDao extends DatabaseAccessor with _$GroupsDaoMixin {
..where((t) => t.groupId.equals(groupId)))
.getSingle();
- final totalMediaCounter = group.totalMediaCounter + (received ? 0 : 1);
+ final totalMediaCounter = group.totalMediaCounter + 1;
var flameCounter = group.flameCounter;
var maxFlameCounter = group.maxFlameCounter;
var maxFlameCounterFrom = group.maxFlameCounterFrom;
diff --git a/lib/src/database/daos/messages.dao.dart b/lib/src/database/daos/messages.dao.dart
index 97bd5b7..7269054 100644
--- a/lib/src/database/daos/messages.dao.dart
+++ b/lib/src/database/daos/messages.dao.dart
@@ -115,7 +115,7 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin {
milliseconds: group.deleteMessagesAfterMilliseconds,
),
);
- final affected = await (delete(messages)
+ await (delete(messages)
..where(
(m) =>
m.groupId.equals(group.groupId) &
@@ -127,7 +127,6 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin {
m.createdAt.isSmallerThanValue(deletionTime))),
))
.go();
- Log.info('Deleted $affected messages.');
}
}
diff --git a/lib/src/database/daos/receipts.dao.dart b/lib/src/database/daos/receipts.dao.dart
index 8b44397..34c05e2 100644
--- a/lib/src/database/daos/receipts.dao.dart
+++ b/lib/src/database/daos/receipts.dao.dart
@@ -62,7 +62,7 @@ class ReceiptsDao extends DatabaseAccessor with _$ReceiptsDaoMixin {
return await (select(receipts)..where((t) => t.rowId.equals(id)))
.getSingle();
} catch (e) {
- Log.error(e);
+ // ignore error, receipts is already in the database...
return null;
}
}
diff --git a/lib/src/localization/app_en.arb b/lib/src/localization/app_en.arb
index df2ccc6..26ada4e 100644
--- a/lib/src/localization/app_en.arb
+++ b/lib/src/localization/app_en.arb
@@ -562,7 +562,7 @@
"notificationText": "sent a message{inGroup}.",
"notificationTwonly": "sent a twonly{inGroup}.",
"notificationVideo": "sent a video{inGroup}.",
- "notificationImage": "sent a image{inGroup}.",
+ "notificationImage": "sent an image{inGroup}.",
"notificationAudio": "sent a voice message{inGroup}.",
"notificationAddedToGroup": "has added you to \"{groupname}\"",
"notificationContactRequest": "wants to connect with you.",
diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart
index 54d0805..9cadfcf 100644
--- a/lib/src/localization/generated/app_localizations.dart
+++ b/lib/src/localization/generated/app_localizations.dart
@@ -2477,7 +2477,7 @@ abstract class AppLocalizations {
/// No description provided for @notificationImage.
///
/// In en, this message translates to:
- /// **'sent a image{inGroup}.'**
+ /// **'sent an image{inGroup}.'**
String notificationImage(Object inGroup);
/// No description provided for @notificationAudio.
diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart
index 5763b12..d011a43 100644
--- a/lib/src/localization/generated/app_localizations_en.dart
+++ b/lib/src/localization/generated/app_localizations_en.dart
@@ -1345,7 +1345,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String notificationImage(Object inGroup) {
- return 'sent a image$inGroup.';
+ return 'sent an image$inGroup.';
}
@override
diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart
index c595be4..dea88dc 100644
--- a/lib/src/services/api.service.dart
+++ b/lib/src/services/api.service.dart
@@ -185,7 +185,7 @@ class ApiService {
}
Future _onError(dynamic e) async {
- Log.error('websocket error: $e');
+ Log.warn('websocket error: $e');
await onClosed();
}
@@ -206,7 +206,7 @@ class ApiService {
Future _waitForResponse(Int64 seq) async {
final startTime = DateTime.now();
- const timeout = Duration(seconds: 20);
+ const timeout = Duration(seconds: 60);
while (true) {
if (messagesV0[seq] != null) {
@@ -215,7 +215,7 @@ class ApiService {
return tmp;
}
if (DateTime.now().difference(startTime) > timeout) {
- Log.error('Timeout for message $seq');
+ Log.warn('Timeout for message $seq');
return null;
}
await Future.delayed(const Duration(milliseconds: 10));
@@ -283,10 +283,6 @@ class ApiService {
request.v0.seq = seq;
final requestBytes = request.writeToBuffer();
- Log.info(
- 'Sending ${requestBytes.length} bytes to the server via WebSocket.',
- );
-
if (ensureRetransmission) {
await addToRetransmissionBuffer(seq, requestBytes);
}
@@ -421,7 +417,7 @@ class ApiService {
final result = await sendRequestSync(req, authenticated: false);
if (result.isError) {
- Log.error('could not request auth challenge', result);
+ Log.warn('could not request auth challenge', result);
return;
}
diff --git a/lib/src/services/api/mediafiles/download.service.dart b/lib/src/services/api/mediafiles/download.service.dart
index f5108a1..12ea9dc 100644
--- a/lib/src/services/api/mediafiles/download.service.dart
+++ b/lib/src/services/api/mediafiles/download.service.dart
@@ -100,9 +100,11 @@ Future handleDownloadStatusUpdate(TaskStatusUpdate update) async {
failed = false;
} else {
failed = true;
- Log.error(
- 'Got invalid response status code: ${update.responseStatusCode}',
- );
+ if (update.responseStatusCode != null) {
+ Log.error(
+ 'Got invalid response status code: ${update.responseStatusCode}',
+ );
+ }
}
} else {
Log.info('Got ${update.status} for $mediaId');
@@ -110,7 +112,6 @@ Future handleDownloadStatusUpdate(TaskStatusUpdate update) async {
}
if (failed) {
- Log.error('Background media upload failed: ${update.status}');
await requestMediaReupload(mediaId);
} else {
await handleEncryptedFile(mediaId);
diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart
index 13affc2..d083505 100644
--- a/lib/src/services/api/messages.dart
+++ b/lib/src/services/api/messages.dart
@@ -44,7 +44,7 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({
if (receipt == null) {
receipt = await twonlyDB.receiptsDao.getReceiptById(receiptId!);
if (receipt == null) {
- Log.error('Receipt not found.');
+ Log.warn('Receipt not found.');
return null;
}
}
diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart
index b4b2ddd..d395f80 100644
--- a/lib/src/services/api/server_messages.dart
+++ b/lib/src/services/api/server_messages.dart
@@ -134,7 +134,6 @@ Future handleClient2ClientMessage(int fromUserId, Uint8List body) async {
..receiptId = receiptId
..type = Message_Type.PLAINTEXT_CONTENT
..plaintextContent = responsePlaintextContent;
- Log.error('Sending decryption error');
} else {
response = Message()..type = Message_Type.SENDER_DELIVERY_RECEIPT;
}
diff --git a/lib/src/services/fcm.service.dart b/lib/src/services/fcm.service.dart
index 33ffaa8..df3ebc5 100644
--- a/lib/src/services/fcm.service.dart
+++ b/lib/src/services/fcm.service.dart
@@ -22,6 +22,13 @@ Future initFCMAfterAuthenticated() async {
final storedToken = await storage.read(key: SecureStorageKeys.googleFcm);
try {
+ if (Platform.isIOS) {
+ final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
+ if (apnsToken == null) {
+ Log.error('Error getting apnsToken');
+ return;
+ }
+ }
final fcmToken = await FirebaseMessaging.instance.getToken();
if (fcmToken == null) {
Log.error('Error getting fcmToken');
diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart
index 0425efa..24b4e37 100644
--- a/lib/src/services/mediafiles/mediafile.service.dart
+++ b/lib/src/services/mediafiles/mediafile.service.dart
@@ -35,11 +35,7 @@ class MediaFileService {
final service = await MediaFileService.fromMediaId(mediaId);
- if (service == null) {
- Log.error(
- 'Purging media file, as it is not in the database $mediaId.',
- );
- } else {
+ if (service != null) {
if (service.mediaFile.isDraftMedia) {
delete = false;
}
diff --git a/lib/src/services/signal/encryption.signal.dart b/lib/src/services/signal/encryption.signal.dart
index 50aad34..3c24598 100644
--- a/lib/src/services/signal/encryption.signal.dart
+++ b/lib/src/services/signal/encryption.signal.dart
@@ -112,7 +112,7 @@ Future<(EncryptedContent?, PlaintextContent_DecryptionErrorMessage_Type?)>
return (EncryptedContent.fromBuffer(plaintext), null);
} on InvalidKeyIdException catch (e) {
- Log.error(e);
+ Log.warn(e);
return (null, PlaintextContent_DecryptionErrorMessage_Type.PREKEY_UNKNOWN);
} catch (e) {
Log.error(e);
diff --git a/lib/src/services/signal/prekeys.signal.dart b/lib/src/services/signal/prekeys.signal.dart
index e70d239..f2dcde2 100644
--- a/lib/src/services/signal/prekeys.signal.dart
+++ b/lib/src/services/signal/prekeys.signal.dart
@@ -50,8 +50,7 @@ Future requestNewPrekeysForContact(int contactId) async {
.toList();
await twonlyDB.signalDao.insertPreKeys(preKeys);
} else {
- // 104400
- Log.error('[PREKEY] Could not load new pre keys for user $contactId');
+ Log.warn('[PREKEY] Could not load new pre keys for user $contactId');
}
});
}
@@ -85,7 +84,7 @@ Future requestNewSignedPreKeyForContact(int contactId) async {
),
);
} else {
- Log.error('could not load new signed pre key for user $contactId');
+ Log.warn('could not load new signed pre key for user $contactId');
}
});
}
diff --git a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart
index 434b9d5..640e9cd 100644
--- a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart
+++ b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart
@@ -203,9 +203,6 @@ Future performTwonlySafeBackup({bool force = false}) async {
Future handleBackupStatusUpdate(TaskStatusUpdate update) async {
if (update.status == TaskStatus.failed ||
update.status == TaskStatus.canceled) {
- Log.error(
- 'twonly Backup upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}',
- );
await updateUserdata((user) {
if (user.twonlySafeBackup != null) {
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed;
diff --git a/lib/src/utils/log.dart b/lib/src/utils/log.dart
index fa9c34c..7eefe2a 100644
--- a/lib/src/utils/log.dart
+++ b/lib/src/utils/log.dart
@@ -18,10 +18,24 @@ void initLogger() {
);
}
});
+ cleanLogFile();
}
class Log {
- static void error(Object? message, [Object? error, StackTrace? stackTrace]) {
+ static String filterLogMessage(String msg) {
+ if (msg.contains('SqliteException')) {
+ // Do not log data which would be inserted into the DB.
+ return msg.substring(0, msg.indexOf('parameters: '));
+ }
+ return msg;
+ }
+
+ static void error(
+ Object? messageInput, [
+ Object? error,
+ StackTrace? stackTrace,
+ ]) {
+ final message = filterLogMessage('$messageInput');
if (globalAllowErrorTrackingViaSentry) {
try {
throw Exception(message);
@@ -32,11 +46,21 @@ class Log {
Logger(_getCallerSourceCodeFilename()).shout(message, error, stackTrace);
}
- static void warn(Object? message, [Object? error, StackTrace? stackTrace]) {
+ static void warn(
+ Object? messageInput, [
+ Object? error,
+ StackTrace? stackTrace,
+ ]) {
+ final message = filterLogMessage('$messageInput');
Logger(_getCallerSourceCodeFilename()).warning(message, error, stackTrace);
}
- static void info(Object? message, [Object? error, StackTrace? stackTrace]) {
+ static void info(
+ Object? messageInput, [
+ Object? error,
+ StackTrace? stackTrace,
+ ]) {
+ final message = filterLogMessage('$messageInput');
Logger(_getCallerSourceCodeFilename()).fine(message, error, stackTrace);
}
}
@@ -77,6 +101,23 @@ Future _writeLogToFile(LogRecord record) async {
});
}
+Future cleanLogFile() async {
+ final directory = await getApplicationSupportDirectory();
+ final logFile = File('${directory.path}/app.log');
+
+ if (logFile.existsSync()) {
+ final lines = await logFile.readAsLines();
+
+ if (lines.length <= 5000) return;
+
+ final removeCount = lines.length - 5000;
+ final remaining = lines.sublist(removeCount);
+
+ final sink = logFile.openWrite()..writeAll(remaining, '\n');
+ await sink.close();
+ }
+}
+
Future deleteLogFile() async {
final directory = await getApplicationSupportDirectory();
final logFile = File('${directory.path}/app.log');
diff --git a/lib/src/views/camera/camera_preview_components/zoom_selector.dart b/lib/src/views/camera/camera_preview_components/zoom_selector.dart
index d5824b0..c6d78cf 100644
--- a/lib/src/views/camera/camera_preview_components/zoom_selector.dart
+++ b/lib/src/views/camera/camera_preview_components/zoom_selector.dart
@@ -6,7 +6,6 @@ import 'dart:math';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:twonly/globals.dart';
-import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/views/camera/camera_preview_controller_view.dart';
class CameraZoomButtons extends StatefulWidget {
@@ -51,7 +50,6 @@ class _CameraZoomButtonsState extends State {
Future initAsync() async {
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
- Log.info('Found ${gCameras.length} cameras for zoom.');
var index =
gCameras.indexWhere((t) => t.lensType == CameraLensType.ultraWide);
diff --git a/lib/src/views/camera/image_editor/layers/text_layer.dart b/lib/src/views/camera/image_editor/layers/text_layer.dart
index b6b98e6..5e9627f 100755
--- a/lib/src/views/camera/image_editor/layers/text_layer.dart
+++ b/lib/src/views/camera/image_editor/layers/text_layer.dart
@@ -90,11 +90,15 @@ class _TextViewState extends State {
final bottom = MediaQuery.of(context).viewInsets.bottom +
MediaQuery.of(context).viewPadding.bottom;
+ // On Android it is possible to close the keyboard without `onEditingComplete` is triggered.
if (maxBottomInset > bottom) {
- maxBottomInset = 0;
- if (widget.layerData.isEditing) {
- widget.layerData.isEditing = false;
- onEditionComplete();
+ // prevent that the text element will be disappearing in case the keyboard just switches for example to the emoji page
+ if (bottom < 20) {
+ maxBottomInset = 0;
+ if (widget.layerData.isEditing) {
+ widget.layerData.isEditing = false;
+ onEditionComplete();
+ }
}
} else {
maxBottomInset = bottom;
diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart
index 8ef97c5..2d2cacc 100644
--- a/lib/src/views/camera/share_image_editor_view.dart
+++ b/lib/src/views/camera/share_image_editor_view.dart
@@ -6,7 +6,6 @@ import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
-import 'package:hashlib/random.dart';
import 'package:screenshot/screenshot.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
@@ -431,9 +430,17 @@ class _ShareImageEditorView extends State {
// In case the image was already stored, then rename the stored image.
if (mediaService.storedPath.existsSync()) {
- final newPath = mediaService.storedPath.absolute.path
- .replaceFirst(media.mediaId, uuid.v7());
- mediaService.storedPath.renameSync(newPath);
+ final mediaFile = await twonlyDB.mediaFilesDao.insertMedia(
+ MediaFilesCompanion(
+ type: Value(mediaService.mediaFile.type),
+ createdAt: Value(DateTime.now()),
+ stored: const Value(true),
+ ),
+ );
+ if (mediaFile != null) {
+ mediaService.storedPath
+ .renameSync(MediaFileService(mediaFile).storedPath.path);
+ }
}
return true;
}
diff --git a/lib/src/views/chats/chat_messages.view.dart b/lib/src/views/chats/chat_messages.view.dart
index 4526e8e..f4dbc51 100644
--- a/lib/src/views/chats/chat_messages.view.dart
+++ b/lib/src/views/chats/chat_messages.view.dart
@@ -260,6 +260,7 @@ class _ChatMessagesViewState extends State {
});
final items = await MemoryItem.convertFromMessages(storedMediaFiles);
+ if (!mounted) return;
galleryItems = items.values.toList();
setState(() {});
}
diff --git a/lib/src/views/chats/chat_messages_components/message_input.dart b/lib/src/views/chats/chat_messages_components/message_input.dart
index aa9059d..2e979b6 100644
--- a/lib/src/views/chats/chat_messages_components/message_input.dart
+++ b/lib/src/views/chats/chat_messages_components/message_input.dart
@@ -76,11 +76,7 @@ class _MessageInputState extends State {
}
void _initializeControllers() {
- recorderController = RecorderController()
- ..androidEncoder = AndroidEncoder.aac
- ..androidOutputFormat = AndroidOutputFormat.mpeg4
- ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
- ..sampleRate = 44100;
+ recorderController = RecorderController();
}
void _handleTextFocusChange() {
diff --git a/lib/src/views/chats/media_viewer.view.dart b/lib/src/views/chats/media_viewer.view.dart
index 846b32d..beba83f 100644
--- a/lib/src/views/chats/media_viewer.view.dart
+++ b/lib/src/views/chats/media_viewer.view.dart
@@ -172,12 +172,7 @@ class _MediaViewerViewState extends State {
showSendTextMessageInput = false;
});
- // if (Platform.isAndroid) {
- // await flutterLocalNotificationsPlugin
- // .cancel(allMediaFiles.first.contactId);
- // } else {
- await flutterLocalNotificationsPlugin.cancelAll();
- // }
+ unawaited(flutterLocalNotificationsPlugin.cancelAll());
final stream =
twonlyDB.mediaFilesDao.watchMedia(allMediaFiles.first.mediaId!);
@@ -261,6 +256,8 @@ class _MediaViewerViewState extends State {
return nextMediaOrExit();
}
+ var timerRequired = false;
+
if (currentMediaLocal.mediaFile.type == MediaType.video) {
videoController = VideoPlayerController.file(currentMediaLocal.tempPath);
await videoController?.setLooping(
@@ -292,12 +289,17 @@ class _MediaViewerViewState extends State {
currentMediaLocal.mediaFile.displayLimitInMilliseconds!,
),
);
+ timerRequired = true;
+ }
+ }
+ if (mounted) {
+ setState(() {
+ currentMedia = currentMediaLocal;
+ });
+ if (timerRequired) {
startTimer();
}
}
- setState(() {
- currentMedia = currentMediaLocal;
- });
}
void startTimer() {
@@ -310,14 +312,16 @@ class _MediaViewerViewState extends State {
}
});
progressTimer = Timer.periodic(const Duration(milliseconds: 10), (timer) {
- if (currentMedia!.mediaFile.displayLimitInMilliseconds == null ||
+ final mediaFile = currentMedia?.mediaFile;
+ if (mediaFile == null) return;
+ if (mediaFile.displayLimitInMilliseconds == null ||
canBeSeenUntil == null) {
return;
}
final difference = canBeSeenUntil!.difference(DateTime.now());
// Calculate the progress as a value between 0.0 and 1.0
- progress = difference.inMilliseconds /
- (currentMedia!.mediaFile.displayLimitInMilliseconds!);
+ progress =
+ difference.inMilliseconds / (mediaFile.displayLimitInMilliseconds!);
setState(() {});
});
}
diff --git a/lib/src/views/components/flame.dart b/lib/src/views/components/flame.dart
index dc83b12..3e33ba3 100644
--- a/lib/src/views/components/flame.dart
+++ b/lib/src/views/components/flame.dart
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:twonly/globals.dart';
+import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/views/components/animate_icon.dart';
class FlameCounterWidget extends StatefulWidget {
@@ -38,18 +39,20 @@ class _FlameCounterWidgetState extends State {
Future initAsync() async {
var groupId = widget.groupId;
+ late Group? group;
if (widget.groupId == null && widget.contactId != null) {
- final group = await twonlyDB.groupsDao.getDirectChat(widget.contactId!);
+ group = await twonlyDB.groupsDao.getDirectChat(widget.contactId!);
groupId = group?.groupId;
} else if (groupId != null) {
// do not display the flame counter for groups
- final group = await twonlyDB.groupsDao.getGroup(groupId);
+ group = await twonlyDB.groupsDao.getGroup(groupId);
if (!(group?.isDirectChat ?? false)) {
return;
}
}
- if (groupId != null) {
- isBestFriend = gUser.myBestFriendGroupId == groupId;
+ if (groupId != null && group != null) {
+ isBestFriend =
+ gUser.myBestFriendGroupId == groupId && group.alsoBestFriend;
final stream = twonlyDB.groupsDao.watchFlameCounter(groupId);
flameCounterSub = stream.listen((counter) {
if (mounted) {
diff --git a/metadata/de-DE/images/logo.png b/metadata/de-DE/icon.png
similarity index 100%
rename from metadata/de-DE/images/logo.png
rename to metadata/de-DE/icon.png
diff --git a/metadata/en-US/images/logo.png b/metadata/en-US/icon.png
similarity index 100%
rename from metadata/en-US/images/logo.png
rename to metadata/en-US/icon.png
diff --git a/pubspec.lock b/pubspec.lock
index e381a20..82b8e83 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -61,10 +61,10 @@ packages:
dependency: "direct main"
description:
name: audio_waveforms
- sha256: "658fef41bbab299184b65ba2fd749e8ec658c1f7d54a21f7cf97fa96b173b4ce"
+ sha256: "3a34bdd15dd63a6d1501218449048b28ebe8e1f795bf00ec310acd7b70648f07"
url: "https://pub.dev"
source: hosted
- version: "1.3.0"
+ version: "2.0.0"
avatar_maker:
dependency: "direct main"
description:
@@ -77,10 +77,10 @@ packages:
dependency: "direct main"
description:
name: background_downloader
- sha256: a913b37cc47a656a225e9562b69576000d516f705482f392e2663500e6ff6032
+ sha256: a3b340e42bc45598918944e378dc6a05877e587fcd0e1b8d2ea26339de87bdf9
url: "https://pub.dev"
source: hosted
- version: "9.3.0"
+ version: "9.4.0"
boolean_selector:
dependency: transitive
description:
@@ -397,11 +397,12 @@ packages:
emoji_picker_flutter:
dependency: "direct main"
description:
- name: emoji_picker_flutter
- sha256: "9a44c102079891ea5877f78c70f2e3c6e9df7b7fe0a01757d31f1046eeaa016d"
- url: "https://pub.dev"
- source: hosted
- version: "4.3.0"
+ path: "."
+ ref: HEAD
+ resolved-ref: c5bffd3414c1e640389b41165b831df7df1cf517
+ url: "https://github.com/otsmr/emoji_picker_flutter.git"
+ source: git
+ version: "4.4.0"
fake_async:
dependency: transitive
description:
@@ -1741,14 +1742,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
- universal_io:
- dependency: transitive
- description:
- name: universal_io
- sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.2"
url_launcher:
dependency: "direct main"
description:
@@ -1865,10 +1858,10 @@ packages:
dependency: "direct main"
description:
name: video_player
- sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a"
+ sha256: "096bc28ce10d131be80dfb00c223024eb0fba301315a406728ab43dd99c45bdf"
url: "https://pub.dev"
source: hosted
- version: "2.10.0"
+ version: "2.10.1"
video_player_android:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index ab0fe5c..1fcfc73 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,16 +3,16 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
publish_to: 'none'
-version: 0.0.71+71
+version: 0.0.72+72
environment:
sdk: ^3.6.0
dependencies:
archive: ^4.0.7
- audio_waveforms: ^1.3.0
+ audio_waveforms: ^2.0.0
avatar_maker: ^0.4.0
- background_downloader: ^9.2.2
+ background_downloader: ^9.4.0
cached_network_image: ^3.4.1
camera: ^0.11.2
collection: ^1.18.0
@@ -74,9 +74,9 @@ dependencies:
sentry_flutter: ^9.8.0
share_plus: ^12.0.0
tutorial_coach_mark: ^1.3.0
- url_launcher: ^6.3.1
+ url_launcher: ^6.3.2
vector_graphics: ^1.1.19
- video_player: ^2.9.5
+ video_player: ^2.10.1
web_socket_channel: ^3.0.1
dependency_overrides:
@@ -86,6 +86,11 @@ dependency_overrides:
url: https://github.com/otsmr/flutter-packages.git
path: packages/camera/camera_android_camerax
ref: aef58af205a5f3ce6588a5c59bb2e734aab943f0
+ emoji_picker_flutter:
+ # Fixes the issue with recent emojis (solved by https://github.com/Fintasys/emoji_picker_flutter/pull/238)
+ # Using override until this gets merged.
+ git:
+ url: https://github.com/otsmr/emoji_picker_flutter.git
flutter_android_volume_keydown:
git:
url: https://github.com/yenchieh/flutter_android_volume_keydown.git