Skip to content
Merged

Dev #416

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 0.2.23

- Improves: Smaller UI changes
- Fix: Some messages were not marked as opened.

## 0.2.20

- New: Adds an "Ask a Friend" button to new contact suggestions.
Expand Down
63 changes: 34 additions & 29 deletions lib/src/database/daos/messages.dao.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
t.openedAt.isNull() |
t.mediaStored.equals(true)) &
(t.isDeletedFromSender.equals(true) |
(t.type.equals(MessageType.text.name).not() |
(t.type.equals(MessageType.text.name).not() &
t.type.equals(MessageType.media.name).not()) |
(t.type.equals(MessageType.text.name) &
t.content.isNotNull()) |
Expand Down Expand Up @@ -156,8 +156,8 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
await (delete(messages)..where(
(m) =>
m.groupId.isIn(groupIds) &
(m.mediaStored.equals(true) &
m.isDeletedFromSender.equals(true) |
((m.mediaStored.equals(true) &
m.isDeletedFromSender.equals(true)) |
m.mediaStored.equals(false)) &
// Only remove the message when ALL members have seen it. Otherwise the receipt will also be deleted which could cause issues in case a member opens the image later..
(m.openedByAll.isSmallerThanValue(deletionTime) |
Expand Down Expand Up @@ -253,41 +253,46 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
List<String> messageIds,
DateTime timestamp,
) async {
try {
await twonlyDB.batch((batch) async {
for (final messageId in messageIds) {
batch.insert(
messageActions,
MessageActionsCompanion(
messageId: Value(messageId),
contactId: contactId,
type: const Value(MessageActionType.openedAt),
actionAt: Value(timestamp),
),
mode: InsertMode.insertOrReplace,
for (final messageId in messageIds) {
try {
var actionTimestamp = timestamp;
final msg = await getMessageById(messageId).getSingleOrNull();
if (msg != null && actionTimestamp.isBefore(msg.createdAt)) {
Log.warn(
'Receiver clock skew detected for message $messageId. '
'Action timestamp $actionTimestamp is before message creation ${msg.createdAt}. '
'Clamping to creation time.',
);
actionTimestamp = msg.createdAt;
}
});
} catch (e) {
Log.error(e);
}

for (final messageId in messageIds) {
try {
await into(messageActions).insertOnConflictUpdate(
MessageActionsCompanion(
messageId: Value(messageId),
contactId: contactId,
type: const Value(MessageActionType.openedAt),
actionAt: Value(actionTimestamp),
),
);

final isOpenedByAll = await haveAllMembers(
messageId,
MessageActionType.openedAt,
);
await (update(
messages,
)..where((tbl) => tbl.messageId.equals(messageId))).write(
MessagesCompanion(
openedAt: Value(timestamp),
openedByAll: Value(isOpenedByAll ? timestamp : null),
),
final rowsUpdated =
await (update(
messages,
)..where((tbl) => tbl.messageId.equals(messageId))).write(
MessagesCompanion(
openedAt: Value(actionTimestamp),
openedByAll: Value(isOpenedByAll ? actionTimestamp : null),
),
);
Log.info(
'handleMessagesOpened updated $rowsUpdated rows for message $messageId',
);
} catch (e) {
Log.error(e);
Log.error('handleMessagesOpened failed for $messageId: $e');
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion lib/src/database/daos/reactions.dao.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ class ReactionsDao extends DatabaseAccessor<TwonlyDB> with _$ReactionsDaoMixin {
final msg = await twonlyDB.messagesDao
.getMessageById(messageId)
.getSingleOrNull();
if (msg == null || msg.groupId != groupId) return;
if (msg == null) {
Log.error('updateReaction: Message $messageId not found!');
return;
}
if (msg.groupId != groupId) {
Log.error('updateReaction: Message groupId ${msg.groupId} != $groupId');
return;
}

try {
if (remove) {
Expand Down
1 change: 1 addition & 0 deletions lib/src/database/twonly.db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class TwonlyDB extends _$TwonlyDB {
setup: (rawDb) {
rawDb
..execute('PRAGMA journal_mode=WAL;')
..execute('PRAGMA synchronous=FULL;')
..execute('PRAGMA busy_timeout=5000;');
},
),
Expand Down
12 changes: 12 additions & 0 deletions lib/src/localization/generated/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3493,6 +3493,18 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Verify now'**
String get unverifiedWarningButton;

/// No description provided for @today.
///
/// In en, this message translates to:
/// **'Today'**
String get today;

/// No description provided for @yesterday.
///
/// In en, this message translates to:
/// **'Yesterday'**
String get yesterday;
}

class _AppLocalizationsDelegate
Expand Down
6 changes: 6 additions & 0 deletions lib/src/localization/generated/app_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1988,4 +1988,10 @@ class AppLocalizationsDe extends AppLocalizations {

@override
String get unverifiedWarningButton => 'Jetzt verifizieren';

@override
String get today => 'Heute';

@override
String get yesterday => 'Gestern';
}
6 changes: 6 additions & 0 deletions lib/src/localization/generated/app_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1972,4 +1972,10 @@ class AppLocalizationsEn extends AppLocalizations {

@override
String get unverifiedWarningButton => 'Verify now';

@override
String get today => 'Today';

@override
String get yesterday => 'Yesterday';
}
2 changes: 1 addition & 1 deletion lib/src/localization/translations
Submodule translations updated from c33a4c to 9a5388
5 changes: 4 additions & 1 deletion lib/src/services/api/client2client/reaction.c2c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ Future<void> handleReaction(
EncryptedContent_Reaction reaction,
String receiptId,
) async {
Log.info('[$receiptId] Got a reaction from $fromUserId (remove=${reaction.remove})');
Log.info(
'[$receiptId] Got a reaction from for ${reaction.targetMessageId} (remove=${reaction.remove})',
);

await twonlyDB.reactionsDao.updateReaction(
fromUserId,
reaction.targetMessageId,
Expand Down
7 changes: 7 additions & 0 deletions lib/src/services/api/mediafiles/upload.api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ Future<void> insertMediaFileInMessagesTable(
);
await twonlyDB.groupsDao.increaseLastMessageExchange(groupId, clock.now());
if (message != null) {
Log.info(
'Created message ${message.messageId} for media ${message.mediaId}',
);
// de-archive contact when sending a new message
await twonlyDB.groupsDao.updateGroup(
message.groupId,
Expand Down Expand Up @@ -444,6 +447,10 @@ Future<void> _startBackgroundMediaUploadInternal(

if (mediaService.mediaFile.uploadState == UploadState.initialized ||
mediaService.mediaFile.uploadState == UploadState.preprocessing) {
Log.info(
'Hanlding media file ${mediaService.mediaFile.mediaId} in ${mediaService.mediaFile.uploadState}',
);

await mediaService.setUploadState(UploadState.preprocessing);

if (!mediaService.tempPath.existsSync()) {
Expand Down
38 changes: 35 additions & 3 deletions lib/src/services/api/messages.api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
message.encryptedContent,
);

Log.info('Uploading message with receiptID ${receipt.receiptId}.');

Uint8List? pushData;
if (receipt.retryCount == 0) {
final pushNotification = await getPushNotificationFromEncryptedContent(
Expand Down Expand Up @@ -194,9 +192,12 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
}

if (onlyReturnEncryptedData) {
Log.info('Returning message with receiptID ${receipt.receiptId}.');
return (message.writeToBuffer(), pushData);
}

Log.info('Uploading message with receiptID ${receipt.receiptId}.');

final resp = await apiService.sendTextMessage(
receipt.contactId,
message.writeToBuffer(),
Expand Down Expand Up @@ -350,7 +351,9 @@ Future<void> insertAndSendAskAboutUserMessage(
) async {
final directChat = await twonlyDB.groupsDao.createOrGetDirectChat(contactId);
if (directChat == null) {
Log.error('Failed to get or create direct chat group for contact $contactId');
Log.error(
'Failed to get or create direct chat group for contact $contactId',
);
return;
}

Expand Down Expand Up @@ -483,6 +486,17 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
);

if (receipt != null) {
try {
final typeKeys = _getEncryptedContentTypes(encryptedContent);
Log.info(
'sendCipherText: type=[$typeKeys] messageId=$messageId receiptId=${receipt.receiptId}',
);
} catch (_) {
Log.info(
'sendCipherText: messageId=$messageId receiptId=${receipt.receiptId}',
);
}

final tmp = tryToSendCompleteMessage(
receipt: receipt,
onlyReturnEncryptedData: onlyReturnEncryptedData,
Expand Down Expand Up @@ -568,3 +582,21 @@ Future<void> sendContactMyProfileData(int contactId) async {
);
await sendCipherText(contactId, encryptedContent, blocking: false);
}

String _getEncryptedContentTypes(pb.EncryptedContent content) {
final ignoredFields = {
'groupId',
'isDirectChat',
'senderProfileCounter',
'senderUserDiscoveryVersion',
};

final types = <String>[];
for (final field in content.info_.byName.values) {
if (content.hasField(field.tagNumber) &&
!ignoredFields.contains(field.name)) {
types.add(field.name);
}
}
return types.join(', ');
}
7 changes: 7 additions & 0 deletions lib/src/services/mediafiles/mediafile.service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ class MediaFileService {
delete = false;
}

// Never purge temp files while an upload is still in progress.
// The temp file is actively needed for encryption/upload.
if (mediaFile.uploadState != UploadState.uploaded &&
mediaFile.uploadState != UploadState.fileLimitReached) {
delete = false;
}

final messages = messageMap[mediaId] ?? [];

// in case messages in empty the file will be deleted, as delete is true by default
Expand Down
32 changes: 0 additions & 32 deletions lib/src/services/migrations.service.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:clock/clock.dart';
import 'package:drift/drift.dart';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
Expand Down Expand Up @@ -145,37 +144,6 @@ Future<void> runMigrations() async {
}
}

if (userService.currentUser.appVersion < 116) {
// Because of a Bug in the handleMessagesOpened function, some messages where not marked as opened. So use the logs,
// to mark the files as opened.
final logs = await loadLogFile();
final openedMessages = logs.split(
'messages.c2c.dart:12 > Opened message [',
);
for (final opened in openedMessages) {
final messageIds = opened.split(']');
if (messageIds.isNotEmpty) {
final now = clock.now();
for (final messageId in messageIds.first.split(',')) {
await (twonlyDB.update(
twonlyDB.messages,
)..where(
(tbl) =>
tbl.messageId.equals(messageId) &
(tbl.openedByAll.isNull() | tbl.openedAt.isNull()),
))
.write(
MessagesCompanion(
openedAt: Value(now),
openedByAll: Value(now),
),
);
}
}
}
await UserService.update((u) => u.appVersion = 116);
}

if (kDebugMode) {
assert(
AppState.latestAppVersionId == 116,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/utils/startup_guard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class StartupGuard {
final stat = file.statSync();
final diff = DateTime.now().difference(stat.modified);

final starting = diff.inSeconds < 30;
final starting = diff.inSeconds < 5;
if (starting) {
Log.info(
'Startup guard: App is currently starting (${diff.inSeconds}s ago).',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
// Maybe this is the reason?
return;
} else {
await androidVolumeDownSub?.cancel();
androidVolumeDownSub = FlutterAndroidVolumeKeydown.stream.listen((
event,
) {
Expand All @@ -233,6 +234,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
}
if (Platform.isAndroid) {
await androidVolumeDownSub?.cancel();
androidVolumeDownSub = null;
}
}

Expand Down
Loading
Loading