✨ Mark message as read
This commit is contained in:
parent
dd50cfd2e9
commit
93267eb327
@ -10,7 +10,20 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase(super.e);
|
AppDatabase(super.e);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 2;
|
||||||
|
|
||||||
|
@override
|
||||||
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
|
onCreate: (Migrator m) async {
|
||||||
|
await m.createAll();
|
||||||
|
},
|
||||||
|
onUpgrade: (Migrator m, int from, int to) async {
|
||||||
|
if (from < 2) {
|
||||||
|
// Add isRead column with default value false
|
||||||
|
await m.addColumn(chatMessages, chatMessages.isRead);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Methods for chat messages
|
// Methods for chat messages
|
||||||
Future<List<ChatMessage>> getMessagesForRoom(
|
Future<List<ChatMessage>> getMessagesForRoom(
|
||||||
@ -40,6 +53,12 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
)).write(ChatMessagesCompanion(status: Value(status)));
|
)).write(ChatMessagesCompanion(status: Value(status)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> markMessageAsRead(String id) {
|
||||||
|
return (update(chatMessages)..where(
|
||||||
|
(m) => m.id.equals(id),
|
||||||
|
)).write(ChatMessagesCompanion(isRead: const Value(true)));
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> deleteMessage(String id) {
|
Future<int> deleteMessage(String id) {
|
||||||
return (delete(chatMessages)..where((m) => m.id.equals(id))).go();
|
return (delete(chatMessages)..where((m) => m.id.equals(id))).go();
|
||||||
}
|
}
|
||||||
@ -55,6 +74,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
data: Value(jsonEncode(message.data)),
|
data: Value(jsonEncode(message.data)),
|
||||||
createdAt: Value(message.createdAt),
|
createdAt: Value(message.createdAt),
|
||||||
status: Value(message.status),
|
status: Value(message.status),
|
||||||
|
isRead: Value(message.isRead),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +88,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
createdAt: dbMessage.createdAt,
|
createdAt: dbMessage.createdAt,
|
||||||
status: dbMessage.status,
|
status: dbMessage.status,
|
||||||
nonce: dbMessage.nonce,
|
nonce: dbMessage.nonce,
|
||||||
|
isRead: dbMessage.isRead,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,19 @@ class $ChatMessagesTable extends ChatMessages
|
|||||||
type: DriftSqlType.int,
|
type: DriftSqlType.int,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
).withConverter<MessageStatus>($ChatMessagesTable.$converterstatus);
|
).withConverter<MessageStatus>($ChatMessagesTable.$converterstatus);
|
||||||
|
static const VerificationMeta _isReadMeta = const VerificationMeta('isRead');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<bool> isRead = GeneratedColumn<bool>(
|
||||||
|
'is_read',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: DriftSqlType.bool,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
|
'CHECK ("is_read" IN (0, 1))',
|
||||||
|
),
|
||||||
|
defaultValue: const Constant(false),
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [
|
List<GeneratedColumn> get $columns => [
|
||||||
id,
|
id,
|
||||||
@ -97,6 +110,7 @@ class $ChatMessagesTable extends ChatMessages
|
|||||||
data,
|
data,
|
||||||
createdAt,
|
createdAt,
|
||||||
status,
|
status,
|
||||||
|
isRead,
|
||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@ -159,6 +173,12 @@ class $ChatMessagesTable extends ChatMessages
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_createdAtMeta);
|
context.missing(_createdAtMeta);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('is_read')) {
|
||||||
|
context.handle(
|
||||||
|
_isReadMeta,
|
||||||
|
isRead.isAcceptableOrUnknown(data['is_read']!, _isReadMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,6 +227,11 @@ class $ChatMessagesTable extends ChatMessages
|
|||||||
data['${effectivePrefix}status'],
|
data['${effectivePrefix}status'],
|
||||||
)!,
|
)!,
|
||||||
),
|
),
|
||||||
|
isRead:
|
||||||
|
attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
data['${effectivePrefix}is_read'],
|
||||||
|
)!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +253,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
final String data;
|
final String data;
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
final MessageStatus status;
|
final MessageStatus status;
|
||||||
|
final bool isRead;
|
||||||
const ChatMessage({
|
const ChatMessage({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.roomId,
|
required this.roomId,
|
||||||
@ -237,6 +263,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
required this.data,
|
required this.data,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.status,
|
required this.status,
|
||||||
|
required this.isRead,
|
||||||
});
|
});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
@ -257,6 +284,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
$ChatMessagesTable.$converterstatus.toSql(status),
|
$ChatMessagesTable.$converterstatus.toSql(status),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
map['is_read'] = Variable<bool>(isRead);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +302,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
data: Value(data),
|
data: Value(data),
|
||||||
createdAt: Value(createdAt),
|
createdAt: Value(createdAt),
|
||||||
status: Value(status),
|
status: Value(status),
|
||||||
|
isRead: Value(isRead),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +322,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
status: $ChatMessagesTable.$converterstatus.fromJson(
|
status: $ChatMessagesTable.$converterstatus.fromJson(
|
||||||
serializer.fromJson<int>(json['status']),
|
serializer.fromJson<int>(json['status']),
|
||||||
),
|
),
|
||||||
|
isRead: serializer.fromJson<bool>(json['isRead']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
@ -309,6 +339,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
'status': serializer.toJson<int>(
|
'status': serializer.toJson<int>(
|
||||||
$ChatMessagesTable.$converterstatus.toJson(status),
|
$ChatMessagesTable.$converterstatus.toJson(status),
|
||||||
),
|
),
|
||||||
|
'isRead': serializer.toJson<bool>(isRead),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,6 +352,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
String? data,
|
String? data,
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
MessageStatus? status,
|
MessageStatus? status,
|
||||||
|
bool? isRead,
|
||||||
}) => ChatMessage(
|
}) => ChatMessage(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
roomId: roomId ?? this.roomId,
|
roomId: roomId ?? this.roomId,
|
||||||
@ -330,6 +362,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
data: data ?? this.data,
|
data: data ?? this.data,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
|
isRead: isRead ?? this.isRead,
|
||||||
);
|
);
|
||||||
ChatMessage copyWithCompanion(ChatMessagesCompanion data) {
|
ChatMessage copyWithCompanion(ChatMessagesCompanion data) {
|
||||||
return ChatMessage(
|
return ChatMessage(
|
||||||
@ -341,6 +374,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
data: data.data.present ? data.data.value : this.data,
|
data: data.data.present ? data.data.value : this.data,
|
||||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||||
status: data.status.present ? data.status.value : this.status,
|
status: data.status.present ? data.status.value : this.status,
|
||||||
|
isRead: data.isRead.present ? data.isRead.value : this.isRead,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +388,8 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
..write('nonce: $nonce, ')
|
..write('nonce: $nonce, ')
|
||||||
..write('data: $data, ')
|
..write('data: $data, ')
|
||||||
..write('createdAt: $createdAt, ')
|
..write('createdAt: $createdAt, ')
|
||||||
..write('status: $status')
|
..write('status: $status, ')
|
||||||
|
..write('isRead: $isRead')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
@ -369,6 +404,7 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
data,
|
data,
|
||||||
createdAt,
|
createdAt,
|
||||||
status,
|
status,
|
||||||
|
isRead,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@ -381,7 +417,8 @@ class ChatMessage extends DataClass implements Insertable<ChatMessage> {
|
|||||||
other.nonce == this.nonce &&
|
other.nonce == this.nonce &&
|
||||||
other.data == this.data &&
|
other.data == this.data &&
|
||||||
other.createdAt == this.createdAt &&
|
other.createdAt == this.createdAt &&
|
||||||
other.status == this.status);
|
other.status == this.status &&
|
||||||
|
other.isRead == this.isRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
||||||
@ -393,6 +430,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
final Value<String> data;
|
final Value<String> data;
|
||||||
final Value<DateTime> createdAt;
|
final Value<DateTime> createdAt;
|
||||||
final Value<MessageStatus> status;
|
final Value<MessageStatus> status;
|
||||||
|
final Value<bool> isRead;
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const ChatMessagesCompanion({
|
const ChatMessagesCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
@ -403,6 +441,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
this.data = const Value.absent(),
|
this.data = const Value.absent(),
|
||||||
this.createdAt = const Value.absent(),
|
this.createdAt = const Value.absent(),
|
||||||
this.status = const Value.absent(),
|
this.status = const Value.absent(),
|
||||||
|
this.isRead = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
});
|
});
|
||||||
ChatMessagesCompanion.insert({
|
ChatMessagesCompanion.insert({
|
||||||
@ -414,6 +453,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
required String data,
|
required String data,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required MessageStatus status,
|
required MessageStatus status,
|
||||||
|
this.isRead = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
roomId = Value(roomId),
|
roomId = Value(roomId),
|
||||||
@ -430,6 +470,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
Expression<String>? data,
|
Expression<String>? data,
|
||||||
Expression<DateTime>? createdAt,
|
Expression<DateTime>? createdAt,
|
||||||
Expression<int>? status,
|
Expression<int>? status,
|
||||||
|
Expression<bool>? isRead,
|
||||||
Expression<int>? rowid,
|
Expression<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
@ -441,6 +482,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
if (data != null) 'data': data,
|
if (data != null) 'data': data,
|
||||||
if (createdAt != null) 'created_at': createdAt,
|
if (createdAt != null) 'created_at': createdAt,
|
||||||
if (status != null) 'status': status,
|
if (status != null) 'status': status,
|
||||||
|
if (isRead != null) 'is_read': isRead,
|
||||||
if (rowid != null) 'rowid': rowid,
|
if (rowid != null) 'rowid': rowid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -454,6 +496,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
Value<String>? data,
|
Value<String>? data,
|
||||||
Value<DateTime>? createdAt,
|
Value<DateTime>? createdAt,
|
||||||
Value<MessageStatus>? status,
|
Value<MessageStatus>? status,
|
||||||
|
Value<bool>? isRead,
|
||||||
Value<int>? rowid,
|
Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return ChatMessagesCompanion(
|
return ChatMessagesCompanion(
|
||||||
@ -465,6 +508,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
data: data ?? this.data,
|
data: data ?? this.data,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
|
isRead: isRead ?? this.isRead,
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -498,6 +542,9 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
$ChatMessagesTable.$converterstatus.toSql(status.value),
|
$ChatMessagesTable.$converterstatus.toSql(status.value),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (isRead.present) {
|
||||||
|
map['is_read'] = Variable<bool>(isRead.value);
|
||||||
|
}
|
||||||
if (rowid.present) {
|
if (rowid.present) {
|
||||||
map['rowid'] = Variable<int>(rowid.value);
|
map['rowid'] = Variable<int>(rowid.value);
|
||||||
}
|
}
|
||||||
@ -515,6 +562,7 @@ class ChatMessagesCompanion extends UpdateCompanion<ChatMessage> {
|
|||||||
..write('data: $data, ')
|
..write('data: $data, ')
|
||||||
..write('createdAt: $createdAt, ')
|
..write('createdAt: $createdAt, ')
|
||||||
..write('status: $status, ')
|
..write('status: $status, ')
|
||||||
|
..write('isRead: $isRead, ')
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
@ -542,6 +590,7 @@ typedef $$ChatMessagesTableCreateCompanionBuilder =
|
|||||||
required String data,
|
required String data,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required MessageStatus status,
|
required MessageStatus status,
|
||||||
|
Value<bool> isRead,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
typedef $$ChatMessagesTableUpdateCompanionBuilder =
|
typedef $$ChatMessagesTableUpdateCompanionBuilder =
|
||||||
@ -554,6 +603,7 @@ typedef $$ChatMessagesTableUpdateCompanionBuilder =
|
|||||||
Value<String> data,
|
Value<String> data,
|
||||||
Value<DateTime> createdAt,
|
Value<DateTime> createdAt,
|
||||||
Value<MessageStatus> status,
|
Value<MessageStatus> status,
|
||||||
|
Value<bool> isRead,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -606,6 +656,11 @@ class $$ChatMessagesTableFilterComposer
|
|||||||
column: $table.status,
|
column: $table.status,
|
||||||
builder: (column) => ColumnWithTypeConverterFilters(column),
|
builder: (column) => ColumnWithTypeConverterFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnFilters<bool> get isRead => $composableBuilder(
|
||||||
|
column: $table.isRead,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$ChatMessagesTableOrderingComposer
|
class $$ChatMessagesTableOrderingComposer
|
||||||
@ -656,6 +711,11 @@ class $$ChatMessagesTableOrderingComposer
|
|||||||
column: $table.status,
|
column: $table.status,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<bool> get isRead => $composableBuilder(
|
||||||
|
column: $table.isRead,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$ChatMessagesTableAnnotationComposer
|
class $$ChatMessagesTableAnnotationComposer
|
||||||
@ -690,6 +750,9 @@ class $$ChatMessagesTableAnnotationComposer
|
|||||||
|
|
||||||
GeneratedColumnWithTypeConverter<MessageStatus, int> get status =>
|
GeneratedColumnWithTypeConverter<MessageStatus, int> get status =>
|
||||||
$composableBuilder(column: $table.status, builder: (column) => column);
|
$composableBuilder(column: $table.status, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<bool> get isRead =>
|
||||||
|
$composableBuilder(column: $table.isRead, builder: (column) => column);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$ChatMessagesTableTableManager
|
class $$ChatMessagesTableTableManager
|
||||||
@ -732,6 +795,7 @@ class $$ChatMessagesTableTableManager
|
|||||||
Value<String> data = const Value.absent(),
|
Value<String> data = const Value.absent(),
|
||||||
Value<DateTime> createdAt = const Value.absent(),
|
Value<DateTime> createdAt = const Value.absent(),
|
||||||
Value<MessageStatus> status = const Value.absent(),
|
Value<MessageStatus> status = const Value.absent(),
|
||||||
|
Value<bool> isRead = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => ChatMessagesCompanion(
|
}) => ChatMessagesCompanion(
|
||||||
id: id,
|
id: id,
|
||||||
@ -742,6 +806,7 @@ class $$ChatMessagesTableTableManager
|
|||||||
data: data,
|
data: data,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
status: status,
|
status: status,
|
||||||
|
isRead: isRead,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
@ -754,6 +819,7 @@ class $$ChatMessagesTableTableManager
|
|||||||
required String data,
|
required String data,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required MessageStatus status,
|
required MessageStatus status,
|
||||||
|
Value<bool> isRead = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => ChatMessagesCompanion.insert(
|
}) => ChatMessagesCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
@ -764,6 +830,7 @@ class $$ChatMessagesTableTableManager
|
|||||||
data: data,
|
data: data,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
status: status,
|
status: status,
|
||||||
|
isRead: isRead,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
withReferenceMapper:
|
withReferenceMapper:
|
||||||
|
@ -11,6 +11,7 @@ class ChatMessages extends Table {
|
|||||||
TextColumn get data => text()();
|
TextColumn get data => text()();
|
||||||
DateTimeColumn get createdAt => dateTime()();
|
DateTimeColumn get createdAt => dateTime()();
|
||||||
IntColumn get status => intEnum<MessageStatus>()();
|
IntColumn get status => intEnum<MessageStatus>()();
|
||||||
|
BoolColumn get isRead => boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {id};
|
Set<Column> get primaryKey => {id};
|
||||||
@ -25,6 +26,7 @@ class LocalChatMessage {
|
|||||||
MessageStatus status;
|
MessageStatus status;
|
||||||
final String? nonce;
|
final String? nonce;
|
||||||
List<UniversalFile>? localAttachments;
|
List<UniversalFile>? localAttachments;
|
||||||
|
bool isRead;
|
||||||
|
|
||||||
LocalChatMessage({
|
LocalChatMessage({
|
||||||
required this.id,
|
required this.id,
|
||||||
@ -35,6 +37,7 @@ class LocalChatMessage {
|
|||||||
required this.nonce,
|
required this.nonce,
|
||||||
required this.status,
|
required this.status,
|
||||||
this.localAttachments,
|
this.localAttachments,
|
||||||
|
this.isRead = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
SnChatMessage toRemoteMessage() {
|
SnChatMessage toRemoteMessage() {
|
||||||
@ -45,6 +48,7 @@ class LocalChatMessage {
|
|||||||
SnChatMessage message,
|
SnChatMessage message,
|
||||||
MessageStatus status, {
|
MessageStatus status, {
|
||||||
String? nonce,
|
String? nonce,
|
||||||
|
bool isRead = false,
|
||||||
}) {
|
}) {
|
||||||
return LocalChatMessage(
|
return LocalChatMessage(
|
||||||
id: message.id,
|
id: message.id,
|
||||||
@ -54,6 +58,7 @@ class LocalChatMessage {
|
|||||||
createdAt: message.createdAt,
|
createdAt: message.createdAt,
|
||||||
status: status,
|
status: status,
|
||||||
nonce: nonce ?? message.nonce,
|
nonce: nonce ?? message.nonce,
|
||||||
|
isRead: isRead,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,4 +457,12 @@ class MessageRepository {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> markMessageAsRead(String messageId) async {
|
||||||
|
try {
|
||||||
|
await _database.markMessageAsRead(messageId);
|
||||||
|
} catch (e) {
|
||||||
|
showErrorAlert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ abstract class WebSocketPacket with _$WebSocketPacket {
|
|||||||
const factory WebSocketPacket({
|
const factory WebSocketPacket({
|
||||||
required String type,
|
required String type,
|
||||||
required Map<String, dynamic>? data,
|
required Map<String, dynamic>? data,
|
||||||
required String? errorMessage,
|
String? errorMessage,
|
||||||
}) = _WebSocketPacket;
|
}) = _WebSocketPacket;
|
||||||
|
|
||||||
factory WebSocketPacket.fromJson(Map<String, dynamic> json) =>
|
factory WebSocketPacket.fromJson(Map<String, dynamic> json) =>
|
||||||
@ -87,7 +87,9 @@ class WebSocketService {
|
|||||||
data is Uint8List ? utf8.decode(data) : data.toString();
|
data is Uint8List ? utf8.decode(data) : data.toString();
|
||||||
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
||||||
_streamController.sink.add(packet);
|
_streamController.sink.add(packet);
|
||||||
log("[WebSocket] Received packet: ${packet.type}");
|
log(
|
||||||
|
"[WebSocket] Received packet: ${packet.type} ${packet.errorMessage}",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onDone: () {
|
onDone: () {
|
||||||
log('[WebSocket] Connection closed, attempting to reconnect...');
|
log('[WebSocket] Connection closed, attempting to reconnect...');
|
||||||
|
@ -310,7 +310,7 @@ as String?,
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _WebSocketPacket with DiagnosticableTreeMixin implements WebSocketPacket {
|
class _WebSocketPacket with DiagnosticableTreeMixin implements WebSocketPacket {
|
||||||
const _WebSocketPacket({required this.type, required final Map<String, dynamic>? data, required this.errorMessage}): _data = data;
|
const _WebSocketPacket({required this.type, required final Map<String, dynamic>? data, this.errorMessage}): _data = data;
|
||||||
factory _WebSocketPacket.fromJson(Map<String, dynamic> json) => _$WebSocketPacketFromJson(json);
|
factory _WebSocketPacket.fromJson(Map<String, dynamic> json) => _$WebSocketPacketFromJson(json);
|
||||||
|
|
||||||
@override final String type;
|
@override final String type;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -19,6 +20,7 @@ import 'package:island/screens/posts/compose.dart';
|
|||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/chat/message_bubble.dart';
|
import 'package:island/widgets/chat/message_bubble.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/response.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@ -306,6 +308,30 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
final attachments = useState<List<UniversalFile>>([]);
|
final attachments = useState<List<UniversalFile>>([]);
|
||||||
final attachmentProgress = useState<Map<String, Map<int, double>>>({});
|
final attachmentProgress = useState<Map<String, Map<int, double>>>({});
|
||||||
|
|
||||||
|
// Function to send read receipt
|
||||||
|
void sendReadReceipt(String messageId) async {
|
||||||
|
// Get message from repository to check read status
|
||||||
|
final repository = await ref.read(messageRepositoryProvider(id).future);
|
||||||
|
final message = await repository.getMessageById(messageId);
|
||||||
|
|
||||||
|
// Skip if message is already marked as read
|
||||||
|
if (message?.isRead ?? false) return;
|
||||||
|
|
||||||
|
// Send websocket packet
|
||||||
|
final wsState = ref.read(websocketStateProvider.notifier);
|
||||||
|
wsState.sendMessage(
|
||||||
|
jsonEncode(
|
||||||
|
WebSocketPacket(
|
||||||
|
type: 'messages.read',
|
||||||
|
data: {'chat_room_id': id, 'message_id': messageId},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark as read in local database
|
||||||
|
await repository.markMessageAsRead(messageId);
|
||||||
|
}
|
||||||
|
|
||||||
// Add scroll listener for pagination
|
// Add scroll listener for pagination
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
void onScroll() {
|
void onScroll() {
|
||||||
@ -319,7 +345,6 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
return () => scrollController.removeListener(onScroll);
|
return () => scrollController.removeListener(onScroll);
|
||||||
}, [scrollController]);
|
}, [scrollController]);
|
||||||
|
|
||||||
// Add websocket listener
|
|
||||||
// Add websocket listener for new messages
|
// Add websocket listener for new messages
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
void onMessage(WebSocketPacket pkt) {
|
void onMessage(WebSocketPacket pkt) {
|
||||||
@ -329,6 +354,8 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
switch (pkt.type) {
|
switch (pkt.type) {
|
||||||
case 'messages.new':
|
case 'messages.new':
|
||||||
messagesNotifier.receiveMessage(message);
|
messagesNotifier.receiveMessage(message);
|
||||||
|
// Send read receipt for new message
|
||||||
|
sendReadReceipt(message.id);
|
||||||
case 'messages.update':
|
case 'messages.update':
|
||||||
messagesNotifier.receiveMessageUpdate(message);
|
messagesNotifier.receiveMessageUpdate(message);
|
||||||
case 'messages.delete':
|
case 'messages.delete':
|
||||||
@ -428,7 +455,11 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
loading: () => const Text('Loading...'),
|
loading: () => const Text('Loading...'),
|
||||||
error: (_, __) => const Text('Error'),
|
error:
|
||||||
|
(err, __) => ResponseErrorWidget(
|
||||||
|
error: err,
|
||||||
|
onRetry: () => messagesNotifier.loadInitial(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -469,6 +500,8 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
nextMessage == null ||
|
nextMessage == null ||
|
||||||
nextMessage.senderId != message.senderId;
|
nextMessage.senderId != message.senderId;
|
||||||
|
|
||||||
|
sendReadReceipt(message.id);
|
||||||
|
|
||||||
return chatIdentity.when(
|
return chatIdentity.when(
|
||||||
skipError: true,
|
skipError: true,
|
||||||
data:
|
data:
|
||||||
@ -527,17 +560,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error:
|
error:
|
||||||
(error, stack) => Center(
|
(error, _) => ResponseErrorWidget(
|
||||||
child: Column(
|
error: error,
|
||||||
mainAxisSize: MainAxisSize.min,
|
onRetry: () => messagesNotifier.loadInitial(),
|
||||||
children: [
|
|
||||||
Text('Error: $error'),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => messagesNotifier.loadInitial(),
|
|
||||||
child: Text('Retry'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user