mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 13:08:42 +00:00
purge text messages fix multiple bugs
This commit is contained in:
parent
4914df5610
commit
071c5c2a0d
25 changed files with 207 additions and 69 deletions
|
|
@ -57,13 +57,12 @@ void main() async {
|
||||||
await initFileDownloader();
|
await initFileDownloader();
|
||||||
|
|
||||||
unawaited(MediaFileService.purgeTempFolder());
|
unawaited(MediaFileService.purgeTempFolder());
|
||||||
|
await twonlyDB.messagesDao.purgeMessageTable();
|
||||||
|
|
||||||
// await twonlyDB.messagesDao.resetPendingDownloadState();
|
// await twonlyDB.messagesDao.resetPendingDownloadState();
|
||||||
// await twonlyDB.messageRetransmissionDao.purgeOldRetransmissions();
|
// await twonlyDB.messageRetransmissionDao.purgeOldRetransmissions();
|
||||||
// await twonlyDB.signalDao.purgeOutDatedPreKeys();
|
// await twonlyDB.signalDao.purgeOutDatedPreKeys();
|
||||||
|
|
||||||
// Purge media files in the background
|
|
||||||
// unawaited(purgeReceivedMediaFiles());
|
|
||||||
// unawaited(purgeSendMediaFiles());
|
// unawaited(purgeSendMediaFiles());
|
||||||
|
|
||||||
// unawaited(performTwonlySafeBackup());
|
// unawaited(performTwonlySafeBackup());
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getContactDisplayName(Contact user) {
|
String getContactDisplayName(Contact user, {int? maxLength}) {
|
||||||
var name = user.username;
|
var name = user.username;
|
||||||
if (user.nickName != null && user.nickName != '') {
|
if (user.nickName != null && user.nickName != '') {
|
||||||
name = user.nickName!;
|
name = user.nickName!;
|
||||||
|
|
@ -131,12 +131,19 @@ String getContactDisplayName(Contact user) {
|
||||||
if (user.accountDeleted) {
|
if (user.accountDeleted) {
|
||||||
name = applyStrikethrough(name);
|
name = applyStrikethrough(name);
|
||||||
}
|
}
|
||||||
if (name.length > 27) {
|
if (maxLength != null) {
|
||||||
return '${name.substring(0, 27 - 3)}...';
|
name = substringBy(name, maxLength);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String substringBy(String string, int maxLength) {
|
||||||
|
if (string.length > maxLength) {
|
||||||
|
return '${string.substring(0, maxLength - 3)}...';
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
String getContactDisplayNameOld(old.Contact user) {
|
String getContactDisplayNameOld(old.Contact user) {
|
||||||
var name = user.username;
|
var name = user.username;
|
||||||
if (user.nickName != null && user.nickName != '') {
|
if (user.nickName != null && user.nickName != '') {
|
||||||
|
|
|
||||||
|
|
@ -68,16 +68,20 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<Message>> watchByGroupId(String groupId) {
|
Stream<List<Message>> watchByGroupId(String groupId) {
|
||||||
return ((select(messages)..where((t) => t.groupId.equals(groupId)))
|
return ((select(messages)
|
||||||
|
..where(
|
||||||
|
(t) =>
|
||||||
|
t.groupId.equals(groupId) &
|
||||||
|
(t.isDeletedFromSender.equals(true) |
|
||||||
|
((t.type.equals(MessageType.text.name) &
|
||||||
|
t.content.isNotNull()) |
|
||||||
|
(t.type.equals(MessageType.media.name) &
|
||||||
|
t.mediaId.isNotNull()))),
|
||||||
|
))
|
||||||
..orderBy([(t) => OrderingTerm.asc(t.createdAt)]))
|
..orderBy([(t) => OrderingTerm.asc(t.createdAt)]))
|
||||||
.watch();
|
.watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream<List<GroupMember>> watchMembersByGroupId(String groupId) {
|
|
||||||
// return (select(groupMembers)..where((t) => t.groupId.equals(groupId)))
|
|
||||||
// .watch();
|
|
||||||
// }
|
|
||||||
|
|
||||||
Stream<List<(GroupMember, Contact)>> watchMembersByGroupId(String groupId) {
|
Stream<List<(GroupMember, Contact)>> watchMembersByGroupId(String groupId) {
|
||||||
final query = (select(groupMembers).join([
|
final query = (select(groupMembers).join([
|
||||||
leftOuterJoin(
|
leftOuterJoin(
|
||||||
|
|
@ -101,21 +105,31 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
.watchSingleOrNull();
|
.watchSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> removeOldMessages() {
|
Future<void> purgeMessageTable() async {
|
||||||
// return (update(messages)
|
final allGroups = await select(groups).get();
|
||||||
// ..where(
|
|
||||||
// (t) =>
|
for (final group in allGroups) {
|
||||||
// (t.openedAt.isSmallerThanValue(
|
final deletionTime = DateTime.now().subtract(
|
||||||
// DateTime.now().subtract(const Duration(days: 1)),
|
Duration(
|
||||||
// ) |
|
milliseconds: group.deleteMessagesAfterMilliseconds,
|
||||||
// (t.sendAt.isSmallerThanValue(
|
),
|
||||||
// DateTime.now().subtract(const Duration(days: 3)),
|
);
|
||||||
// ) &
|
final affected = await (delete(messages)
|
||||||
// t.errorWhileSending.equals(true))) &
|
..where(
|
||||||
// t.kind.equals(MessageKind.textMessage.name),
|
(m) =>
|
||||||
// ))
|
m.groupId.equals(group.groupId) &
|
||||||
// .write(const MessagesCompanion(contentJson: Value(null)));
|
// m.messageId.equals(lastMessage.messageId).not() &
|
||||||
// }
|
(m.mediaStored.equals(true) &
|
||||||
|
m.isDeletedFromSender.equals(true) |
|
||||||
|
m.mediaStored.equals(false)) &
|
||||||
|
(m.openedAt.isSmallerThanValue(deletionTime) |
|
||||||
|
(m.isDeletedFromSender.equals(true) &
|
||||||
|
m.createdAt.isSmallerThanValue(deletionTime))),
|
||||||
|
))
|
||||||
|
.go();
|
||||||
|
Log.info('Deleted $affected messages.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Future<List<Message>> getAllMessagesPendingDownloading() {
|
// Future<List<Message>> getAllMessagesPendingDownloading() {
|
||||||
// return (select(messages)
|
// return (select(messages)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class Groups extends Table {
|
||||||
boolean().withDefault(const Constant(false))();
|
boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
IntColumn get deleteMessagesAfterMilliseconds =>
|
IntColumn get deleteMessagesAfterMilliseconds =>
|
||||||
integer().withDefault(const Constant(1000 * 60 * 24))();
|
integer().withDefault(const Constant(1000 * 60 * 60 * 24))();
|
||||||
|
|
||||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -734,7 +734,7 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> {
|
||||||
'delete_messages_after_milliseconds', aliasedName, false,
|
'delete_messages_after_milliseconds', aliasedName, false,
|
||||||
type: DriftSqlType.int,
|
type: DriftSqlType.int,
|
||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
defaultValue: const Constant(1000 * 60 * 24));
|
defaultValue: const Constant(1000 * 60 * 60 * 24));
|
||||||
static const VerificationMeta _createdAtMeta =
|
static const VerificationMeta _createdAtMeta =
|
||||||
const VerificationMeta('createdAt');
|
const VerificationMeta('createdAt');
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -352,5 +352,10 @@
|
||||||
"received": "Empfangen",
|
"received": "Empfangen",
|
||||||
"opened": "Geöffnet",
|
"opened": "Geöffnet",
|
||||||
"waitingForInternet": "Warten auf Internet",
|
"waitingForInternet": "Warten auf Internet",
|
||||||
"editHistory": "Bearbeitungshistorie"
|
"editHistory": "Bearbeitungshistorie",
|
||||||
|
"archivedChats": "Archivierte Chats",
|
||||||
|
"durationShortSecond": "Sek.",
|
||||||
|
"durationShortMinute": "Min.",
|
||||||
|
"durationShortHour": "Std",
|
||||||
|
"durationShortDays": "Tagen"
|
||||||
}
|
}
|
||||||
|
|
@ -508,5 +508,10 @@
|
||||||
"received": "Received",
|
"received": "Received",
|
||||||
"opened": "Opened",
|
"opened": "Opened",
|
||||||
"waitingForInternet": "Waiting for internet",
|
"waitingForInternet": "Waiting for internet",
|
||||||
"editHistory": "Edit history"
|
"editHistory": "Edit history",
|
||||||
|
"archivedChats": "Archived chats",
|
||||||
|
"durationShortSecond": "Sec.",
|
||||||
|
"durationShortMinute": "Min.",
|
||||||
|
"durationShortHour": "Hrs.",
|
||||||
|
"durationShortDays": "Days"
|
||||||
}
|
}
|
||||||
|
|
@ -2155,6 +2155,36 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Edit history'**
|
/// **'Edit history'**
|
||||||
String get editHistory;
|
String get editHistory;
|
||||||
|
|
||||||
|
/// No description provided for @archivedChats.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Archived chats'**
|
||||||
|
String get archivedChats;
|
||||||
|
|
||||||
|
/// No description provided for @durationShortSecond.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Sec.'**
|
||||||
|
String get durationShortSecond;
|
||||||
|
|
||||||
|
/// No description provided for @durationShortMinute.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Min.'**
|
||||||
|
String get durationShortMinute;
|
||||||
|
|
||||||
|
/// No description provided for @durationShortHour.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Hrs.'**
|
||||||
|
String get durationShortHour;
|
||||||
|
|
||||||
|
/// No description provided for @durationShortDays.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Days'**
|
||||||
|
String get durationShortDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -1143,4 +1143,19 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get editHistory => 'Bearbeitungshistorie';
|
String get editHistory => 'Bearbeitungshistorie';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get archivedChats => 'Archivierte Chats';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortSecond => 'Sek.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortMinute => 'Min.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortHour => 'Std';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortDays => 'Tagen';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1136,4 +1136,19 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get editHistory => 'Edit history';
|
String get editHistory => 'Edit history';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get archivedChats => 'Archived chats';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortSecond => 'Sec.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortMinute => 'Min.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortHour => 'Hrs.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get durationShortDays => 'Days';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@ Future<void> insertMediaFileInMessagesTable(
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> startBackgroundMediaUpload(MediaFileService mediaService) async {
|
Future<void> startBackgroundMediaUpload(MediaFileService mediaService) async {
|
||||||
if (mediaService.mediaFile.uploadState == UploadState.initialized) {
|
if (mediaService.mediaFile.uploadState == UploadState.initialized ||
|
||||||
|
mediaService.mediaFile.uploadState == UploadState.preprocessing) {
|
||||||
await mediaService.setUploadState(UploadState.preprocessing);
|
await mediaService.setUploadState(UploadState.preprocessing);
|
||||||
if (!mediaService.tempPath.existsSync()) {
|
if (!mediaService.tempPath.existsSync()) {
|
||||||
await mediaService.compressMedia();
|
await mediaService.compressMedia();
|
||||||
|
|
@ -84,8 +85,10 @@ Future<void> startBackgroundMediaUpload(MediaFileService mediaService) async {
|
||||||
if (!mediaService.uploadRequestPath.existsSync()) {
|
if (!mediaService.uploadRequestPath.existsSync()) {
|
||||||
await _createUploadRequest(mediaService);
|
await _createUploadRequest(mediaService);
|
||||||
}
|
}
|
||||||
|
if (mediaService.uploadRequestPath.existsSync()) {
|
||||||
await mediaService.setUploadState(UploadState.uploading);
|
await mediaService.setUploadState(UploadState.uploading);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mediaService.mediaFile.uploadState == UploadState.uploading) {
|
if (mediaService.mediaFile.uploadState == UploadState.uploading) {
|
||||||
await _uploadUploadRequest(mediaService);
|
await _uploadUploadRequest(mediaService);
|
||||||
|
|
@ -109,8 +112,6 @@ Future<void> _encryptMediaFiles(MediaFileService mediaService) async {
|
||||||
|
|
||||||
mediaService.encryptedPath
|
mediaService.encryptedPath
|
||||||
.writeAsBytesSync(Uint8List.fromList(secretBox.cipherText));
|
.writeAsBytesSync(Uint8List.fromList(secretBox.cipherText));
|
||||||
|
|
||||||
await mediaService.setUploadState(UploadState.uploading);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _createUploadRequest(MediaFileService media) async {
|
Future<void> _createUploadRequest(MediaFileService media) async {
|
||||||
|
|
@ -121,6 +122,11 @@ Future<void> _createUploadRequest(MediaFileService media) async {
|
||||||
final messages =
|
final messages =
|
||||||
await twonlyDB.messagesDao.getMessagesByMediaId(media.mediaFile.mediaId);
|
await twonlyDB.messagesDao.getMessagesByMediaId(media.mediaFile.mediaId);
|
||||||
|
|
||||||
|
if (messages.isEmpty) {
|
||||||
|
// There where no user selected who should receive the image, so waiting with this step...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (final message in messages) {
|
for (final message in messages) {
|
||||||
final groupMembers =
|
final groupMembers =
|
||||||
await twonlyDB.groupsDao.getGroupMembers(message.groupId);
|
await twonlyDB.groupsDao.getGroupMembers(message.groupId);
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ class MediaFileService {
|
||||||
final messages =
|
final messages =
|
||||||
await twonlyDB.messagesDao.getMessagesByMediaId(mediaId);
|
await twonlyDB.messagesDao.getMessagesByMediaId(mediaId);
|
||||||
|
|
||||||
|
// in case messages in empty the file will be deleted, as delete is true by default
|
||||||
|
|
||||||
for (final message in messages) {
|
for (final message in messages) {
|
||||||
if (message.senderId == null) {
|
if (message.senderId == null) {
|
||||||
// Media was send by me
|
// Media was send by me
|
||||||
|
|
|
||||||
|
|
@ -89,27 +89,26 @@ String errorCodeToText(BuildContext context, ErrorCode code) {
|
||||||
case ErrorCode.PlanUpgradeNotYearly:
|
case ErrorCode.PlanUpgradeNotYearly:
|
||||||
return context.lang.errorPlanUpgradeNotYearly;
|
return context.lang.errorPlanUpgradeNotYearly;
|
||||||
}
|
}
|
||||||
return code.toString(); // Fallback for unrecognized keys
|
return code.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
String formatDuration(int seconds) {
|
String formatDuration(BuildContext context, int seconds) {
|
||||||
if (seconds < 60) {
|
if (seconds < 60) {
|
||||||
return '$seconds Sec.';
|
return '$seconds ${context.lang.durationShortSecond}';
|
||||||
} else if (seconds < 3600) {
|
} else if (seconds < 3600) {
|
||||||
final minutes = seconds ~/ 60;
|
final minutes = seconds ~/ 60;
|
||||||
return '$minutes Min.';
|
return '$minutes ${context.lang.durationShortMinute}';
|
||||||
} else if (seconds < 86400) {
|
} else if (seconds < 86400) {
|
||||||
final hours = seconds ~/ 3600;
|
final hours = seconds ~/ 3600;
|
||||||
return '$hours Hrs.'; // Assuming "Stu." is for hours
|
return '$hours ${context.lang.durationShortHour}';
|
||||||
} else {
|
} else {
|
||||||
final days = seconds ~/ 86400;
|
final days = seconds ~/ 86400;
|
||||||
return '$days Days';
|
return '$days ${context.lang.durationShortDays}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDecoration getInputDecoration(BuildContext context, String hintText) {
|
InputDecoration getInputDecoration(BuildContext context, String hintText) {
|
||||||
final primaryColor =
|
final primaryColor = Theme.of(context).colorScheme.primary;
|
||||||
Theme.of(context).colorScheme.primary; // Get the primary color
|
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
class SendToWidget extends StatelessWidget {
|
class SendToWidget extends StatelessWidget {
|
||||||
|
|
@ -40,7 +41,7 @@ class SendToWidget extends StatelessWidget {
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
sendTo,
|
substringBy(sendTo, 20),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: boldTextStyle, // Use the bold text style here
|
style: boldTextStyle, // Use the bold text style here
|
||||||
),
|
),
|
||||||
|
|
@ -48,9 +49,4 @@ class SendToWidget extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getContactDisplayName(String contact) {
|
|
||||||
// Replace this with your actual logic to get the contact display name
|
|
||||||
return contact; // Placeholder implementation
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:hashlib/random.dart';
|
import 'package:hashlib/random.dart';
|
||||||
import 'package:screenshot/screenshot.dart';
|
import 'package:screenshot/screenshot.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||||
|
|
@ -75,8 +76,8 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
if (widget.imageBytesFuture != null) {
|
if (widget.imageBytesFuture != null) {
|
||||||
loadImage(widget.imageBytesFuture!);
|
loadImage(widget.imageBytesFuture!);
|
||||||
} else {
|
} else {
|
||||||
if (widget.mediaFileService.storedPath.existsSync()) {
|
if (widget.mediaFileService.tempPath.existsSync()) {
|
||||||
loadImage(widget.mediaFileService.storedPath.readAsBytes());
|
loadImage(widget.mediaFileService.tempPath.readAsBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -482,7 +483,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
label: Text(
|
label: Text(
|
||||||
(widget.sendToGroup == null)
|
(widget.sendToGroup == null)
|
||||||
? context.lang.shareImagedEditorShareWith
|
? context.lang.shareImagedEditorShareWith
|
||||||
: widget.sendToGroup!.groupName,
|
: substringBy(widget.sendToGroup!.groupName, 15),
|
||||||
style: const TextStyle(fontSize: 17),
|
style: const TextStyle(fontSize: 17),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/chats/chat_list_components/group_list_item.dart';
|
import 'package:twonly/src/views/chats/chat_list_components/group_list_item.dart';
|
||||||
|
|
||||||
class ArchivedChatsView extends StatefulWidget {
|
class ArchivedChatsView extends StatefulWidget {
|
||||||
|
|
@ -40,7 +41,7 @@ class _ArchivedChatsViewState extends State<ArchivedChatsView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Archivierte Chats'),
|
title: Text(context.lang.archivedChats),
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: _groupsArchived.map((group) {
|
children: _groupsArchived.map((group) {
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
if (_groupsArchived.isEmpty) return Container();
|
if (_groupsArchived.isEmpty) return Container();
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
'Archivierte Chats (${_groupsArchived.length})',
|
'${context.lang.archivedChats} (${_groupsArchived.length})',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(fontSize: 13),
|
style: const TextStyle(fontSize: 13),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ 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:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
|
@ -208,10 +209,12 @@ class _UserListItem extends State<GroupListItem> {
|
||||||
group: widget.group,
|
group: widget.group,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
widget.group.groupName,
|
substringBy(widget.group.groupName, 30),
|
||||||
),
|
),
|
||||||
subtitle: (_currentMessage == null)
|
subtitle: (_currentMessage == null)
|
||||||
|
? (widget.group.totalMediaCounter == 0)
|
||||||
? Text(context.lang.chatsTapToSend)
|
? Text(context.lang.chatsTapToSend)
|
||||||
|
: LastMessageTime(dateTime: widget.group.lastMessageExchange)
|
||||||
: Row(
|
: Row(
|
||||||
children: [
|
children: [
|
||||||
MessageSendStateIcon(
|
MessageSendStateIcon(
|
||||||
|
|
@ -222,7 +225,7 @@ class _UserListItem extends State<GroupListItem> {
|
||||||
const Text('•'),
|
const Text('•'),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
if (_currentMessage != null)
|
if (_currentMessage != null)
|
||||||
LastMessageTime(message: _currentMessage!),
|
LastMessageTime(message: _currentMessage),
|
||||||
FlameCounterWidget(
|
FlameCounterWidget(
|
||||||
groupId: widget.group.groupId,
|
groupId: widget.group.groupId,
|
||||||
prefix: true,
|
prefix: true,
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
class LastMessageTime extends StatefulWidget {
|
class LastMessageTime extends StatefulWidget {
|
||||||
const LastMessageTime({required this.message, super.key});
|
const LastMessageTime({this.message, this.dateTime, super.key});
|
||||||
|
|
||||||
final Message message;
|
final Message? message;
|
||||||
|
final DateTime? dateTime;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<LastMessageTime> createState() => _LastMessageTimeState();
|
State<LastMessageTime> createState() => _LastMessageTimeState();
|
||||||
|
|
@ -24,12 +25,17 @@ class _LastMessageTimeState extends State<LastMessageTime> {
|
||||||
// Change the color every 200 milliseconds
|
// Change the color every 200 milliseconds
|
||||||
updateTime =
|
updateTime =
|
||||||
Timer.periodic(const Duration(milliseconds: 500), (timer) async {
|
Timer.periodic(const Duration(milliseconds: 500), (timer) async {
|
||||||
|
if (widget.message != null) {
|
||||||
final lastAction = await twonlyDB.messagesDao
|
final lastAction = await twonlyDB.messagesDao
|
||||||
.getLastMessageAction(widget.message.messageId);
|
.getLastMessageAction(widget.message!.messageId);
|
||||||
setState(() {
|
|
||||||
lastMessageInSeconds = DateTime.now()
|
lastMessageInSeconds = DateTime.now()
|
||||||
.difference(lastAction?.actionAt ?? widget.message.createdAt)
|
.difference(lastAction?.actionAt ?? widget.message!.createdAt)
|
||||||
.inSeconds;
|
.inSeconds;
|
||||||
|
} else if (widget.dateTime != null) {
|
||||||
|
lastMessageInSeconds =
|
||||||
|
DateTime.now().difference(widget.dateTime!).inSeconds;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
if (lastMessageInSeconds < 0) {
|
if (lastMessageInSeconds < 0) {
|
||||||
lastMessageInSeconds = 0;
|
lastMessageInSeconds = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +52,7 @@ class _LastMessageTimeState extends State<LastMessageTime> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
formatDuration(lastMessageInSeconds),
|
formatDuration(context, lastMessageInSeconds),
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/model/memory_item.model.dart';
|
import 'package:twonly/src/model/memory_item.model.dart';
|
||||||
|
|
@ -241,7 +242,9 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(group.groupName),
|
Text(
|
||||||
|
substringBy(widget.group.groupName, 20),
|
||||||
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
VerifiedShield(key: verifyShieldKey, group: group),
|
VerifiedShield(key: verifyShieldKey, group: group),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,16 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
case MessageSendState.sending:
|
case MessageSendState.sending:
|
||||||
icon = getLoaderIcon(color);
|
icon = getLoaderIcon(color);
|
||||||
text = context.lang.messageSendState_Sending;
|
text = context.lang.messageSendState_Sending;
|
||||||
|
|
||||||
|
if (mediaFile != null) {
|
||||||
|
if (mediaFile.uploadState == UploadState.uploadLimitReached) {
|
||||||
|
text = 'Upload Limit erreicht';
|
||||||
|
}
|
||||||
|
if (mediaFile.uploadState == UploadState.preprocessing) {
|
||||||
|
text = 'Wird verarbeitet';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hasLoader = true;
|
hasLoader = true;
|
||||||
case MessageSendState.receiving:
|
case MessageSendState.receiving:
|
||||||
icon = getLoaderIcon(color);
|
icon = getLoaderIcon(color);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ class _ContactViewState extends State<ContactView> {
|
||||||
Future<void> handleUserRemoveRequest(Contact contact) async {
|
Future<void> handleUserRemoveRequest(Contact contact) async {
|
||||||
final remove = await showAlertDialog(
|
final remove = await showAlertDialog(
|
||||||
context,
|
context,
|
||||||
context.lang.contactRemoveTitle(getContactDisplayName(contact)),
|
context.lang
|
||||||
|
.contactRemoveTitle(getContactDisplayName(contact, maxLength: 20)),
|
||||||
context.lang.contactRemoveBody,
|
context.lang.contactRemoveBody,
|
||||||
);
|
);
|
||||||
if (remove) {
|
if (remove) {
|
||||||
|
|
@ -124,7 +125,7 @@ class _ContactViewState extends State<ContactView> {
|
||||||
child: VerifiedShield(key: GlobalKey(), contact: contact),
|
child: VerifiedShield(key: GlobalKey(), contact: contact),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
getContactDisplayName(contact),
|
getContactDisplayName(contact, maxLength: 20),
|
||||||
style: const TextStyle(fontSize: 20),
|
style: const TextStyle(fontSize: 20),
|
||||||
),
|
),
|
||||||
// if (flameCounter > 0)
|
// if (flameCounter > 0)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import 'package:photo_view/photo_view_gallery.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/model/memory_item.model.dart';
|
import 'package:twonly/src/model/memory_item.model.dart';
|
||||||
|
import 'package:twonly/src/services/api/mediafiles/upload.service.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/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';
|
||||||
|
|
@ -117,12 +119,28 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
|
||||||
FilledButton.icon(
|
FilledButton.icon(
|
||||||
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
onPressed: () async {
|
onPressed: () 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.tempPath.path);
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => ShareImageEditorView(
|
builder: (context) => ShareImageEditorView(
|
||||||
mediaFileService: widget
|
mediaFileService: newMediaService,
|
||||||
.galleryItems[currentIndex].mediaService,
|
|
||||||
sharedFromGallery: true,
|
sharedFromGallery: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ Future<String?> showDisplayNameChangeDialog(
|
||||||
content: TextField(
|
content: TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
|
maxLength: 30,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: context.lang.settingsProfileEditDisplayNameNew,
|
hintText: context.lang.settingsProfileEditDisplayNameNew,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
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/globals.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/components/avatar_icon.component.dart';
|
import 'package:twonly/src/views/components/avatar_icon.component.dart';
|
||||||
import 'package:twonly/src/views/components/better_list_title.dart';
|
import 'package:twonly/src/views/components/better_list_title.dart';
|
||||||
|
|
@ -63,7 +64,7 @@ class _SettingsMainViewState extends State<SettingsMainView> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
gUser.displayName,
|
substringBy(gUser.displayName, 27),
|
||||||
style: const TextStyle(fontSize: 20),
|
style: const TextStyle(fontSize: 20),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue