mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:28:41 +00:00
fix #134
This commit is contained in:
parent
0d36289169
commit
3b65e7d7d1
15 changed files with 3351 additions and 55 deletions
1
drift_schemas/twonly_database/drift_schema_v6.json
Normal file
1
drift_schemas/twonly_database/drift_schema_v6.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -3,6 +3,8 @@ import 'package:flutter/services.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/providers/api/media_received.dart';
|
||||
import 'package:twonly/src/providers/api/media_send.dart';
|
||||
import 'package:twonly/src/providers/api_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/src/providers/connection_provider.dart';
|
||||
|
|
@ -32,6 +34,8 @@ void main() async {
|
|||
apiProvider = ApiProvider();
|
||||
twonlyDatabase = TwonlyDatabase();
|
||||
await twonlyDatabase.messagesDao.resetPendingDownloadState();
|
||||
await purgeReceivedMediaFiles();
|
||||
await purgeSendMediaFiles();
|
||||
|
||||
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDatabase>
|
|||
t.contactId.equals(contactId) &
|
||||
t.contentJson.isNotNull() &
|
||||
(t.openedAt.isNull() |
|
||||
t.mediaStored.equals(true) |
|
||||
t.openedAt.isBiggerThanValue(
|
||||
DateTime.now().subtract(Duration(days: 1)))))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.sendAt)]))
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ class Messages extends Table {
|
|||
IntColumn get responseToOtherMessageId => integer().nullable()();
|
||||
|
||||
BoolColumn get acknowledgeByUser => boolean().withDefault(Constant(false))();
|
||||
BoolColumn get mediaStored => boolean().withDefault(Constant(false))();
|
||||
|
||||
IntColumn get downloadState => intEnum<DownloadState>()
|
||||
.withDefault(Constant(DownloadState.downloaded.index))();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
|
|||
TwonlyDatabase.forTesting(DatabaseConnection super.connection);
|
||||
|
||||
@override
|
||||
int get schemaVersion => 5;
|
||||
int get schemaVersion => 6;
|
||||
|
||||
static QueryExecutor _openConnection() {
|
||||
return driftDatabase(
|
||||
|
|
@ -69,6 +69,8 @@ class TwonlyDatabase extends _$TwonlyDatabase {
|
|||
m.createTable(mediaDownloads);
|
||||
m.addColumn(schema.messages, schema.messages.mediaDownloadId);
|
||||
m.addColumn(schema.messages, schema.messages.mediaUploadId);
|
||||
}, from5To6: (m, schema) async {
|
||||
m.addColumn(schema.messages, schema.messages.mediaStored);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -992,6 +992,16 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
|||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("acknowledge_by_user" IN (0, 1))'),
|
||||
defaultValue: Constant(false));
|
||||
static const VerificationMeta _mediaStoredMeta =
|
||||
const VerificationMeta('mediaStored');
|
||||
@override
|
||||
late final GeneratedColumn<bool> mediaStored = GeneratedColumn<bool>(
|
||||
'media_stored', aliasedName, false,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("media_stored" IN (0, 1))'),
|
||||
defaultValue: Constant(false));
|
||||
@override
|
||||
late final GeneratedColumnWithTypeConverter<DownloadState, int>
|
||||
downloadState = GeneratedColumn<int>('download_state', aliasedName, false,
|
||||
|
|
@ -1061,6 +1071,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
|||
responseToMessageId,
|
||||
responseToOtherMessageId,
|
||||
acknowledgeByUser,
|
||||
mediaStored,
|
||||
downloadState,
|
||||
acknowledgeByServer,
|
||||
errorWhileSending,
|
||||
|
|
@ -1127,6 +1138,12 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
|||
acknowledgeByUser.isAcceptableOrUnknown(
|
||||
data['acknowledge_by_user']!, _acknowledgeByUserMeta));
|
||||
}
|
||||
if (data.containsKey('media_stored')) {
|
||||
context.handle(
|
||||
_mediaStoredMeta,
|
||||
mediaStored.isAcceptableOrUnknown(
|
||||
data['media_stored']!, _mediaStoredMeta));
|
||||
}
|
||||
if (data.containsKey('acknowledge_by_server')) {
|
||||
context.handle(
|
||||
_acknowledgeByServerMeta,
|
||||
|
|
@ -1183,6 +1200,8 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
|||
data['${effectivePrefix}response_to_other_message_id']),
|
||||
acknowledgeByUser: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.bool, data['${effectivePrefix}acknowledge_by_user'])!,
|
||||
mediaStored: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.bool, data['${effectivePrefix}media_stored'])!,
|
||||
downloadState: $MessagesTable.$converterdownloadState.fromSql(
|
||||
attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int, data['${effectivePrefix}download_state'])!),
|
||||
|
|
@ -1223,6 +1242,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
final int? responseToMessageId;
|
||||
final int? responseToOtherMessageId;
|
||||
final bool acknowledgeByUser;
|
||||
final bool mediaStored;
|
||||
final DownloadState downloadState;
|
||||
final bool acknowledgeByServer;
|
||||
final bool errorWhileSending;
|
||||
|
|
@ -1240,6 +1260,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
this.responseToMessageId,
|
||||
this.responseToOtherMessageId,
|
||||
required this.acknowledgeByUser,
|
||||
required this.mediaStored,
|
||||
required this.downloadState,
|
||||
required this.acknowledgeByServer,
|
||||
required this.errorWhileSending,
|
||||
|
|
@ -1270,6 +1291,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
Variable<int>(responseToOtherMessageId);
|
||||
}
|
||||
map['acknowledge_by_user'] = Variable<bool>(acknowledgeByUser);
|
||||
map['media_stored'] = Variable<bool>(mediaStored);
|
||||
{
|
||||
map['download_state'] = Variable<int>(
|
||||
$MessagesTable.$converterdownloadState.toSql(downloadState));
|
||||
|
|
@ -1310,6 +1332,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
? const Value.absent()
|
||||
: Value(responseToOtherMessageId),
|
||||
acknowledgeByUser: Value(acknowledgeByUser),
|
||||
mediaStored: Value(mediaStored),
|
||||
downloadState: Value(downloadState),
|
||||
acknowledgeByServer: Value(acknowledgeByServer),
|
||||
errorWhileSending: Value(errorWhileSending),
|
||||
|
|
@ -1339,6 +1362,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
responseToOtherMessageId:
|
||||
serializer.fromJson<int?>(json['responseToOtherMessageId']),
|
||||
acknowledgeByUser: serializer.fromJson<bool>(json['acknowledgeByUser']),
|
||||
mediaStored: serializer.fromJson<bool>(json['mediaStored']),
|
||||
downloadState: $MessagesTable.$converterdownloadState
|
||||
.fromJson(serializer.fromJson<int>(json['downloadState'])),
|
||||
acknowledgeByServer:
|
||||
|
|
@ -1365,6 +1389,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
'responseToOtherMessageId':
|
||||
serializer.toJson<int?>(responseToOtherMessageId),
|
||||
'acknowledgeByUser': serializer.toJson<bool>(acknowledgeByUser),
|
||||
'mediaStored': serializer.toJson<bool>(mediaStored),
|
||||
'downloadState': serializer.toJson<int>(
|
||||
$MessagesTable.$converterdownloadState.toJson(downloadState)),
|
||||
'acknowledgeByServer': serializer.toJson<bool>(acknowledgeByServer),
|
||||
|
|
@ -1387,6 +1412,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
Value<int?> responseToMessageId = const Value.absent(),
|
||||
Value<int?> responseToOtherMessageId = const Value.absent(),
|
||||
bool? acknowledgeByUser,
|
||||
bool? mediaStored,
|
||||
DownloadState? downloadState,
|
||||
bool? acknowledgeByServer,
|
||||
bool? errorWhileSending,
|
||||
|
|
@ -1412,6 +1438,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
? responseToOtherMessageId.value
|
||||
: this.responseToOtherMessageId,
|
||||
acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser,
|
||||
mediaStored: mediaStored ?? this.mediaStored,
|
||||
downloadState: downloadState ?? this.downloadState,
|
||||
acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer,
|
||||
errorWhileSending: errorWhileSending ?? this.errorWhileSending,
|
||||
|
|
@ -1443,6 +1470,8 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
acknowledgeByUser: data.acknowledgeByUser.present
|
||||
? data.acknowledgeByUser.value
|
||||
: this.acknowledgeByUser,
|
||||
mediaStored:
|
||||
data.mediaStored.present ? data.mediaStored.value : this.mediaStored,
|
||||
downloadState: data.downloadState.present
|
||||
? data.downloadState.value
|
||||
: this.downloadState,
|
||||
|
|
@ -1472,6 +1501,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
..write('responseToMessageId: $responseToMessageId, ')
|
||||
..write('responseToOtherMessageId: $responseToOtherMessageId, ')
|
||||
..write('acknowledgeByUser: $acknowledgeByUser, ')
|
||||
..write('mediaStored: $mediaStored, ')
|
||||
..write('downloadState: $downloadState, ')
|
||||
..write('acknowledgeByServer: $acknowledgeByServer, ')
|
||||
..write('errorWhileSending: $errorWhileSending, ')
|
||||
|
|
@ -1494,6 +1524,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
responseToMessageId,
|
||||
responseToOtherMessageId,
|
||||
acknowledgeByUser,
|
||||
mediaStored,
|
||||
downloadState,
|
||||
acknowledgeByServer,
|
||||
errorWhileSending,
|
||||
|
|
@ -1514,6 +1545,7 @@ class Message extends DataClass implements Insertable<Message> {
|
|||
other.responseToMessageId == this.responseToMessageId &&
|
||||
other.responseToOtherMessageId == this.responseToOtherMessageId &&
|
||||
other.acknowledgeByUser == this.acknowledgeByUser &&
|
||||
other.mediaStored == this.mediaStored &&
|
||||
other.downloadState == this.downloadState &&
|
||||
other.acknowledgeByServer == this.acknowledgeByServer &&
|
||||
other.errorWhileSending == this.errorWhileSending &&
|
||||
|
|
@ -1533,6 +1565,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
final Value<int?> responseToMessageId;
|
||||
final Value<int?> responseToOtherMessageId;
|
||||
final Value<bool> acknowledgeByUser;
|
||||
final Value<bool> mediaStored;
|
||||
final Value<DownloadState> downloadState;
|
||||
final Value<bool> acknowledgeByServer;
|
||||
final Value<bool> errorWhileSending;
|
||||
|
|
@ -1550,6 +1583,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
this.responseToMessageId = const Value.absent(),
|
||||
this.responseToOtherMessageId = const Value.absent(),
|
||||
this.acknowledgeByUser = const Value.absent(),
|
||||
this.mediaStored = const Value.absent(),
|
||||
this.downloadState = const Value.absent(),
|
||||
this.acknowledgeByServer = const Value.absent(),
|
||||
this.errorWhileSending = const Value.absent(),
|
||||
|
|
@ -1568,6 +1602,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
this.responseToMessageId = const Value.absent(),
|
||||
this.responseToOtherMessageId = const Value.absent(),
|
||||
this.acknowledgeByUser = const Value.absent(),
|
||||
this.mediaStored = const Value.absent(),
|
||||
this.downloadState = const Value.absent(),
|
||||
this.acknowledgeByServer = const Value.absent(),
|
||||
this.errorWhileSending = const Value.absent(),
|
||||
|
|
@ -1587,6 +1622,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
Expression<int>? responseToMessageId,
|
||||
Expression<int>? responseToOtherMessageId,
|
||||
Expression<bool>? acknowledgeByUser,
|
||||
Expression<bool>? mediaStored,
|
||||
Expression<int>? downloadState,
|
||||
Expression<bool>? acknowledgeByServer,
|
||||
Expression<bool>? errorWhileSending,
|
||||
|
|
@ -1607,6 +1643,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
if (responseToOtherMessageId != null)
|
||||
'response_to_other_message_id': responseToOtherMessageId,
|
||||
if (acknowledgeByUser != null) 'acknowledge_by_user': acknowledgeByUser,
|
||||
if (mediaStored != null) 'media_stored': mediaStored,
|
||||
if (downloadState != null) 'download_state': downloadState,
|
||||
if (acknowledgeByServer != null)
|
||||
'acknowledge_by_server': acknowledgeByServer,
|
||||
|
|
@ -1628,6 +1665,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
Value<int?>? responseToMessageId,
|
||||
Value<int?>? responseToOtherMessageId,
|
||||
Value<bool>? acknowledgeByUser,
|
||||
Value<bool>? mediaStored,
|
||||
Value<DownloadState>? downloadState,
|
||||
Value<bool>? acknowledgeByServer,
|
||||
Value<bool>? errorWhileSending,
|
||||
|
|
@ -1646,6 +1684,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
responseToOtherMessageId:
|
||||
responseToOtherMessageId ?? this.responseToOtherMessageId,
|
||||
acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser,
|
||||
mediaStored: mediaStored ?? this.mediaStored,
|
||||
downloadState: downloadState ?? this.downloadState,
|
||||
acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer,
|
||||
errorWhileSending: errorWhileSending ?? this.errorWhileSending,
|
||||
|
|
@ -1685,6 +1724,9 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
if (acknowledgeByUser.present) {
|
||||
map['acknowledge_by_user'] = Variable<bool>(acknowledgeByUser.value);
|
||||
}
|
||||
if (mediaStored.present) {
|
||||
map['media_stored'] = Variable<bool>(mediaStored.value);
|
||||
}
|
||||
if (downloadState.present) {
|
||||
map['download_state'] = Variable<int>(
|
||||
$MessagesTable.$converterdownloadState.toSql(downloadState.value));
|
||||
|
|
@ -1725,6 +1767,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
|||
..write('responseToMessageId: $responseToMessageId, ')
|
||||
..write('responseToOtherMessageId: $responseToOtherMessageId, ')
|
||||
..write('acknowledgeByUser: $acknowledgeByUser, ')
|
||||
..write('mediaStored: $mediaStored, ')
|
||||
..write('downloadState: $downloadState, ')
|
||||
..write('acknowledgeByServer: $acknowledgeByServer, ')
|
||||
..write('errorWhileSending: $errorWhileSending, ')
|
||||
|
|
@ -3868,6 +3911,7 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({
|
|||
Value<int?> responseToMessageId,
|
||||
Value<int?> responseToOtherMessageId,
|
||||
Value<bool> acknowledgeByUser,
|
||||
Value<bool> mediaStored,
|
||||
Value<DownloadState> downloadState,
|
||||
Value<bool> acknowledgeByServer,
|
||||
Value<bool> errorWhileSending,
|
||||
|
|
@ -3886,6 +3930,7 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({
|
|||
Value<int?> responseToMessageId,
|
||||
Value<int?> responseToOtherMessageId,
|
||||
Value<bool> acknowledgeByUser,
|
||||
Value<bool> mediaStored,
|
||||
Value<DownloadState> downloadState,
|
||||
Value<bool> acknowledgeByServer,
|
||||
Value<bool> errorWhileSending,
|
||||
|
|
@ -3951,6 +3996,9 @@ class $$MessagesTableFilterComposer
|
|||
column: $table.acknowledgeByUser,
|
||||
builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<bool> get mediaStored => $composableBuilder(
|
||||
column: $table.mediaStored, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnWithTypeConverterFilters<DownloadState, DownloadState, int>
|
||||
get downloadState => $composableBuilder(
|
||||
column: $table.downloadState,
|
||||
|
|
@ -4038,6 +4086,9 @@ class $$MessagesTableOrderingComposer
|
|||
column: $table.acknowledgeByUser,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<bool> get mediaStored => $composableBuilder(
|
||||
column: $table.mediaStored, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<int> get downloadState => $composableBuilder(
|
||||
column: $table.downloadState,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
|
@ -4116,6 +4167,9 @@ class $$MessagesTableAnnotationComposer
|
|||
GeneratedColumn<bool> get acknowledgeByUser => $composableBuilder(
|
||||
column: $table.acknowledgeByUser, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<bool> get mediaStored => $composableBuilder(
|
||||
column: $table.mediaStored, builder: (column) => column);
|
||||
|
||||
GeneratedColumnWithTypeConverter<DownloadState, int> get downloadState =>
|
||||
$composableBuilder(
|
||||
column: $table.downloadState, builder: (column) => column);
|
||||
|
|
@ -4193,6 +4247,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
Value<int?> responseToMessageId = const Value.absent(),
|
||||
Value<int?> responseToOtherMessageId = const Value.absent(),
|
||||
Value<bool> acknowledgeByUser = const Value.absent(),
|
||||
Value<bool> mediaStored = const Value.absent(),
|
||||
Value<DownloadState> downloadState = const Value.absent(),
|
||||
Value<bool> acknowledgeByServer = const Value.absent(),
|
||||
Value<bool> errorWhileSending = const Value.absent(),
|
||||
|
|
@ -4211,6 +4266,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
responseToMessageId: responseToMessageId,
|
||||
responseToOtherMessageId: responseToOtherMessageId,
|
||||
acknowledgeByUser: acknowledgeByUser,
|
||||
mediaStored: mediaStored,
|
||||
downloadState: downloadState,
|
||||
acknowledgeByServer: acknowledgeByServer,
|
||||
errorWhileSending: errorWhileSending,
|
||||
|
|
@ -4229,6 +4285,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
Value<int?> responseToMessageId = const Value.absent(),
|
||||
Value<int?> responseToOtherMessageId = const Value.absent(),
|
||||
Value<bool> acknowledgeByUser = const Value.absent(),
|
||||
Value<bool> mediaStored = const Value.absent(),
|
||||
Value<DownloadState> downloadState = const Value.absent(),
|
||||
Value<bool> acknowledgeByServer = const Value.absent(),
|
||||
Value<bool> errorWhileSending = const Value.absent(),
|
||||
|
|
@ -4247,6 +4304,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
responseToMessageId: responseToMessageId,
|
||||
responseToOtherMessageId: responseToOtherMessageId,
|
||||
acknowledgeByUser: acknowledgeByUser,
|
||||
mediaStored: mediaStored,
|
||||
downloadState: downloadState,
|
||||
acknowledgeByServer: acknowledgeByServer,
|
||||
errorWhileSending: errorWhileSending,
|
||||
|
|
|
|||
|
|
@ -1026,11 +1026,228 @@ i1.GeneratedColumn<int> _column_50(String aliasedName) =>
|
|||
i1.GeneratedColumn<String> _column_51(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('download_token', aliasedName, false,
|
||||
type: i1.DriftSqlType.string);
|
||||
|
||||
final class Schema6 extends i0.VersionedSchema {
|
||||
Schema6({required super.database}) : super(version: 6);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
contacts,
|
||||
messages,
|
||||
mediaUploads,
|
||||
mediaDownloads,
|
||||
signalIdentityKeyStores,
|
||||
signalPreKeyStores,
|
||||
signalSenderKeyStores,
|
||||
signalSessionStores,
|
||||
];
|
||||
late final Shape6 contacts = Shape6(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'contacts',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(user_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
_column_6,
|
||||
_column_7,
|
||||
_column_8,
|
||||
_column_9,
|
||||
_column_39,
|
||||
_column_40,
|
||||
_column_10,
|
||||
_column_11,
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
_column_15,
|
||||
_column_16,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape10 messages = Shape10(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'messages',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_17,
|
||||
_column_18,
|
||||
_column_19,
|
||||
_column_48,
|
||||
_column_49,
|
||||
_column_20,
|
||||
_column_21,
|
||||
_column_22,
|
||||
_column_52,
|
||||
_column_23,
|
||||
_column_24,
|
||||
_column_25,
|
||||
_column_26,
|
||||
_column_27,
|
||||
_column_28,
|
||||
_column_29,
|
||||
_column_30,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape7 mediaUploads = Shape7(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_uploads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_41,
|
||||
_column_42,
|
||||
_column_43,
|
||||
_column_44,
|
||||
_column_45,
|
||||
_column_46,
|
||||
_column_47,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape9 mediaDownloads = Shape9(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_downloads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_50,
|
||||
_column_51,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape2 signalIdentityKeyStores = Shape2(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_identity_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_33,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape3 signalPreKeyStores = Shape3(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_pre_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(pre_key_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_34,
|
||||
_column_35,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape4 signalSenderKeyStores = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_sender_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(sender_key_name)',
|
||||
],
|
||||
columns: [
|
||||
_column_36,
|
||||
_column_37,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 signalSessionStores = Shape5(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_session_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_38,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape10 extends i0.VersionedTable {
|
||||
Shape10({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get contactId =>
|
||||
columnsByName['contact_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get messageId =>
|
||||
columnsByName['message_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get messageOtherId =>
|
||||
columnsByName['message_other_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get mediaUploadId =>
|
||||
columnsByName['media_upload_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get mediaDownloadId =>
|
||||
columnsByName['media_download_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get responseToMessageId =>
|
||||
columnsByName['response_to_message_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get responseToOtherMessageId =>
|
||||
columnsByName['response_to_other_message_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<bool> get acknowledgeByUser =>
|
||||
columnsByName['acknowledge_by_user']! as i1.GeneratedColumn<bool>;
|
||||
i1.GeneratedColumn<bool> get mediaStored =>
|
||||
columnsByName['media_stored']! as i1.GeneratedColumn<bool>;
|
||||
i1.GeneratedColumn<int> get downloadState =>
|
||||
columnsByName['download_state']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<bool> get acknowledgeByServer =>
|
||||
columnsByName['acknowledge_by_server']! as i1.GeneratedColumn<bool>;
|
||||
i1.GeneratedColumn<bool> get errorWhileSending =>
|
||||
columnsByName['error_while_sending']! as i1.GeneratedColumn<bool>;
|
||||
i1.GeneratedColumn<String> get kind =>
|
||||
columnsByName['kind']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<String> get contentJson =>
|
||||
columnsByName['content_json']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<DateTime> get openedAt =>
|
||||
columnsByName['opened_at']! as i1.GeneratedColumn<DateTime>;
|
||||
i1.GeneratedColumn<DateTime> get sendAt =>
|
||||
columnsByName['send_at']! as i1.GeneratedColumn<DateTime>;
|
||||
i1.GeneratedColumn<DateTime> get updatedAt =>
|
||||
columnsByName['updated_at']! as i1.GeneratedColumn<DateTime>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<bool> _column_52(String aliasedName) =>
|
||||
i1.GeneratedColumn<bool>('media_stored', aliasedName, false,
|
||||
type: i1.DriftSqlType.bool,
|
||||
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("media_stored" IN (0, 1))'),
|
||||
defaultValue: const CustomExpression('0'));
|
||||
i0.MigrationStepWithVersion migrationSteps({
|
||||
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
||||
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
|
||||
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
|
||||
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
|
||||
}) {
|
||||
return (currentVersion, database) async {
|
||||
switch (currentVersion) {
|
||||
|
|
@ -1054,6 +1271,11 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||
final migrator = i1.Migrator(database, schema);
|
||||
await from4To5(migrator, schema);
|
||||
return 5;
|
||||
case 5:
|
||||
final schema = Schema6(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from5To6(migrator, schema);
|
||||
return 6;
|
||||
default:
|
||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||
}
|
||||
|
|
@ -1065,6 +1287,7 @@ i1.OnUpgrade stepByStep({
|
|||
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
|
||||
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
|
||||
required Future<void> Function(i1.Migrator m, Schema6 schema) from5To6,
|
||||
}) =>
|
||||
i0.VersionedSchema.stepByStepHelper(
|
||||
step: migrationSteps(
|
||||
|
|
@ -1072,4 +1295,5 @@ i1.OnUpgrade stepByStep({
|
|||
from2To3: from2To3,
|
||||
from3To4: from3To4,
|
||||
from4To5: from4To5,
|
||||
from5To6: from5To6,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Color getMessageColorFromType(MessageContent content, BuildContext context) {
|
|||
Color color;
|
||||
|
||||
if (content is TextMessageContent || content is StoredMediaFileContent) {
|
||||
color = isDarkMode(context) ? Colors.white : Colors.black;
|
||||
color = Colors.blueAccent;
|
||||
} else {
|
||||
if (content is MediaMessageContent) {
|
||||
if (content.isRealTwonly) {
|
||||
|
|
@ -15,7 +15,7 @@ Color getMessageColorFromType(MessageContent content, BuildContext context) {
|
|||
if (content.isVideo) {
|
||||
color = const Color.fromARGB(255, 240, 243, 33);
|
||||
} else {
|
||||
color = Colors.deepOrange;
|
||||
color = Colors.redAccent;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/database/tables/messages_table.dart';
|
||||
|
|
@ -235,7 +237,55 @@ Future<void> writeMediaFile(int mediaId, String type, Uint8List data) async {
|
|||
Future<void> deleteMediaFile(int mediaId, String type) async {
|
||||
String basePath = await getMediaFilePath(mediaId, "received");
|
||||
File file = File("$basePath.$type");
|
||||
try {
|
||||
if (await file.exists()) {
|
||||
await file.delete();
|
||||
}
|
||||
} catch (e) {
|
||||
Logger("media_received.dart").shout("Erro deleting: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> purgeReceivedMediaFiles() async {
|
||||
final basedir = await getApplicationSupportDirectory();
|
||||
final directory = Directory(join(basedir.path, 'media', "received"));
|
||||
await purgeMediaFiles(directory);
|
||||
}
|
||||
|
||||
Future<void> purgeMediaFiles(Directory directory) async {
|
||||
// Check if the directory exists
|
||||
if (await directory.exists()) {
|
||||
// List all files in the directory
|
||||
List<FileSystemEntity> files = directory.listSync();
|
||||
|
||||
List<int> integerFilenames = [];
|
||||
|
||||
// Iterate over each file
|
||||
for (var file in files) {
|
||||
// Get the filename
|
||||
String filename = file.uri.pathSegments.last;
|
||||
|
||||
// Use a regular expression to extract the integer part
|
||||
final match = RegExp(r'(\d+)').firstMatch(filename);
|
||||
if (match != null) {
|
||||
// Parse the integer and add it to the list
|
||||
int messageId = int.parse(match.group(0)!);
|
||||
Message? message = await twonlyDatabase.messagesDao
|
||||
.getMessageByMessageId(messageId)
|
||||
.getSingleOrNull();
|
||||
|
||||
if ((message == null) ||
|
||||
(message.openedAt != null && !message.mediaStored) ||
|
||||
message.errorWhileSending) {
|
||||
try {
|
||||
file.deleteSync();
|
||||
} catch (e) {
|
||||
Logger("media_received.dart").shout("$e");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print(integerFilenames);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import 'package:twonly/src/model/json/message.dart';
|
|||
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
|
||||
import 'package:twonly/src/providers/api/api.dart';
|
||||
import 'package:twonly/src/providers/api/api_utils.dart';
|
||||
import 'package:twonly/src/providers/api/media_received.dart';
|
||||
import 'package:twonly/src/services/notification_service.dart';
|
||||
import 'package:video_compress/video_compress.dart';
|
||||
|
||||
|
|
@ -45,9 +46,9 @@ Future sendMediaFile(
|
|||
if (mediaUploadId != null) {
|
||||
if (videoFilePath != null) {
|
||||
String basePath = await getMediaFilePath(mediaUploadId, "send");
|
||||
await File(videoFilePath.path).rename("$basePath.mp4");
|
||||
await File(videoFilePath.path).rename("$basePath.orginal.mp4");
|
||||
}
|
||||
await writeMediaFile(mediaUploadId, "png", imageBytes);
|
||||
await writeMediaFile(mediaUploadId, "orginal.png", imageBytes);
|
||||
await handleSingleMediaFile(mediaUploadId);
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +169,7 @@ Future handleAddToMessageDb(MediaUpload media) async {
|
|||
}
|
||||
|
||||
Future handleCompressionState(MediaUpload media) async {
|
||||
Uint8List imageBytes = await readMediaFile(media, "png");
|
||||
Uint8List imageBytes = await readMediaFile(media, "orginal.png");
|
||||
|
||||
try {
|
||||
Uint8List imageBytesCompressed =
|
||||
|
|
@ -186,18 +187,17 @@ Future handleCompressionState(MediaUpload media) async {
|
|||
quality: 60,
|
||||
);
|
||||
}
|
||||
await writeMediaFile(
|
||||
media.mediaUploadId, "compressed.png", imageBytesCompressed);
|
||||
await writeMediaFile(media.mediaUploadId, "png", imageBytesCompressed);
|
||||
} catch (e) {
|
||||
Logger("media_send.dart").shout("$e");
|
||||
// as a fall back use the original image
|
||||
await writeMediaFile(media.mediaUploadId, "compressed.png", imageBytes);
|
||||
// as a fall back use the orginal image
|
||||
await writeMediaFile(media.mediaUploadId, "png", imageBytes);
|
||||
}
|
||||
|
||||
if (media.metadata.isVideo) {
|
||||
String basePath = await getMediaFilePath(media.mediaUploadId, "send");
|
||||
File videoOriginalFile = File("$basePath.mp4");
|
||||
File videoCompressedFile = File("$basePath.compressed.mp4");
|
||||
File videoOriginalFile = File("$basePath.orginal.mp4");
|
||||
File videoCompressedFile = File("$basePath.mp4");
|
||||
|
||||
MediaInfo? mediaInfo;
|
||||
|
||||
|
|
@ -235,8 +235,8 @@ Future handleCompressionState(MediaUpload media) async {
|
|||
}
|
||||
|
||||
// delete non compressed media files
|
||||
await deleteMediaFile(media, "png");
|
||||
await deleteMediaFile(media, "mp4");
|
||||
await deleteMediaFile(media, "orginal.png");
|
||||
await deleteMediaFile(media, "orginal.mp4");
|
||||
|
||||
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
|
||||
media.mediaUploadId,
|
||||
|
|
@ -251,10 +251,10 @@ Future handleCompressionState(MediaUpload media) async {
|
|||
Future handleEncryptionState(MediaUpload media) async {
|
||||
var state = MediaEncryptionData();
|
||||
|
||||
Uint8List dataToEncrypt = await readMediaFile(media, "compressed.png");
|
||||
Uint8List dataToEncrypt = await readMediaFile(media, "png");
|
||||
|
||||
if (media.metadata.isVideo) {
|
||||
Uint8List compressedVideo = await readMediaFile(media, "compressed.mp4");
|
||||
Uint8List compressedVideo = await readMediaFile(media, "mp4");
|
||||
dataToEncrypt = combineUint8Lists(dataToEncrypt, compressedVideo);
|
||||
}
|
||||
|
||||
|
|
@ -488,3 +488,9 @@ List<Uint8List> extractUint8Lists(Uint8List combinedList) {
|
|||
combinedList.lengthInBytes - 4 - sizeOfList1);
|
||||
return [list1, list2];
|
||||
}
|
||||
|
||||
Future<void> purgeSendMediaFiles() async {
|
||||
final basedir = await getApplicationSupportDirectory();
|
||||
final directory = Directory(join(basedir.path, 'media', "send"));
|
||||
await purgeMediaFiles(directory);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,10 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
break;
|
||||
|
||||
case MessageKind.ack:
|
||||
final update = MessagesCompanion(acknowledgeByUser: Value(true));
|
||||
final update = MessagesCompanion(
|
||||
acknowledgeByUser: Value(true),
|
||||
errorWhileSending: Value(false),
|
||||
);
|
||||
await twonlyDatabase.messagesDao.updateMessageByOtherUser(
|
||||
fromUserId,
|
||||
message.messageId!,
|
||||
|
|
@ -150,6 +153,7 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
}
|
||||
|
||||
int? responseToMessageId;
|
||||
int? messageId;
|
||||
|
||||
final content = message.content!;
|
||||
if (content is TextMessageContent) {
|
||||
|
|
@ -157,8 +161,14 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
}
|
||||
if (content is StoredMediaFileContent) {
|
||||
responseToMessageId = content.messageId;
|
||||
}
|
||||
|
||||
await twonlyDatabase.messagesDao.updateMessageByOtherUser(
|
||||
fromUserId,
|
||||
content.messageId,
|
||||
MessagesCompanion(
|
||||
mediaStored: Value(true),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
String contentJson = jsonEncode(content.toJson());
|
||||
final update = MessagesCompanion(
|
||||
contactId: Value(fromUserId),
|
||||
|
|
@ -175,15 +185,16 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
sendAt: Value(message.timestamp),
|
||||
);
|
||||
|
||||
final messageId = await twonlyDatabase.messagesDao.insertMessage(
|
||||
messageId = await twonlyDatabase.messagesDao.insertMessage(
|
||||
update,
|
||||
);
|
||||
|
||||
if (messageId == null) {
|
||||
return client.Response()..error = ErrorCode.InternalError;
|
||||
}
|
||||
}
|
||||
|
||||
await encryptAndSendMessage(
|
||||
encryptAndSendMessage(
|
||||
message.messageId!,
|
||||
fromUserId,
|
||||
MessageJson(
|
||||
|
|
@ -194,7 +205,7 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
),
|
||||
);
|
||||
|
||||
if (message.kind == MessageKind.media) {
|
||||
if (message.kind == MessageKind.media && messageId != null) {
|
||||
twonlyDatabase.contactsDao.incFlameCounter(
|
||||
fromUserId,
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/providers/api/media_send.dart';
|
||||
import 'package:twonly/src/views/components/animate_icon.dart';
|
||||
import 'package:twonly/src/views/components/better_text.dart';
|
||||
import 'package:twonly/src/views/components/initialsavatar.dart';
|
||||
|
|
@ -43,6 +44,65 @@ InputDecoration inputTextMessageDeco(BuildContext context) {
|
|||
);
|
||||
}
|
||||
|
||||
class InChatMediaViewer extends StatefulWidget {
|
||||
const InChatMediaViewer({super.key, required this.message});
|
||||
|
||||
final Message message;
|
||||
|
||||
@override
|
||||
State<InChatMediaViewer> createState() => _InChatMediaViewerState();
|
||||
}
|
||||
|
||||
class _InChatMediaViewerState extends State<InChatMediaViewer> {
|
||||
File? image;
|
||||
File? video;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initAsync();
|
||||
}
|
||||
|
||||
Future initAsync() async {
|
||||
if (!widget.message.mediaStored) return;
|
||||
bool isSend = widget.message.messageOtherId == null;
|
||||
final basePath = await getMediaFilePath(
|
||||
isSend ? widget.message.mediaUploadId! : widget.message.messageId,
|
||||
isSend ? "send" : "received",
|
||||
);
|
||||
final imagePath = File("$basePath.png");
|
||||
if (imagePath.existsSync()) {
|
||||
setState(() {
|
||||
image = imagePath;
|
||||
});
|
||||
} else {
|
||||
print("Not found: $imagePath");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
if (image != null) Image.file(image!),
|
||||
if (image == null && video == null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: MessageSendStateIcon(
|
||||
[widget.message],
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatListEntry extends StatelessWidget {
|
||||
const ChatListEntry(
|
||||
this.message, this.contact, this.lastMessageFromSameUser, this.reactions,
|
||||
|
|
@ -59,7 +119,7 @@ class ChatListEntry extends StatelessWidget {
|
|||
MessageContent? content = MessageContent.fromJson(
|
||||
reaction.kind, jsonDecode(reaction.contentJson!));
|
||||
|
||||
if (content is StoredMediaFileContent) {
|
||||
if (content is StoredMediaFileContent || message.mediaStored) {
|
||||
children.add(
|
||||
Expanded(
|
||||
child: Align(
|
||||
|
|
@ -235,7 +295,6 @@ class ChatListEntry extends StatelessWidget {
|
|||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
width: 150,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
|
|
@ -246,9 +305,9 @@ class ChatListEntry extends StatelessWidget {
|
|||
),
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: MessageSendStateIcon(
|
||||
[message],
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: InChatMediaViewer(message: message),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -293,7 +352,11 @@ class ChatListEntry extends StatelessWidget {
|
|||
children: [
|
||||
child,
|
||||
Positioned(
|
||||
bottom: 5, left: 5, right: 5, child: getReactionRow()),
|
||||
bottom: 5,
|
||||
left: 5,
|
||||
right: 5,
|
||||
child: getReactionRow(),
|
||||
),
|
||||
],
|
||||
),
|
||||
getTextResponseColumns(context, !right)
|
||||
|
|
@ -352,7 +415,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
Stream<List<Message>> msgStream =
|
||||
twonlyDatabase.messagesDao.watchAllMessagesFrom(widget.contact.userId);
|
||||
messageSub = msgStream.listen((msgs) {
|
||||
if (!context.mounted) return;
|
||||
// if (!context.mounted) return;
|
||||
if (Platform.isAndroid) {
|
||||
flutterLocalNotificationsPlugin.cancel(widget.contact.userId);
|
||||
} else {
|
||||
|
|
@ -481,6 +544,7 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
|||
reactions = reactionsToOtherMessages[msg.messageOtherId!]!;
|
||||
}
|
||||
return ChatListEntry(
|
||||
key: Key(msg.messageId.toString()),
|
||||
msg,
|
||||
user,
|
||||
lastMessageFromSameUser,
|
||||
|
|
|
|||
|
|
@ -100,6 +100,16 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
Future nextMediaOrExit() async {
|
||||
nextMediaTimer?.cancel();
|
||||
progressTimer?.cancel();
|
||||
if (allMediaFiles.isNotEmpty) {
|
||||
try {
|
||||
if (!imageSaved) {
|
||||
await deleteMediaFile(allMediaFiles.first.messageId, "mp4");
|
||||
await deleteMediaFile(allMediaFiles.first.messageId, "png");
|
||||
}
|
||||
} catch (e) {
|
||||
Logger("media_viewer_view.dart").shout("$e");
|
||||
}
|
||||
}
|
||||
if (allMediaFiles.isEmpty || allMediaFiles.length == 1) {
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
|
|
@ -268,6 +278,10 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
setState(() {
|
||||
imageSaving = true;
|
||||
});
|
||||
await twonlyDatabase.messagesDao.updateMessageByMessageId(
|
||||
allMediaFiles.first.messageId,
|
||||
MessagesCompanion(mediaStored: Value(true)),
|
||||
);
|
||||
encryptAndSendMessage(
|
||||
null,
|
||||
widget.contact.userId,
|
||||
|
|
@ -281,11 +295,13 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
),
|
||||
pushKind: PushKind.storedMediaFile,
|
||||
);
|
||||
setState(() {
|
||||
imageSaved = true;
|
||||
});
|
||||
final res = await saveImageToGallery(imageBytes!);
|
||||
if (res == null) {
|
||||
setState(() {
|
||||
imageSaving = false;
|
||||
imageSaved = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -295,7 +311,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (maxShowTime == gMediaShowInfinite)
|
||||
if (maxShowTime == gMediaShowInfinite && videoController == null)
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
iconColor: imageSaved
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import 'schema_v2.dart' as v2;
|
|||
import 'schema_v3.dart' as v3;
|
||||
import 'schema_v4.dart' as v4;
|
||||
import 'schema_v5.dart' as v5;
|
||||
import 'schema_v6.dart' as v6;
|
||||
|
||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
@override
|
||||
|
|
@ -23,10 +24,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||
return v4.DatabaseAtV4(db);
|
||||
case 5:
|
||||
return v5.DatabaseAtV5(db);
|
||||
case 6:
|
||||
return v6.DatabaseAtV6(db);
|
||||
default:
|
||||
throw MissingSchemaException(version, versions);
|
||||
}
|
||||
}
|
||||
|
||||
static const versions = const [1, 2, 3, 4, 5];
|
||||
static const versions = const [1, 2, 3, 4, 5, 6];
|
||||
}
|
||||
|
|
|
|||
2854
test/drift/twonly_database/generated/schema_v6.dart
Normal file
2854
test/drift/twonly_database/generated/schema_v6.dart
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue