updating profile and minor issues

This commit is contained in:
otsmr 2025-10-26 22:49:36 +01:00
parent 746887b845
commit 7fe0f16a5c
15 changed files with 124 additions and 176 deletions

View file

@ -1,4 +1,5 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/tables/contacts.table.dart';
import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/database/twonly_database_old.dart' as old; import 'package:twonly/src/database/twonly_database_old.dart' as old;
@ -45,6 +46,15 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
final contact = await getContactByUserId(userId).getSingleOrNull(); final contact = await getContactByUserId(userId).getSingleOrNull();
if (contact != null) { if (contact != null) {
await updatePushUser(contact); await updatePushUser(contact);
final group = await twonlyDB.groupsDao.getDirectChat(userId);
if (group != null) {
await twonlyDB.groupsDao.updateGroup(
group.groupId,
GroupsCompanion(
groupName: Value(getContactDisplayName(contact)),
),
);
}
} }
} }
} }

View file

@ -26,8 +26,7 @@ class Messages extends Table {
BlobColumn get downloadToken => blob().nullable()(); BlobColumn get downloadToken => blob().nullable()();
TextColumn get quotesMessageId => TextColumn get quotesMessageId => text().nullable()();
text().nullable().references(Messages, #messageId)();
BoolColumn get isDeletedFromSender => BoolColumn get isDeletedFromSender =>
boolean().withDefault(const Constant(false))(); boolean().withDefault(const Constant(false))();

View file

@ -2265,10 +2265,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
@override @override
late final GeneratedColumn<String> quotesMessageId = GeneratedColumn<String>( late final GeneratedColumn<String> quotesMessageId = GeneratedColumn<String>(
'quotes_message_id', aliasedName, true, 'quotes_message_id', aliasedName, true,
type: DriftSqlType.string, type: DriftSqlType.string, requiredDuringInsert: false);
requiredDuringInsert: false,
defaultConstraints: GeneratedColumn.constraintIsAlways(
'REFERENCES messages (message_id)'));
static const VerificationMeta _isDeletedFromSenderMeta = static const VerificationMeta _isDeletedFromSenderMeta =
const VerificationMeta('isDeletedFromSender'); const VerificationMeta('isDeletedFromSender');
@override @override
@ -8207,21 +8204,6 @@ final class $$MessagesTableReferences
manager.$state.copyWith(prefetchedData: [item])); manager.$state.copyWith(prefetchedData: [item]));
} }
static $MessagesTable _quotesMessageIdTable(_$TwonlyDB db) =>
db.messages.createAlias($_aliasNameGenerator(
db.messages.quotesMessageId, db.messages.messageId));
$$MessagesTableProcessedTableManager? get quotesMessageId {
final $_column = $_itemColumn<String>('quotes_message_id');
if ($_column == null) return null;
final manager = $$MessagesTableTableManager($_db, $_db.messages)
.filter((f) => f.messageId.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_quotesMessageIdTable($_db));
if (item == null) return manager;
return ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
static MultiTypedResultKey<$MessageHistoriesTable, List<MessageHistory>> static MultiTypedResultKey<$MessageHistoriesTable, List<MessageHistory>>
_messageHistoriesRefsTable(_$TwonlyDB db) => _messageHistoriesRefsTable(_$TwonlyDB db) =>
MultiTypedResultKey.fromTable(db.messageHistories, MultiTypedResultKey.fromTable(db.messageHistories,
@ -8315,6 +8297,10 @@ class $$MessagesTableFilterComposer
ColumnFilters<Uint8List> get downloadToken => $composableBuilder( ColumnFilters<Uint8List> get downloadToken => $composableBuilder(
column: $table.downloadToken, builder: (column) => ColumnFilters(column)); column: $table.downloadToken, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get quotesMessageId => $composableBuilder(
column: $table.quotesMessageId,
builder: (column) => ColumnFilters(column));
ColumnFilters<bool> get isDeletedFromSender => $composableBuilder( ColumnFilters<bool> get isDeletedFromSender => $composableBuilder(
column: $table.isDeletedFromSender, column: $table.isDeletedFromSender,
builder: (column) => ColumnFilters(column)); builder: (column) => ColumnFilters(column));
@ -8394,26 +8380,6 @@ class $$MessagesTableFilterComposer
return composer; return composer;
} }
$$MessagesTableFilterComposer get quotesMessageId {
final $$MessagesTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.quotesMessageId,
referencedTable: $db.messages,
getReferencedColumn: (t) => t.messageId,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
$$MessagesTableFilterComposer(
$db: $db,
$table: $db.messages,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
Expression<bool> messageHistoriesRefs( Expression<bool> messageHistoriesRefs(
Expression<bool> Function($$MessageHistoriesTableFilterComposer f) f) { Expression<bool> Function($$MessageHistoriesTableFilterComposer f) f) {
final $$MessageHistoriesTableFilterComposer composer = $composerBuilder( final $$MessageHistoriesTableFilterComposer composer = $composerBuilder(
@ -8524,6 +8490,10 @@ class $$MessagesTableOrderingComposer
column: $table.downloadToken, column: $table.downloadToken,
builder: (column) => ColumnOrderings(column)); builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get quotesMessageId => $composableBuilder(
column: $table.quotesMessageId,
builder: (column) => ColumnOrderings(column));
ColumnOrderings<bool> get isDeletedFromSender => $composableBuilder( ColumnOrderings<bool> get isDeletedFromSender => $composableBuilder(
column: $table.isDeletedFromSender, column: $table.isDeletedFromSender,
builder: (column) => ColumnOrderings(column)); builder: (column) => ColumnOrderings(column));
@ -8602,26 +8572,6 @@ class $$MessagesTableOrderingComposer
)); ));
return composer; return composer;
} }
$$MessagesTableOrderingComposer get quotesMessageId {
final $$MessagesTableOrderingComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.quotesMessageId,
referencedTable: $db.messages,
getReferencedColumn: (t) => t.messageId,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
$$MessagesTableOrderingComposer(
$db: $db,
$table: $db.messages,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
} }
class $$MessagesTableAnnotationComposer class $$MessagesTableAnnotationComposer
@ -8648,6 +8598,9 @@ class $$MessagesTableAnnotationComposer
GeneratedColumn<Uint8List> get downloadToken => $composableBuilder( GeneratedColumn<Uint8List> get downloadToken => $composableBuilder(
column: $table.downloadToken, builder: (column) => column); column: $table.downloadToken, builder: (column) => column);
GeneratedColumn<String> get quotesMessageId => $composableBuilder(
column: $table.quotesMessageId, builder: (column) => column);
GeneratedColumn<bool> get isDeletedFromSender => $composableBuilder( GeneratedColumn<bool> get isDeletedFromSender => $composableBuilder(
column: $table.isDeletedFromSender, builder: (column) => column); column: $table.isDeletedFromSender, builder: (column) => column);
@ -8726,26 +8679,6 @@ class $$MessagesTableAnnotationComposer
return composer; return composer;
} }
$$MessagesTableAnnotationComposer get quotesMessageId {
final $$MessagesTableAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.quotesMessageId,
referencedTable: $db.messages,
getReferencedColumn: (t) => t.messageId,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
$$MessagesTableAnnotationComposer(
$db: $db,
$table: $db.messages,
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
Expression<T> messageHistoriesRefs<T extends Object>( Expression<T> messageHistoriesRefs<T extends Object>(
Expression<T> Function($$MessageHistoriesTableAnnotationComposer a) f) { Expression<T> Function($$MessageHistoriesTableAnnotationComposer a) f) {
final $$MessageHistoriesTableAnnotationComposer composer = $composerBuilder( final $$MessageHistoriesTableAnnotationComposer composer = $composerBuilder(
@ -8846,7 +8779,6 @@ class $$MessagesTableTableManager extends RootTableManager<
{bool groupId, {bool groupId,
bool senderId, bool senderId,
bool mediaId, bool mediaId,
bool quotesMessageId,
bool messageHistoriesRefs, bool messageHistoriesRefs,
bool reactionsRefs, bool reactionsRefs,
bool receiptsRefs, bool receiptsRefs,
@ -8941,7 +8873,6 @@ class $$MessagesTableTableManager extends RootTableManager<
{groupId = false, {groupId = false,
senderId = false, senderId = false,
mediaId = false, mediaId = false,
quotesMessageId = false,
messageHistoriesRefs = false, messageHistoriesRefs = false,
reactionsRefs = false, reactionsRefs = false,
receiptsRefs = false, receiptsRefs = false,
@ -8997,17 +8928,6 @@ class $$MessagesTableTableManager extends RootTableManager<
$$MessagesTableReferences._mediaIdTable(db).mediaId, $$MessagesTableReferences._mediaIdTable(db).mediaId,
) as T; ) as T;
} }
if (quotesMessageId) {
state = state.withJoin(
currentTable: table,
currentColumn: table.quotesMessageId,
referencedTable:
$$MessagesTableReferences._quotesMessageIdTable(db),
referencedColumn: $$MessagesTableReferences
._quotesMessageIdTable(db)
.messageId,
) as T;
}
return state; return state;
}, },
@ -9086,7 +9006,6 @@ typedef $$MessagesTableProcessedTableManager = ProcessedTableManager<
{bool groupId, {bool groupId,
bool senderId, bool senderId,
bool mediaId, bool mediaId,
bool quotesMessageId,
bool messageHistoriesRefs, bool messageHistoriesRefs,
bool reactionsRefs, bool reactionsRefs,
bool receiptsRefs, bool receiptsRefs,

View file

@ -341,5 +341,6 @@
"reportUserReason": "Meldegrund", "reportUserReason": "Meldegrund",
"reportUser": "Benutzer melden", "reportUser": "Benutzer melden",
"newDeviceRegistered": "Du hast dich auf einem anderen Gerät angemeldet. Daher wurdest du hier abgemeldet.", "newDeviceRegistered": "Du hast dich auf einem anderen Gerät angemeldet. Daher wurdest du hier abgemeldet.",
"tabToRemoveEmoji": "Tippen um zu entfernen" "tabToRemoveEmoji": "Tippen um zu entfernen",
"quotedMessageWasDeleted": "Die zitierte Nachricht wurde gelöscht."
} }

View file

@ -497,5 +497,6 @@
"reportUserReason": "Reporting reason", "reportUserReason": "Reporting reason",
"reportUser": "Report user", "reportUser": "Report user",
"newDeviceRegistered": "You have logged in on another device. You have therefore been logged out here.", "newDeviceRegistered": "You have logged in on another device. You have therefore been logged out here.",
"tabToRemoveEmoji": "Tab to remove" "tabToRemoveEmoji": "Tab to remove",
"quotedMessageWasDeleted": "The quoted message has been deleted."
} }

View file

@ -2089,6 +2089,12 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Tab to remove'** /// **'Tab to remove'**
String get tabToRemoveEmoji; String get tabToRemoveEmoji;
/// No description provided for @quotedMessageWasDeleted.
///
/// In en, this message translates to:
/// **'The quoted message has been deleted.'**
String get quotedMessageWasDeleted;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate

View file

@ -1109,4 +1109,8 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get tabToRemoveEmoji => 'Tippen um zu entfernen'; String get tabToRemoveEmoji => 'Tippen um zu entfernen';
@override
String get quotedMessageWasDeleted =>
'Die zitierte Nachricht wurde gelöscht.';
} }

View file

@ -1103,4 +1103,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get tabToRemoveEmoji => 'Tab to remove'; String get tabToRemoveEmoji => 'Tab to remove';
@override
String get quotedMessageWasDeleted => 'The quoted message has been deleted.';
} }

View file

@ -214,6 +214,8 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
bool onlyReturnEncryptedData = false, bool onlyReturnEncryptedData = false,
String? messageId, String? messageId,
}) async { }) async {
encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter);
final response = pb.Message() final response = pb.Message()
..type = pb.Message_Type.CIPHERTEXT ..type = pb.Message_Type.CIPHERTEXT
..encryptedContent = encryptedContent.writeToBuffer(); ..encryptedContent = encryptedContent.writeToBuffer();

View file

@ -106,19 +106,21 @@ Future<int?> checkForProfileUpdate(
) async { ) async {
int? senderProfileCounter; int? senderProfileCounter;
if (content.hasSenderProfileCounter() && !content.hasContactUpdate()) { if (content.hasSenderProfileCounter()) {
senderProfileCounter = content.senderProfileCounter.toInt(); senderProfileCounter = content.senderProfileCounter.toInt();
final contact = await twonlyDB.contactsDao if (!content.hasContactUpdate()) {
.getContactByUserId(fromUserId) final contact = await twonlyDB.contactsDao
.getSingleOrNull(); .getContactByUserId(fromUserId)
if (contact != null) { .getSingleOrNull();
if (contact.senderProfileCounter < senderProfileCounter) { if (contact != null) {
await sendCipherText( if (contact.senderProfileCounter < senderProfileCounter) {
fromUserId, await sendCipherText(
EncryptedContent() fromUserId,
..contactUpdate = (EncryptedContent_ContactUpdate() EncryptedContent()
..type = EncryptedContent_ContactUpdate_Type.REQUEST), ..contactUpdate = (EncryptedContent_ContactUpdate()
); ..type = EncryptedContent_ContactUpdate_Type.REQUEST),
);
}
} }
} }
} }

View file

@ -277,7 +277,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
return Transform.translate( return Transform.translate(
offset: Offset( offset: Offset(
(focusedScrollItem == i) (focusedScrollItem == i)
? (chatMessage.quotesMessageId == null) ? (chatMessage.senderId == null)
? -8 ? -8
: 8 : 8
: 0, : 0,

View file

@ -57,7 +57,7 @@ class ChatTextEntry extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
if (measureTextWidth(text) > 270) if (measureTextWidth(text) > 270 || message.quotesMessageId != null)
Expanded( Expanded(
child: BetterText(text: text), child: BetterText(text: text),
) )

View file

@ -76,12 +76,14 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final icons = <Widget>[]; var icons = <Widget>[];
var text = ''; var text = '';
Widget? textWidget; Widget? textWidget;
textWidget = null; textWidget = null;
final kindsAlreadyShown = HashSet<MessageType>(); final kindsAlreadyShown = HashSet<MessageType>();
var hasLoader = false;
for (final message in widget.messages) { for (final message in widget.messages) {
if (icons.length == 2) break; if (icons.length == 2) break;
if (kindsAlreadyShown.contains(message.type)) continue; if (kindsAlreadyShown.contains(message.type)) continue;
@ -130,6 +132,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
if (mediaFile.downloadState == DownloadState.downloading) { if (mediaFile.downloadState == DownloadState.downloading) {
text = context.lang.messageSendState_Loading; text = context.lang.messageSendState_Loading;
icon = getLoaderIcon(color); icon = getLoaderIcon(color);
hasLoader = true;
} }
} }
case MessageSendState.send: case MessageSendState.send:
@ -139,9 +142,11 @@ 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;
hasLoader = true;
case MessageSendState.receiving: case MessageSendState.receiving:
icon = getLoaderIcon(color); icon = getLoaderIcon(color);
text = context.lang.messageSendState_Received; text = context.lang.messageSendState_Received;
hasLoader = true;
} }
if (message.mediaStored) { if (message.mediaStored) {
@ -165,6 +170,11 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
} }
} }
if (hasLoader) {
icons = [icon];
break;
}
if (message.type == MessageType.media) { if (message.type == MessageType.media) {
icons.insert(0, icon); icons.insert(0, icon);
} else { } else {

View file

@ -150,53 +150,58 @@ class _ResponsePreviewState extends State<ResponsePreview> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (message == null) return Container();
String? subtitle; String? subtitle;
var color = const Color.fromARGB(233, 68, 137, 255);
var username = '';
if (message!.type == MessageType.text) { if (message != null) {
if (message!.content != null) { if (message!.type == MessageType.text) {
subtitle = truncateString(message!.content!); if (message!.content != null) {
subtitle = truncateString(message!.content!);
}
}
if (message!.type == MessageType.media && mediaService != null) {
subtitle = mediaService!.mediaFile.type == MediaType.video
? context.lang.video
: context.lang.image;
} }
}
if (message!.type == MessageType.media && mediaService != null) {
subtitle = mediaService!.mediaFile.type == MediaType.video
? context.lang.video
: context.lang.image;
}
var username = context.lang.you; username = context.lang.you;
if (message!.senderId != null) { if (message!.senderId != null) {
username = message!.senderId.toString(); username = message!.senderId.toString();
} }
final color = getMessageColor(message!); color = getMessageColor(message!);
if (!message!.mediaStored) { if (!message!.mediaStored) {
return Container( return Container(
padding: widget.showBorder padding: widget.showBorder
? const EdgeInsets.only(left: 10, right: 10) ? const EdgeInsets.only(left: 10, right: 10)
: const EdgeInsets.symmetric(horizontal: 5), : const EdgeInsets.symmetric(horizontal: 5),
decoration: (widget.showBorder) decoration: (widget.showBorder)
? BoxDecoration( ? BoxDecoration(
border: Border( border: Border(
left: BorderSide( left: BorderSide(
color: color, color: color,
width: 2, width: 2,
),
), ),
), )
) : null,
: null, child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text( username,
username, style: const TextStyle(fontWeight: FontWeight.bold),
style: const TextStyle(fontWeight: FontWeight.bold), ),
), if (subtitle != null) Text(subtitle),
if (subtitle != null) Text(subtitle), ],
], ),
), );
); }
} else {
username = context.lang.quotedMessageWasDeleted;
} }
return Container( return Container(
@ -227,7 +232,11 @@ class _ResponsePreviewState extends State<ResponsePreview> {
if (mediaService != null) if (mediaService != null)
SizedBox( SizedBox(
height: widget.showBorder ? 100 : 210, height: widget.showBorder ? 100 : 210,
child: Image.file(mediaService!.thumbnailPath), child: Image.file(
mediaService!.mediaFile.type == MediaType.video
? mediaService!.thumbnailPath
: mediaService!.storedPath,
),
), ),
], ],
), ),

View file

@ -469,27 +469,6 @@ class _MediaViewerViewState extends State<MediaViewerView> {
child: Image.file( child: Image.file(
currentMedia!.tempPath, currentMedia!.tempPath,
fit: BoxFit.contain, fit: BoxFit.contain,
frameBuilder: (
context,
child,
frame,
wasSynchronouslyLoaded,
) {
if (wasSynchronouslyLoaded) return child;
return AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: frame != null
? child
: Container(
height: 60,
color: Colors.transparent,
width: 60,
child: const CircularProgressIndicator(
strokeWidth: 2,
),
),
);
},
), ),
), ),
], ],
@ -534,13 +513,16 @@ class _MediaViewerViewState extends State<MediaViewerView> {
], ],
), ),
), ),
if (currentMedia?.mediaFile.downloadState != DownloadState.ready) if (currentMedia != null &&
currentMedia?.mediaFile.downloadState != DownloadState.ready)
const Positioned.fill( const Positioned.fill(
child: Center( child: Center(
child: SizedBox( child: SizedBox(
height: 60, height: 60,
width: 60, width: 60,
child: CircularProgressIndicator(strokeWidth: 6), child: CircularProgressIndicator(
strokeWidth: 6,
),
), ),
), ),
), ),