mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-17 03:28:40 +00:00
Merge pull request #309 from twonlyapp/dev
- Option to export and import memories - iOS support for ultra-wide-angle camera - Support Android Monochrome Icon - Multiple layout issues fixed - Multiple bug fixes
This commit is contained in:
commit
39c8d4990f
76 changed files with 22102 additions and 332 deletions
|
|
@ -1,5 +1,13 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.0.69
|
||||||
|
|
||||||
|
- Option to export and import memories
|
||||||
|
- iOS support for ultra-wide-angle camera
|
||||||
|
- Support Android Monochrome Icon
|
||||||
|
- Multiple layout issues fixed
|
||||||
|
- Multiple bug fixes
|
||||||
|
|
||||||
## 0.0.67
|
## 0.0.67
|
||||||
|
|
||||||
- Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”
|
- Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
|
|
@ -6,4 +6,9 @@
|
||||||
android:drawable="@drawable/ic_launcher_foreground"
|
android:drawable="@drawable/ic_launcher_foreground"
|
||||||
android:inset="16%" />
|
android:inset="16%" />
|
||||||
</foreground>
|
</foreground>
|
||||||
|
<monochrome>
|
||||||
|
<inset
|
||||||
|
android:drawable="@drawable/ic_launcher_monochrome"
|
||||||
|
android:inset="16%" />
|
||||||
|
</monochrome>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,4 @@ targets:
|
||||||
databases:
|
databases:
|
||||||
twonly_db: lib/src/database/twonly.db.dart
|
twonly_db: lib/src/database/twonly.db.dart
|
||||||
twonly_database: lib/src/database/twonly_database_old.dart
|
twonly_database: lib/src/database/twonly_database_old.dart
|
||||||
|
schema_dir: lib/src/database/schemas
|
||||||
|
|
@ -11,6 +11,37 @@ PODS:
|
||||||
- Flutter
|
- Flutter
|
||||||
- device_info_plus (0.0.1):
|
- device_info_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- DKImagePickerController/Core (4.3.9):
|
||||||
|
- DKImagePickerController/ImageDataManager
|
||||||
|
- DKImagePickerController/Resource
|
||||||
|
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||||
|
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||||
|
- DKImagePickerController/Core
|
||||||
|
- DKPhotoGallery
|
||||||
|
- DKImagePickerController/Resource (4.3.9)
|
||||||
|
- DKPhotoGallery (0.0.19):
|
||||||
|
- DKPhotoGallery/Core (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Model (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Preview (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Resource (= 0.0.19)
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Core (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Preview
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Model (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Preview (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Resource
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Resource (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
- emoji_picker_flutter (0.0.1):
|
- emoji_picker_flutter (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- ffmpeg_kit_flutter_new (1.0.0):
|
- ffmpeg_kit_flutter_new (1.0.0):
|
||||||
|
|
@ -18,6 +49,9 @@ PODS:
|
||||||
- Flutter
|
- Flutter
|
||||||
- ffmpeg_kit_flutter_new/full-gpl (1.0.0):
|
- ffmpeg_kit_flutter_new/full-gpl (1.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- file_picker (0.0.1):
|
||||||
|
- DKImagePickerController/PhotoGallery
|
||||||
|
- Flutter
|
||||||
- Firebase (12.4.0):
|
- Firebase (12.4.0):
|
||||||
- Firebase/Core (= 12.4.0)
|
- Firebase/Core (= 12.4.0)
|
||||||
- Firebase/Core (12.4.0):
|
- Firebase/Core (12.4.0):
|
||||||
|
|
@ -249,6 +283,7 @@ PODS:
|
||||||
- sqlite3/rtree
|
- sqlite3/rtree
|
||||||
- sqlite3/session
|
- sqlite3/session
|
||||||
- SwiftProtobuf (1.33.1)
|
- SwiftProtobuf (1.33.1)
|
||||||
|
- SwiftyGif (5.4.5)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- video_player_avfoundation (0.0.1):
|
- video_player_avfoundation (0.0.1):
|
||||||
|
|
@ -264,6 +299,7 @@ DEPENDENCIES:
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
|
- emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
|
||||||
- ffmpeg_kit_flutter_new (from `.symlinks/plugins/ffmpeg_kit_flutter_new/ios`)
|
- ffmpeg_kit_flutter_new (from `.symlinks/plugins/ffmpeg_kit_flutter_new/ios`)
|
||||||
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
- Firebase
|
- Firebase
|
||||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
|
|
@ -298,6 +334,8 @@ DEPENDENCIES:
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
|
- DKImagePickerController
|
||||||
|
- DKPhotoGallery
|
||||||
- Firebase
|
- Firebase
|
||||||
- FirebaseAnalytics
|
- FirebaseAnalytics
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
|
|
@ -318,6 +356,7 @@ SPEC REPOS:
|
||||||
- Sentry
|
- Sentry
|
||||||
- sqlite3
|
- sqlite3
|
||||||
- SwiftProtobuf
|
- SwiftProtobuf
|
||||||
|
- SwiftyGif
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
audio_waveforms:
|
audio_waveforms:
|
||||||
|
|
@ -336,6 +375,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/emoji_picker_flutter/ios"
|
:path: ".symlinks/plugins/emoji_picker_flutter/ios"
|
||||||
ffmpeg_kit_flutter_new:
|
ffmpeg_kit_flutter_new:
|
||||||
:path: ".symlinks/plugins/ffmpeg_kit_flutter_new/ios"
|
:path: ".symlinks/plugins/ffmpeg_kit_flutter_new/ios"
|
||||||
|
file_picker:
|
||||||
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
firebase_core:
|
firebase_core:
|
||||||
:path: ".symlinks/plugins/firebase_core/ios"
|
:path: ".symlinks/plugins/firebase_core/ios"
|
||||||
firebase_messaging:
|
firebase_messaging:
|
||||||
|
|
@ -394,8 +435,11 @@ SPEC CHECKSUMS:
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
|
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
|
||||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
|
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
|
||||||
ffmpeg_kit_flutter_new: 12426a19f10ac81186c67c6ebc4717f8f4364b7f
|
ffmpeg_kit_flutter_new: 12426a19f10ac81186c67c6ebc4717f8f4364b7f
|
||||||
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
||||||
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
|
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
|
||||||
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde
|
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde
|
||||||
|
|
@ -439,6 +483,7 @@ SPEC CHECKSUMS:
|
||||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
||||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
||||||
SwiftProtobuf: 533a18409c3ca3a6156b2b1e46afd0f69e751aba
|
SwiftProtobuf: 533a18409c3ca3a6156b2b1e46afd0f69e751aba
|
||||||
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||||
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
|
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
|
|
@ -27,29 +29,7 @@ import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
SentryWidgetsFlutterBinding.ensureInitialized();
|
||||||
try {
|
|
||||||
await initFCMService();
|
|
||||||
} catch (e) {
|
|
||||||
Log.error('$e');
|
|
||||||
}
|
|
||||||
|
|
||||||
initLogger();
|
|
||||||
|
|
||||||
final user = await getUser();
|
|
||||||
if (user != null) {
|
|
||||||
gUser = user;
|
|
||||||
unawaited(performTwonlySafeBackup());
|
|
||||||
}
|
|
||||||
|
|
||||||
final settingsController = SettingsChangeProvider();
|
|
||||||
|
|
||||||
await settingsController.loadSettings();
|
|
||||||
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
|
||||||
|
|
||||||
unawaited(setupPushNotification());
|
|
||||||
|
|
||||||
gCameras = await availableCameras();
|
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// File(join((await getApplicationSupportDirectory()).path, 'twonly.sqlite'))
|
// File(join((await getApplicationSupportDirectory()).path, 'twonly.sqlite'))
|
||||||
|
|
@ -60,44 +40,67 @@ void main() async {
|
||||||
// return u;
|
// return u;
|
||||||
// });
|
// });
|
||||||
|
|
||||||
apiService = ApiService();
|
final user = await getUser();
|
||||||
twonlyDB = TwonlyDB();
|
|
||||||
|
|
||||||
await initFileDownloader();
|
|
||||||
unawaited(finishStartedPreprocessing());
|
|
||||||
|
|
||||||
unawaited(MediaFileService.purgeTempFolder());
|
|
||||||
unawaited(createPushAvatars());
|
|
||||||
await twonlyDB.messagesDao.purgeMessageTable();
|
|
||||||
|
|
||||||
final providers = [
|
|
||||||
ChangeNotifierProvider(create: (_) => settingsController),
|
|
||||||
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
|
|
||||||
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
gUser = user;
|
||||||
|
|
||||||
if (user.allowErrorTrackingViaSentry) {
|
if (user.allowErrorTrackingViaSentry) {
|
||||||
globalAllowErrorTrackingViaSentry = true;
|
globalAllowErrorTrackingViaSentry = true;
|
||||||
return SentryFlutter.init(
|
await SentryFlutter.init(
|
||||||
(options) => options
|
(options) => options
|
||||||
..dsn =
|
..dsn =
|
||||||
'https://6b24a012c85144c9b522440a1d17d01c@glitchtip.twonly.eu/4'
|
'https://6b24a012c85144c9b522440a1d17d01c@glitchtip.twonly.eu/4'
|
||||||
..tracesSampleRate = 0.01
|
..tracesSampleRate = 0.1
|
||||||
..enableAutoSessionTracking = false,
|
..enableAutoSessionTracking = false,
|
||||||
appRunner: () => runApp(
|
|
||||||
MultiProvider(
|
|
||||||
providers: providers,
|
|
||||||
child: const App(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unawaited(performTwonlySafeBackup());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await initFCMService();
|
||||||
|
|
||||||
|
initLogger();
|
||||||
|
|
||||||
|
final settingsController = SettingsChangeProvider();
|
||||||
|
|
||||||
|
await settingsController.loadSettings();
|
||||||
|
await SystemChrome.setPreferredOrientations(
|
||||||
|
[DeviceOrientation.portraitUp],
|
||||||
|
);
|
||||||
|
|
||||||
|
unawaited(setupPushNotification());
|
||||||
|
|
||||||
|
gCameras = await availableCameras();
|
||||||
|
|
||||||
|
apiService = ApiService();
|
||||||
|
twonlyDB = TwonlyDB();
|
||||||
|
|
||||||
|
await twonlyDB.messagesDao.purgeMessageTable();
|
||||||
|
unawaited(MediaFileService.purgeTempFolder());
|
||||||
|
|
||||||
|
await initFileDownloader();
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if ((await DeviceInfoPlugin().androidInfo).version.release == '9') {
|
||||||
|
Future.delayed(const Duration(seconds: 20), () {
|
||||||
|
unawaited(finishStartedPreprocessing());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
unawaited(finishStartedPreprocessing());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unawaited(finishStartedPreprocessing());
|
||||||
|
}
|
||||||
|
|
||||||
|
unawaited(createPushAvatars());
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: providers,
|
providers: [
|
||||||
|
ChangeNotifierProvider(create: (_) => settingsController),
|
||||||
|
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
|
||||||
|
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
||||||
|
],
|
||||||
child: const App(),
|
child: const App(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -247,16 +247,22 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() {
|
Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() async {
|
||||||
final query =
|
try {
|
||||||
((select(groups)..where((t) => t.isDirectChat.equals(false))).join([
|
final query = ((select(groupMembers)
|
||||||
|
..where((t) => t.groupPublicKey.isNull()))
|
||||||
|
.join([
|
||||||
leftOuterJoin(
|
leftOuterJoin(
|
||||||
groupMembers,
|
groups,
|
||||||
groupMembers.groupId.equalsExp(groups.groupId),
|
groups.groupId.equalsExp(groupMembers.groupId),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
..where(groupMembers.groupPublicKey.isNull()));
|
..where(groups.isDirectChat.isNull()));
|
||||||
return query.map((row) => row.readTable(groupMembers)).get();
|
return query.map((row) => row.readTable(groupMembers)).get();
|
||||||
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Group?> getDirectChat(int userId) async {
|
Future<Group?> getDirectChat(int userId) async {
|
||||||
|
|
|
||||||
|
|
@ -119,11 +119,10 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
..where(
|
..where(
|
||||||
(m) =>
|
(m) =>
|
||||||
m.groupId.equals(group.groupId) &
|
m.groupId.equals(group.groupId) &
|
||||||
// m.messageId.equals(lastMessage.messageId).not() &
|
|
||||||
(m.mediaStored.equals(true) &
|
(m.mediaStored.equals(true) &
|
||||||
m.isDeletedFromSender.equals(true) |
|
m.isDeletedFromSender.equals(true) |
|
||||||
m.mediaStored.equals(false)) &
|
m.mediaStored.equals(false)) &
|
||||||
(m.openedByAll.isSmallerThanValue(deletionTime) |
|
(m.openedAt.isSmallerThanValue(deletionTime) |
|
||||||
(m.isDeletedFromSender.equals(true) &
|
(m.isDeletedFromSender.equals(true) &
|
||||||
m.createdAt.isSmallerThanValue(deletionTime))),
|
m.createdAt.isSmallerThanValue(deletionTime))),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
1
lib/src/database/schemas/twonly_db/drift_schema_v1.json
Normal file
1
lib/src/database/schemas/twonly_db/drift_schema_v1.json
Normal file
File diff suppressed because one or more lines are too long
1
lib/src/database/schemas/twonly_db/drift_schema_v2.json
Normal file
1
lib/src/database/schemas/twonly_db/drift_schema_v2.json
Normal file
File diff suppressed because one or more lines are too long
1
lib/src/database/schemas/twonly_db/drift_schema_v3.json
Normal file
1
lib/src/database/schemas/twonly_db/drift_schema_v3.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -20,7 +20,7 @@ class ConnectPreKeyStore extends PreKeyStore {
|
||||||
.get();
|
.get();
|
||||||
if (preKeyRecord.isEmpty) {
|
if (preKeyRecord.isEmpty) {
|
||||||
throw InvalidKeyIdException(
|
throw InvalidKeyIdException(
|
||||||
'[PREKEY] No such preKey record! - $preKeyId',
|
'[PREKEY] No such preKey record!',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final preKey = preKeyRecord.first.preKey;
|
final preKey = preKeyRecord.first.preKey;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ class Groups extends Table {
|
||||||
BlobColumn get myGroupPrivateKey => blob().nullable()();
|
BlobColumn get myGroupPrivateKey => blob().nullable()();
|
||||||
|
|
||||||
TextColumn get groupName => text()();
|
TextColumn get groupName => text()();
|
||||||
|
TextColumn get draftMessage => text().nullable()();
|
||||||
|
|
||||||
IntColumn get totalMediaCounter => integer().withDefault(const Constant(0))();
|
IntColumn get totalMediaCounter => integer().withDefault(const Constant(0))();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,6 @@ class MediaFiles extends Table {
|
||||||
BoolColumn get requiresAuthentication =>
|
BoolColumn get requiresAuthentication =>
|
||||||
boolean().withDefault(const Constant(false))();
|
boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
BoolColumn get reopenByContact =>
|
|
||||||
boolean().withDefault(const Constant(false))();
|
|
||||||
|
|
||||||
BoolColumn get stored => boolean().withDefault(const Constant(false))();
|
BoolColumn get stored => boolean().withDefault(const Constant(false))();
|
||||||
BoolColumn get isDraftMedia => boolean().withDefault(const Constant(false))();
|
BoolColumn get isDraftMedia => boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ class Messages extends Table {
|
||||||
.references(MediaFiles, #mediaId, onDelete: KeyAction.setNull)();
|
.references(MediaFiles, #mediaId, onDelete: KeyAction.setNull)();
|
||||||
|
|
||||||
BoolColumn get mediaStored => boolean().withDefault(const Constant(false))();
|
BoolColumn get mediaStored => boolean().withDefault(const Constant(false))();
|
||||||
|
BoolColumn get mediaReopened =>
|
||||||
|
boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
BlobColumn get downloadToken => blob().nullable()();
|
BlobColumn get downloadToken => blob().nullable()();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import 'package:twonly/src/database/tables/signal_identity_key_store.table.dart'
|
||||||
import 'package:twonly/src/database/tables/signal_pre_key_store.table.dart';
|
import 'package:twonly/src/database/tables/signal_pre_key_store.table.dart';
|
||||||
import 'package:twonly/src/database/tables/signal_sender_key_store.table.dart';
|
import 'package:twonly/src/database/tables/signal_sender_key_store.table.dart';
|
||||||
import 'package:twonly/src/database/tables/signal_session_store.table.dart';
|
import 'package:twonly/src/database/tables/signal_session_store.table.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.steps.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
|
|
||||||
part 'twonly.db.g.dart';
|
part 'twonly.db.g.dart';
|
||||||
|
|
@ -66,7 +67,7 @@ class TwonlyDB extends _$TwonlyDB {
|
||||||
TwonlyDB.forTesting(DatabaseConnection super.connection);
|
TwonlyDB.forTesting(DatabaseConnection super.connection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 3;
|
||||||
|
|
||||||
static QueryExecutor _openConnection() {
|
static QueryExecutor _openConnection() {
|
||||||
return driftDatabase(
|
return driftDatabase(
|
||||||
|
|
@ -83,7 +84,15 @@ class TwonlyDB extends _$TwonlyDB {
|
||||||
beforeOpen: (details) async {
|
beforeOpen: (details) async {
|
||||||
await customStatement('PRAGMA foreign_keys = ON');
|
await customStatement('PRAGMA foreign_keys = ON');
|
||||||
},
|
},
|
||||||
// onUpgrade: stepByStep(),
|
onUpgrade: stepByStep(
|
||||||
|
from1To2: (m, schema) async {
|
||||||
|
await m.addColumn(schema.messages, schema.messages.mediaReopened);
|
||||||
|
await m.dropColumn(schema.mediaFiles, 'reopen_by_contact');
|
||||||
|
},
|
||||||
|
from2To3: (m, schema) async {
|
||||||
|
await m.addColumn(schema.groups, schema.groups.draftMessage);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,25 +114,39 @@ class TwonlyDB extends _$TwonlyDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteDataForTwonlySafe() async {
|
Future<void> deleteDataForTwonlySafe() async {
|
||||||
// await delete(messages).go();
|
await (delete(messages)
|
||||||
// await delete(messageRetransmissions).go();
|
..where(
|
||||||
// await delete(mediaUploads).go();
|
(t) => (t.mediaStored.equals(false) &
|
||||||
// await update(contacts).write(
|
t.isDeletedFromSender.equals(false)),
|
||||||
// const ContactsCompanion(
|
))
|
||||||
// avatarSvg: Value(null),
|
.go();
|
||||||
// myAvatarCounter: Value(0),
|
await update(messages).write(
|
||||||
// ),
|
const MessagesCompanion(
|
||||||
// );
|
downloadToken: Value(null),
|
||||||
// await delete(signalContactPreKeys).go();
|
),
|
||||||
// await delete(signalContactSignedPreKeys).go();
|
);
|
||||||
// await (delete(signalPreKeyStores)
|
await (delete(mediaFiles)
|
||||||
// ..where(
|
..where(
|
||||||
// (t) => (t.createdAt.isSmallerThanValue(
|
(t) => (t.stored.equals(false)),
|
||||||
// DateTime.now().subtract(
|
))
|
||||||
// const Duration(days: 25),
|
.go();
|
||||||
// ),
|
await delete(receipts).go();
|
||||||
// )),
|
await update(contacts).write(
|
||||||
// ))
|
const ContactsCompanion(
|
||||||
// .go();
|
avatarSvgCompressed: Value(null),
|
||||||
|
senderProfileCounter: Value(0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await delete(signalContactPreKeys).go();
|
||||||
|
await delete(signalContactSignedPreKeys).go();
|
||||||
|
await (delete(signalPreKeyStores)
|
||||||
|
..where(
|
||||||
|
(t) => (t.createdAt.isSmallerThanValue(
|
||||||
|
DateTime.now().subtract(
|
||||||
|
const Duration(days: 25),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
.go();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -760,6 +760,12 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> {
|
||||||
late final GeneratedColumn<String> groupName = GeneratedColumn<String>(
|
late final GeneratedColumn<String> groupName = GeneratedColumn<String>(
|
||||||
'group_name', aliasedName, false,
|
'group_name', aliasedName, false,
|
||||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
static const VerificationMeta _draftMessageMeta =
|
||||||
|
const VerificationMeta('draftMessage');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> draftMessage = GeneratedColumn<String>(
|
||||||
|
'draft_message', aliasedName, true,
|
||||||
|
type: DriftSqlType.string, requiredDuringInsert: false);
|
||||||
static const VerificationMeta _totalMediaCounterMeta =
|
static const VerificationMeta _totalMediaCounterMeta =
|
||||||
const VerificationMeta('totalMediaCounter');
|
const VerificationMeta('totalMediaCounter');
|
||||||
@override
|
@override
|
||||||
|
|
@ -863,6 +869,7 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> {
|
||||||
stateEncryptionKey,
|
stateEncryptionKey,
|
||||||
myGroupPrivateKey,
|
myGroupPrivateKey,
|
||||||
groupName,
|
groupName,
|
||||||
|
draftMessage,
|
||||||
totalMediaCounter,
|
totalMediaCounter,
|
||||||
alsoBestFriend,
|
alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds,
|
deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -952,6 +959,12 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> {
|
||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_groupNameMeta);
|
context.missing(_groupNameMeta);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('draft_message')) {
|
||||||
|
context.handle(
|
||||||
|
_draftMessageMeta,
|
||||||
|
draftMessage.isAcceptableOrUnknown(
|
||||||
|
data['draft_message']!, _draftMessageMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('total_media_counter')) {
|
if (data.containsKey('total_media_counter')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_totalMediaCounterMeta,
|
_totalMediaCounterMeta,
|
||||||
|
|
@ -1056,6 +1069,8 @@ class $GroupsTable extends Groups with TableInfo<$GroupsTable, Group> {
|
||||||
DriftSqlType.blob, data['${effectivePrefix}my_group_private_key']),
|
DriftSqlType.blob, data['${effectivePrefix}my_group_private_key']),
|
||||||
groupName: attachedDatabase.typeMapping
|
groupName: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.string, data['${effectivePrefix}group_name'])!,
|
.read(DriftSqlType.string, data['${effectivePrefix}group_name'])!,
|
||||||
|
draftMessage: attachedDatabase.typeMapping
|
||||||
|
.read(DriftSqlType.string, data['${effectivePrefix}draft_message']),
|
||||||
totalMediaCounter: attachedDatabase.typeMapping.read(
|
totalMediaCounter: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.int, data['${effectivePrefix}total_media_counter'])!,
|
DriftSqlType.int, data['${effectivePrefix}total_media_counter'])!,
|
||||||
alsoBestFriend: attachedDatabase.typeMapping
|
alsoBestFriend: attachedDatabase.typeMapping
|
||||||
|
|
@ -1107,6 +1122,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
final Uint8List? stateEncryptionKey;
|
final Uint8List? stateEncryptionKey;
|
||||||
final Uint8List? myGroupPrivateKey;
|
final Uint8List? myGroupPrivateKey;
|
||||||
final String groupName;
|
final String groupName;
|
||||||
|
final String? draftMessage;
|
||||||
final int totalMediaCounter;
|
final int totalMediaCounter;
|
||||||
final bool alsoBestFriend;
|
final bool alsoBestFriend;
|
||||||
final int deleteMessagesAfterMilliseconds;
|
final int deleteMessagesAfterMilliseconds;
|
||||||
|
|
@ -1132,6 +1148,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
this.stateEncryptionKey,
|
this.stateEncryptionKey,
|
||||||
this.myGroupPrivateKey,
|
this.myGroupPrivateKey,
|
||||||
required this.groupName,
|
required this.groupName,
|
||||||
|
this.draftMessage,
|
||||||
required this.totalMediaCounter,
|
required this.totalMediaCounter,
|
||||||
required this.alsoBestFriend,
|
required this.alsoBestFriend,
|
||||||
required this.deleteMessagesAfterMilliseconds,
|
required this.deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -1163,6 +1180,9 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
map['my_group_private_key'] = Variable<Uint8List>(myGroupPrivateKey);
|
map['my_group_private_key'] = Variable<Uint8List>(myGroupPrivateKey);
|
||||||
}
|
}
|
||||||
map['group_name'] = Variable<String>(groupName);
|
map['group_name'] = Variable<String>(groupName);
|
||||||
|
if (!nullToAbsent || draftMessage != null) {
|
||||||
|
map['draft_message'] = Variable<String>(draftMessage);
|
||||||
|
}
|
||||||
map['total_media_counter'] = Variable<int>(totalMediaCounter);
|
map['total_media_counter'] = Variable<int>(totalMediaCounter);
|
||||||
map['also_best_friend'] = Variable<bool>(alsoBestFriend);
|
map['also_best_friend'] = Variable<bool>(alsoBestFriend);
|
||||||
map['delete_messages_after_milliseconds'] =
|
map['delete_messages_after_milliseconds'] =
|
||||||
|
|
@ -1208,6 +1228,9 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(myGroupPrivateKey),
|
: Value(myGroupPrivateKey),
|
||||||
groupName: Value(groupName),
|
groupName: Value(groupName),
|
||||||
|
draftMessage: draftMessage == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(draftMessage),
|
||||||
totalMediaCounter: Value(totalMediaCounter),
|
totalMediaCounter: Value(totalMediaCounter),
|
||||||
alsoBestFriend: Value(alsoBestFriend),
|
alsoBestFriend: Value(alsoBestFriend),
|
||||||
deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds),
|
deleteMessagesAfterMilliseconds: Value(deleteMessagesAfterMilliseconds),
|
||||||
|
|
@ -1251,6 +1274,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
myGroupPrivateKey:
|
myGroupPrivateKey:
|
||||||
serializer.fromJson<Uint8List?>(json['myGroupPrivateKey']),
|
serializer.fromJson<Uint8List?>(json['myGroupPrivateKey']),
|
||||||
groupName: serializer.fromJson<String>(json['groupName']),
|
groupName: serializer.fromJson<String>(json['groupName']),
|
||||||
|
draftMessage: serializer.fromJson<String?>(json['draftMessage']),
|
||||||
totalMediaCounter: serializer.fromJson<int>(json['totalMediaCounter']),
|
totalMediaCounter: serializer.fromJson<int>(json['totalMediaCounter']),
|
||||||
alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']),
|
alsoBestFriend: serializer.fromJson<bool>(json['alsoBestFriend']),
|
||||||
deleteMessagesAfterMilliseconds:
|
deleteMessagesAfterMilliseconds:
|
||||||
|
|
@ -1286,6 +1310,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
'stateEncryptionKey': serializer.toJson<Uint8List?>(stateEncryptionKey),
|
'stateEncryptionKey': serializer.toJson<Uint8List?>(stateEncryptionKey),
|
||||||
'myGroupPrivateKey': serializer.toJson<Uint8List?>(myGroupPrivateKey),
|
'myGroupPrivateKey': serializer.toJson<Uint8List?>(myGroupPrivateKey),
|
||||||
'groupName': serializer.toJson<String>(groupName),
|
'groupName': serializer.toJson<String>(groupName),
|
||||||
|
'draftMessage': serializer.toJson<String?>(draftMessage),
|
||||||
'totalMediaCounter': serializer.toJson<int>(totalMediaCounter),
|
'totalMediaCounter': serializer.toJson<int>(totalMediaCounter),
|
||||||
'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend),
|
'alsoBestFriend': serializer.toJson<bool>(alsoBestFriend),
|
||||||
'deleteMessagesAfterMilliseconds':
|
'deleteMessagesAfterMilliseconds':
|
||||||
|
|
@ -1316,6 +1341,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
||||||
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
||||||
String? groupName,
|
String? groupName,
|
||||||
|
Value<String?> draftMessage = const Value.absent(),
|
||||||
int? totalMediaCounter,
|
int? totalMediaCounter,
|
||||||
bool? alsoBestFriend,
|
bool? alsoBestFriend,
|
||||||
int? deleteMessagesAfterMilliseconds,
|
int? deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -1345,6 +1371,8 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
? myGroupPrivateKey.value
|
? myGroupPrivateKey.value
|
||||||
: this.myGroupPrivateKey,
|
: this.myGroupPrivateKey,
|
||||||
groupName: groupName ?? this.groupName,
|
groupName: groupName ?? this.groupName,
|
||||||
|
draftMessage:
|
||||||
|
draftMessage.present ? draftMessage.value : this.draftMessage,
|
||||||
totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter,
|
totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter,
|
||||||
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
|
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds ??
|
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds ??
|
||||||
|
|
@ -1395,6 +1423,9 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
? data.myGroupPrivateKey.value
|
? data.myGroupPrivateKey.value
|
||||||
: this.myGroupPrivateKey,
|
: this.myGroupPrivateKey,
|
||||||
groupName: data.groupName.present ? data.groupName.value : this.groupName,
|
groupName: data.groupName.present ? data.groupName.value : this.groupName,
|
||||||
|
draftMessage: data.draftMessage.present
|
||||||
|
? data.draftMessage.value
|
||||||
|
: this.draftMessage,
|
||||||
totalMediaCounter: data.totalMediaCounter.present
|
totalMediaCounter: data.totalMediaCounter.present
|
||||||
? data.totalMediaCounter.value
|
? data.totalMediaCounter.value
|
||||||
: this.totalMediaCounter,
|
: this.totalMediaCounter,
|
||||||
|
|
@ -1448,6 +1479,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
..write('stateEncryptionKey: $stateEncryptionKey, ')
|
..write('stateEncryptionKey: $stateEncryptionKey, ')
|
||||||
..write('myGroupPrivateKey: $myGroupPrivateKey, ')
|
..write('myGroupPrivateKey: $myGroupPrivateKey, ')
|
||||||
..write('groupName: $groupName, ')
|
..write('groupName: $groupName, ')
|
||||||
|
..write('draftMessage: $draftMessage, ')
|
||||||
..write('totalMediaCounter: $totalMediaCounter, ')
|
..write('totalMediaCounter: $totalMediaCounter, ')
|
||||||
..write('alsoBestFriend: $alsoBestFriend, ')
|
..write('alsoBestFriend: $alsoBestFriend, ')
|
||||||
..write(
|
..write(
|
||||||
|
|
@ -1479,6 +1511,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
$driftBlobEquality.hash(stateEncryptionKey),
|
$driftBlobEquality.hash(stateEncryptionKey),
|
||||||
$driftBlobEquality.hash(myGroupPrivateKey),
|
$driftBlobEquality.hash(myGroupPrivateKey),
|
||||||
groupName,
|
groupName,
|
||||||
|
draftMessage,
|
||||||
totalMediaCounter,
|
totalMediaCounter,
|
||||||
alsoBestFriend,
|
alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds,
|
deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -1510,6 +1543,7 @@ class Group extends DataClass implements Insertable<Group> {
|
||||||
$driftBlobEquality.equals(
|
$driftBlobEquality.equals(
|
||||||
other.myGroupPrivateKey, this.myGroupPrivateKey) &&
|
other.myGroupPrivateKey, this.myGroupPrivateKey) &&
|
||||||
other.groupName == this.groupName &&
|
other.groupName == this.groupName &&
|
||||||
|
other.draftMessage == this.draftMessage &&
|
||||||
other.totalMediaCounter == this.totalMediaCounter &&
|
other.totalMediaCounter == this.totalMediaCounter &&
|
||||||
other.alsoBestFriend == this.alsoBestFriend &&
|
other.alsoBestFriend == this.alsoBestFriend &&
|
||||||
other.deleteMessagesAfterMilliseconds ==
|
other.deleteMessagesAfterMilliseconds ==
|
||||||
|
|
@ -1538,6 +1572,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
final Value<Uint8List?> stateEncryptionKey;
|
final Value<Uint8List?> stateEncryptionKey;
|
||||||
final Value<Uint8List?> myGroupPrivateKey;
|
final Value<Uint8List?> myGroupPrivateKey;
|
||||||
final Value<String> groupName;
|
final Value<String> groupName;
|
||||||
|
final Value<String?> draftMessage;
|
||||||
final Value<int> totalMediaCounter;
|
final Value<int> totalMediaCounter;
|
||||||
final Value<bool> alsoBestFriend;
|
final Value<bool> alsoBestFriend;
|
||||||
final Value<int> deleteMessagesAfterMilliseconds;
|
final Value<int> deleteMessagesAfterMilliseconds;
|
||||||
|
|
@ -1564,6 +1599,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
this.stateEncryptionKey = const Value.absent(),
|
this.stateEncryptionKey = const Value.absent(),
|
||||||
this.myGroupPrivateKey = const Value.absent(),
|
this.myGroupPrivateKey = const Value.absent(),
|
||||||
this.groupName = const Value.absent(),
|
this.groupName = const Value.absent(),
|
||||||
|
this.draftMessage = const Value.absent(),
|
||||||
this.totalMediaCounter = const Value.absent(),
|
this.totalMediaCounter = const Value.absent(),
|
||||||
this.alsoBestFriend = const Value.absent(),
|
this.alsoBestFriend = const Value.absent(),
|
||||||
this.deleteMessagesAfterMilliseconds = const Value.absent(),
|
this.deleteMessagesAfterMilliseconds = const Value.absent(),
|
||||||
|
|
@ -1591,6 +1627,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
this.stateEncryptionKey = const Value.absent(),
|
this.stateEncryptionKey = const Value.absent(),
|
||||||
this.myGroupPrivateKey = const Value.absent(),
|
this.myGroupPrivateKey = const Value.absent(),
|
||||||
required String groupName,
|
required String groupName,
|
||||||
|
this.draftMessage = const Value.absent(),
|
||||||
this.totalMediaCounter = const Value.absent(),
|
this.totalMediaCounter = const Value.absent(),
|
||||||
this.alsoBestFriend = const Value.absent(),
|
this.alsoBestFriend = const Value.absent(),
|
||||||
this.deleteMessagesAfterMilliseconds = const Value.absent(),
|
this.deleteMessagesAfterMilliseconds = const Value.absent(),
|
||||||
|
|
@ -1619,6 +1656,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
Expression<Uint8List>? stateEncryptionKey,
|
Expression<Uint8List>? stateEncryptionKey,
|
||||||
Expression<Uint8List>? myGroupPrivateKey,
|
Expression<Uint8List>? myGroupPrivateKey,
|
||||||
Expression<String>? groupName,
|
Expression<String>? groupName,
|
||||||
|
Expression<String>? draftMessage,
|
||||||
Expression<int>? totalMediaCounter,
|
Expression<int>? totalMediaCounter,
|
||||||
Expression<bool>? alsoBestFriend,
|
Expression<bool>? alsoBestFriend,
|
||||||
Expression<int>? deleteMessagesAfterMilliseconds,
|
Expression<int>? deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -1647,6 +1685,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
'state_encryption_key': stateEncryptionKey,
|
'state_encryption_key': stateEncryptionKey,
|
||||||
if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey,
|
if (myGroupPrivateKey != null) 'my_group_private_key': myGroupPrivateKey,
|
||||||
if (groupName != null) 'group_name': groupName,
|
if (groupName != null) 'group_name': groupName,
|
||||||
|
if (draftMessage != null) 'draft_message': draftMessage,
|
||||||
if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter,
|
if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter,
|
||||||
if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend,
|
if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend,
|
||||||
if (deleteMessagesAfterMilliseconds != null)
|
if (deleteMessagesAfterMilliseconds != null)
|
||||||
|
|
@ -1681,6 +1720,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
Value<Uint8List?>? stateEncryptionKey,
|
Value<Uint8List?>? stateEncryptionKey,
|
||||||
Value<Uint8List?>? myGroupPrivateKey,
|
Value<Uint8List?>? myGroupPrivateKey,
|
||||||
Value<String>? groupName,
|
Value<String>? groupName,
|
||||||
|
Value<String?>? draftMessage,
|
||||||
Value<int>? totalMediaCounter,
|
Value<int>? totalMediaCounter,
|
||||||
Value<bool>? alsoBestFriend,
|
Value<bool>? alsoBestFriend,
|
||||||
Value<int>? deleteMessagesAfterMilliseconds,
|
Value<int>? deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -1707,6 +1747,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey,
|
stateEncryptionKey: stateEncryptionKey ?? this.stateEncryptionKey,
|
||||||
myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey,
|
myGroupPrivateKey: myGroupPrivateKey ?? this.myGroupPrivateKey,
|
||||||
groupName: groupName ?? this.groupName,
|
groupName: groupName ?? this.groupName,
|
||||||
|
draftMessage: draftMessage ?? this.draftMessage,
|
||||||
totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter,
|
totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter,
|
||||||
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
|
alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds ??
|
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds ??
|
||||||
|
|
@ -1766,6 +1807,9 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
if (groupName.present) {
|
if (groupName.present) {
|
||||||
map['group_name'] = Variable<String>(groupName.value);
|
map['group_name'] = Variable<String>(groupName.value);
|
||||||
}
|
}
|
||||||
|
if (draftMessage.present) {
|
||||||
|
map['draft_message'] = Variable<String>(draftMessage.value);
|
||||||
|
}
|
||||||
if (totalMediaCounter.present) {
|
if (totalMediaCounter.present) {
|
||||||
map['total_media_counter'] = Variable<int>(totalMediaCounter.value);
|
map['total_media_counter'] = Variable<int>(totalMediaCounter.value);
|
||||||
}
|
}
|
||||||
|
|
@ -1828,6 +1872,7 @@ class GroupsCompanion extends UpdateCompanion<Group> {
|
||||||
..write('stateEncryptionKey: $stateEncryptionKey, ')
|
..write('stateEncryptionKey: $stateEncryptionKey, ')
|
||||||
..write('myGroupPrivateKey: $myGroupPrivateKey, ')
|
..write('myGroupPrivateKey: $myGroupPrivateKey, ')
|
||||||
..write('groupName: $groupName, ')
|
..write('groupName: $groupName, ')
|
||||||
|
..write('draftMessage: $draftMessage, ')
|
||||||
..write('totalMediaCounter: $totalMediaCounter, ')
|
..write('totalMediaCounter: $totalMediaCounter, ')
|
||||||
..write('alsoBestFriend: $alsoBestFriend, ')
|
..write('alsoBestFriend: $alsoBestFriend, ')
|
||||||
..write(
|
..write(
|
||||||
|
|
@ -1886,16 +1931,6 @@ class $MediaFilesTable extends MediaFiles
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
'CHECK ("requires_authentication" IN (0, 1))'),
|
'CHECK ("requires_authentication" IN (0, 1))'),
|
||||||
defaultValue: const Constant(false));
|
defaultValue: const Constant(false));
|
||||||
static const VerificationMeta _reopenByContactMeta =
|
|
||||||
const VerificationMeta('reopenByContact');
|
|
||||||
@override
|
|
||||||
late final GeneratedColumn<bool> reopenByContact = GeneratedColumn<bool>(
|
|
||||||
'reopen_by_contact', aliasedName, false,
|
|
||||||
type: DriftSqlType.bool,
|
|
||||||
requiredDuringInsert: false,
|
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
|
||||||
'CHECK ("reopen_by_contact" IN (0, 1))'),
|
|
||||||
defaultValue: const Constant(false));
|
|
||||||
static const VerificationMeta _storedMeta = const VerificationMeta('stored');
|
static const VerificationMeta _storedMeta = const VerificationMeta('stored');
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumn<bool> stored = GeneratedColumn<bool>(
|
late final GeneratedColumn<bool> stored = GeneratedColumn<bool>(
|
||||||
|
|
@ -1976,7 +2011,6 @@ class $MediaFilesTable extends MediaFiles
|
||||||
uploadState,
|
uploadState,
|
||||||
downloadState,
|
downloadState,
|
||||||
requiresAuthentication,
|
requiresAuthentication,
|
||||||
reopenByContact,
|
|
||||||
stored,
|
stored,
|
||||||
isDraftMedia,
|
isDraftMedia,
|
||||||
reuploadRequestedBy,
|
reuploadRequestedBy,
|
||||||
|
|
@ -2010,12 +2044,6 @@ class $MediaFilesTable extends MediaFiles
|
||||||
requiresAuthentication.isAcceptableOrUnknown(
|
requiresAuthentication.isAcceptableOrUnknown(
|
||||||
data['requires_authentication']!, _requiresAuthenticationMeta));
|
data['requires_authentication']!, _requiresAuthenticationMeta));
|
||||||
}
|
}
|
||||||
if (data.containsKey('reopen_by_contact')) {
|
|
||||||
context.handle(
|
|
||||||
_reopenByContactMeta,
|
|
||||||
reopenByContact.isAcceptableOrUnknown(
|
|
||||||
data['reopen_by_contact']!, _reopenByContactMeta));
|
|
||||||
}
|
|
||||||
if (data.containsKey('stored')) {
|
if (data.containsKey('stored')) {
|
||||||
context.handle(_storedMeta,
|
context.handle(_storedMeta,
|
||||||
stored.isAcceptableOrUnknown(data['stored']!, _storedMeta));
|
stored.isAcceptableOrUnknown(data['stored']!, _storedMeta));
|
||||||
|
|
@ -2089,8 +2117,6 @@ class $MediaFilesTable extends MediaFiles
|
||||||
requiresAuthentication: attachedDatabase.typeMapping.read(
|
requiresAuthentication: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
data['${effectivePrefix}requires_authentication'])!,
|
data['${effectivePrefix}requires_authentication'])!,
|
||||||
reopenByContact: attachedDatabase.typeMapping.read(
|
|
||||||
DriftSqlType.bool, data['${effectivePrefix}reopen_by_contact'])!,
|
|
||||||
stored: attachedDatabase.typeMapping
|
stored: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.bool, data['${effectivePrefix}stored'])!,
|
.read(DriftSqlType.bool, data['${effectivePrefix}stored'])!,
|
||||||
isDraftMedia: attachedDatabase.typeMapping
|
isDraftMedia: attachedDatabase.typeMapping
|
||||||
|
|
@ -2146,7 +2172,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
final UploadState? uploadState;
|
final UploadState? uploadState;
|
||||||
final DownloadState? downloadState;
|
final DownloadState? downloadState;
|
||||||
final bool requiresAuthentication;
|
final bool requiresAuthentication;
|
||||||
final bool reopenByContact;
|
|
||||||
final bool stored;
|
final bool stored;
|
||||||
final bool isDraftMedia;
|
final bool isDraftMedia;
|
||||||
final List<int>? reuploadRequestedBy;
|
final List<int>? reuploadRequestedBy;
|
||||||
|
|
@ -2163,7 +2188,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
this.uploadState,
|
this.uploadState,
|
||||||
this.downloadState,
|
this.downloadState,
|
||||||
required this.requiresAuthentication,
|
required this.requiresAuthentication,
|
||||||
required this.reopenByContact,
|
|
||||||
required this.stored,
|
required this.stored,
|
||||||
required this.isDraftMedia,
|
required this.isDraftMedia,
|
||||||
this.reuploadRequestedBy,
|
this.reuploadRequestedBy,
|
||||||
|
|
@ -2191,7 +2215,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
$MediaFilesTable.$converterdownloadStaten.toSql(downloadState));
|
$MediaFilesTable.$converterdownloadStaten.toSql(downloadState));
|
||||||
}
|
}
|
||||||
map['requires_authentication'] = Variable<bool>(requiresAuthentication);
|
map['requires_authentication'] = Variable<bool>(requiresAuthentication);
|
||||||
map['reopen_by_contact'] = Variable<bool>(reopenByContact);
|
|
||||||
map['stored'] = Variable<bool>(stored);
|
map['stored'] = Variable<bool>(stored);
|
||||||
map['is_draft_media'] = Variable<bool>(isDraftMedia);
|
map['is_draft_media'] = Variable<bool>(isDraftMedia);
|
||||||
if (!nullToAbsent || reuploadRequestedBy != null) {
|
if (!nullToAbsent || reuploadRequestedBy != null) {
|
||||||
|
|
@ -2233,7 +2256,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(downloadState),
|
: Value(downloadState),
|
||||||
requiresAuthentication: Value(requiresAuthentication),
|
requiresAuthentication: Value(requiresAuthentication),
|
||||||
reopenByContact: Value(reopenByContact),
|
|
||||||
stored: Value(stored),
|
stored: Value(stored),
|
||||||
isDraftMedia: Value(isDraftMedia),
|
isDraftMedia: Value(isDraftMedia),
|
||||||
reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent
|
reuploadRequestedBy: reuploadRequestedBy == null && nullToAbsent
|
||||||
|
|
@ -2275,7 +2297,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
.fromJson(serializer.fromJson<String?>(json['downloadState'])),
|
.fromJson(serializer.fromJson<String?>(json['downloadState'])),
|
||||||
requiresAuthentication:
|
requiresAuthentication:
|
||||||
serializer.fromJson<bool>(json['requiresAuthentication']),
|
serializer.fromJson<bool>(json['requiresAuthentication']),
|
||||||
reopenByContact: serializer.fromJson<bool>(json['reopenByContact']),
|
|
||||||
stored: serializer.fromJson<bool>(json['stored']),
|
stored: serializer.fromJson<bool>(json['stored']),
|
||||||
isDraftMedia: serializer.fromJson<bool>(json['isDraftMedia']),
|
isDraftMedia: serializer.fromJson<bool>(json['isDraftMedia']),
|
||||||
reuploadRequestedBy:
|
reuploadRequestedBy:
|
||||||
|
|
@ -2302,7 +2323,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
'downloadState': serializer.toJson<String?>(
|
'downloadState': serializer.toJson<String?>(
|
||||||
$MediaFilesTable.$converterdownloadStaten.toJson(downloadState)),
|
$MediaFilesTable.$converterdownloadStaten.toJson(downloadState)),
|
||||||
'requiresAuthentication': serializer.toJson<bool>(requiresAuthentication),
|
'requiresAuthentication': serializer.toJson<bool>(requiresAuthentication),
|
||||||
'reopenByContact': serializer.toJson<bool>(reopenByContact),
|
|
||||||
'stored': serializer.toJson<bool>(stored),
|
'stored': serializer.toJson<bool>(stored),
|
||||||
'isDraftMedia': serializer.toJson<bool>(isDraftMedia),
|
'isDraftMedia': serializer.toJson<bool>(isDraftMedia),
|
||||||
'reuploadRequestedBy': serializer.toJson<List<int>?>(reuploadRequestedBy),
|
'reuploadRequestedBy': serializer.toJson<List<int>?>(reuploadRequestedBy),
|
||||||
|
|
@ -2323,7 +2343,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
Value<UploadState?> uploadState = const Value.absent(),
|
Value<UploadState?> uploadState = const Value.absent(),
|
||||||
Value<DownloadState?> downloadState = const Value.absent(),
|
Value<DownloadState?> downloadState = const Value.absent(),
|
||||||
bool? requiresAuthentication,
|
bool? requiresAuthentication,
|
||||||
bool? reopenByContact,
|
|
||||||
bool? stored,
|
bool? stored,
|
||||||
bool? isDraftMedia,
|
bool? isDraftMedia,
|
||||||
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
||||||
|
|
@ -2342,7 +2361,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
downloadState.present ? downloadState.value : this.downloadState,
|
downloadState.present ? downloadState.value : this.downloadState,
|
||||||
requiresAuthentication:
|
requiresAuthentication:
|
||||||
requiresAuthentication ?? this.requiresAuthentication,
|
requiresAuthentication ?? this.requiresAuthentication,
|
||||||
reopenByContact: reopenByContact ?? this.reopenByContact,
|
|
||||||
stored: stored ?? this.stored,
|
stored: stored ?? this.stored,
|
||||||
isDraftMedia: isDraftMedia ?? this.isDraftMedia,
|
isDraftMedia: isDraftMedia ?? this.isDraftMedia,
|
||||||
reuploadRequestedBy: reuploadRequestedBy.present
|
reuploadRequestedBy: reuploadRequestedBy.present
|
||||||
|
|
@ -2375,9 +2393,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
requiresAuthentication: data.requiresAuthentication.present
|
requiresAuthentication: data.requiresAuthentication.present
|
||||||
? data.requiresAuthentication.value
|
? data.requiresAuthentication.value
|
||||||
: this.requiresAuthentication,
|
: this.requiresAuthentication,
|
||||||
reopenByContact: data.reopenByContact.present
|
|
||||||
? data.reopenByContact.value
|
|
||||||
: this.reopenByContact,
|
|
||||||
stored: data.stored.present ? data.stored.value : this.stored,
|
stored: data.stored.present ? data.stored.value : this.stored,
|
||||||
isDraftMedia: data.isDraftMedia.present
|
isDraftMedia: data.isDraftMedia.present
|
||||||
? data.isDraftMedia.value
|
? data.isDraftMedia.value
|
||||||
|
|
@ -2414,7 +2429,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
..write('uploadState: $uploadState, ')
|
..write('uploadState: $uploadState, ')
|
||||||
..write('downloadState: $downloadState, ')
|
..write('downloadState: $downloadState, ')
|
||||||
..write('requiresAuthentication: $requiresAuthentication, ')
|
..write('requiresAuthentication: $requiresAuthentication, ')
|
||||||
..write('reopenByContact: $reopenByContact, ')
|
|
||||||
..write('stored: $stored, ')
|
..write('stored: $stored, ')
|
||||||
..write('isDraftMedia: $isDraftMedia, ')
|
..write('isDraftMedia: $isDraftMedia, ')
|
||||||
..write('reuploadRequestedBy: $reuploadRequestedBy, ')
|
..write('reuploadRequestedBy: $reuploadRequestedBy, ')
|
||||||
|
|
@ -2436,7 +2450,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
uploadState,
|
uploadState,
|
||||||
downloadState,
|
downloadState,
|
||||||
requiresAuthentication,
|
requiresAuthentication,
|
||||||
reopenByContact,
|
|
||||||
stored,
|
stored,
|
||||||
isDraftMedia,
|
isDraftMedia,
|
||||||
reuploadRequestedBy,
|
reuploadRequestedBy,
|
||||||
|
|
@ -2456,7 +2469,6 @@ class MediaFile extends DataClass implements Insertable<MediaFile> {
|
||||||
other.uploadState == this.uploadState &&
|
other.uploadState == this.uploadState &&
|
||||||
other.downloadState == this.downloadState &&
|
other.downloadState == this.downloadState &&
|
||||||
other.requiresAuthentication == this.requiresAuthentication &&
|
other.requiresAuthentication == this.requiresAuthentication &&
|
||||||
other.reopenByContact == this.reopenByContact &&
|
|
||||||
other.stored == this.stored &&
|
other.stored == this.stored &&
|
||||||
other.isDraftMedia == this.isDraftMedia &&
|
other.isDraftMedia == this.isDraftMedia &&
|
||||||
other.reuploadRequestedBy == this.reuploadRequestedBy &&
|
other.reuploadRequestedBy == this.reuploadRequestedBy &&
|
||||||
|
|
@ -2476,7 +2488,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
final Value<UploadState?> uploadState;
|
final Value<UploadState?> uploadState;
|
||||||
final Value<DownloadState?> downloadState;
|
final Value<DownloadState?> downloadState;
|
||||||
final Value<bool> requiresAuthentication;
|
final Value<bool> requiresAuthentication;
|
||||||
final Value<bool> reopenByContact;
|
|
||||||
final Value<bool> stored;
|
final Value<bool> stored;
|
||||||
final Value<bool> isDraftMedia;
|
final Value<bool> isDraftMedia;
|
||||||
final Value<List<int>?> reuploadRequestedBy;
|
final Value<List<int>?> reuploadRequestedBy;
|
||||||
|
|
@ -2494,7 +2505,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
this.uploadState = const Value.absent(),
|
this.uploadState = const Value.absent(),
|
||||||
this.downloadState = const Value.absent(),
|
this.downloadState = const Value.absent(),
|
||||||
this.requiresAuthentication = const Value.absent(),
|
this.requiresAuthentication = const Value.absent(),
|
||||||
this.reopenByContact = const Value.absent(),
|
|
||||||
this.stored = const Value.absent(),
|
this.stored = const Value.absent(),
|
||||||
this.isDraftMedia = const Value.absent(),
|
this.isDraftMedia = const Value.absent(),
|
||||||
this.reuploadRequestedBy = const Value.absent(),
|
this.reuploadRequestedBy = const Value.absent(),
|
||||||
|
|
@ -2513,7 +2523,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
this.uploadState = const Value.absent(),
|
this.uploadState = const Value.absent(),
|
||||||
this.downloadState = const Value.absent(),
|
this.downloadState = const Value.absent(),
|
||||||
this.requiresAuthentication = const Value.absent(),
|
this.requiresAuthentication = const Value.absent(),
|
||||||
this.reopenByContact = const Value.absent(),
|
|
||||||
this.stored = const Value.absent(),
|
this.stored = const Value.absent(),
|
||||||
this.isDraftMedia = const Value.absent(),
|
this.isDraftMedia = const Value.absent(),
|
||||||
this.reuploadRequestedBy = const Value.absent(),
|
this.reuploadRequestedBy = const Value.absent(),
|
||||||
|
|
@ -2533,7 +2542,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
Expression<String>? uploadState,
|
Expression<String>? uploadState,
|
||||||
Expression<String>? downloadState,
|
Expression<String>? downloadState,
|
||||||
Expression<bool>? requiresAuthentication,
|
Expression<bool>? requiresAuthentication,
|
||||||
Expression<bool>? reopenByContact,
|
|
||||||
Expression<bool>? stored,
|
Expression<bool>? stored,
|
||||||
Expression<bool>? isDraftMedia,
|
Expression<bool>? isDraftMedia,
|
||||||
Expression<String>? reuploadRequestedBy,
|
Expression<String>? reuploadRequestedBy,
|
||||||
|
|
@ -2553,7 +2561,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
if (downloadState != null) 'download_state': downloadState,
|
if (downloadState != null) 'download_state': downloadState,
|
||||||
if (requiresAuthentication != null)
|
if (requiresAuthentication != null)
|
||||||
'requires_authentication': requiresAuthentication,
|
'requires_authentication': requiresAuthentication,
|
||||||
if (reopenByContact != null) 'reopen_by_contact': reopenByContact,
|
|
||||||
if (stored != null) 'stored': stored,
|
if (stored != null) 'stored': stored,
|
||||||
if (isDraftMedia != null) 'is_draft_media': isDraftMedia,
|
if (isDraftMedia != null) 'is_draft_media': isDraftMedia,
|
||||||
if (reuploadRequestedBy != null)
|
if (reuploadRequestedBy != null)
|
||||||
|
|
@ -2576,7 +2583,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
Value<UploadState?>? uploadState,
|
Value<UploadState?>? uploadState,
|
||||||
Value<DownloadState?>? downloadState,
|
Value<DownloadState?>? downloadState,
|
||||||
Value<bool>? requiresAuthentication,
|
Value<bool>? requiresAuthentication,
|
||||||
Value<bool>? reopenByContact,
|
|
||||||
Value<bool>? stored,
|
Value<bool>? stored,
|
||||||
Value<bool>? isDraftMedia,
|
Value<bool>? isDraftMedia,
|
||||||
Value<List<int>?>? reuploadRequestedBy,
|
Value<List<int>?>? reuploadRequestedBy,
|
||||||
|
|
@ -2595,7 +2601,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
downloadState: downloadState ?? this.downloadState,
|
downloadState: downloadState ?? this.downloadState,
|
||||||
requiresAuthentication:
|
requiresAuthentication:
|
||||||
requiresAuthentication ?? this.requiresAuthentication,
|
requiresAuthentication ?? this.requiresAuthentication,
|
||||||
reopenByContact: reopenByContact ?? this.reopenByContact,
|
|
||||||
stored: stored ?? this.stored,
|
stored: stored ?? this.stored,
|
||||||
isDraftMedia: isDraftMedia ?? this.isDraftMedia,
|
isDraftMedia: isDraftMedia ?? this.isDraftMedia,
|
||||||
reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy,
|
reuploadRequestedBy: reuploadRequestedBy ?? this.reuploadRequestedBy,
|
||||||
|
|
@ -2633,9 +2638,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
map['requires_authentication'] =
|
map['requires_authentication'] =
|
||||||
Variable<bool>(requiresAuthentication.value);
|
Variable<bool>(requiresAuthentication.value);
|
||||||
}
|
}
|
||||||
if (reopenByContact.present) {
|
|
||||||
map['reopen_by_contact'] = Variable<bool>(reopenByContact.value);
|
|
||||||
}
|
|
||||||
if (stored.present) {
|
if (stored.present) {
|
||||||
map['stored'] = Variable<bool>(stored.value);
|
map['stored'] = Variable<bool>(stored.value);
|
||||||
}
|
}
|
||||||
|
|
@ -2683,7 +2685,6 @@ class MediaFilesCompanion extends UpdateCompanion<MediaFile> {
|
||||||
..write('uploadState: $uploadState, ')
|
..write('uploadState: $uploadState, ')
|
||||||
..write('downloadState: $downloadState, ')
|
..write('downloadState: $downloadState, ')
|
||||||
..write('requiresAuthentication: $requiresAuthentication, ')
|
..write('requiresAuthentication: $requiresAuthentication, ')
|
||||||
..write('reopenByContact: $reopenByContact, ')
|
|
||||||
..write('stored: $stored, ')
|
..write('stored: $stored, ')
|
||||||
..write('isDraftMedia: $isDraftMedia, ')
|
..write('isDraftMedia: $isDraftMedia, ')
|
||||||
..write('reuploadRequestedBy: $reuploadRequestedBy, ')
|
..write('reuploadRequestedBy: $reuploadRequestedBy, ')
|
||||||
|
|
@ -2759,6 +2760,16 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
'CHECK ("media_stored" IN (0, 1))'),
|
'CHECK ("media_stored" IN (0, 1))'),
|
||||||
defaultValue: const Constant(false));
|
defaultValue: const Constant(false));
|
||||||
|
static const VerificationMeta _mediaReopenedMeta =
|
||||||
|
const VerificationMeta('mediaReopened');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<bool> mediaReopened = GeneratedColumn<bool>(
|
||||||
|
'media_reopened', aliasedName, false,
|
||||||
|
type: DriftSqlType.bool,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
|
'CHECK ("media_reopened" IN (0, 1))'),
|
||||||
|
defaultValue: const Constant(false));
|
||||||
static const VerificationMeta _downloadTokenMeta =
|
static const VerificationMeta _downloadTokenMeta =
|
||||||
const VerificationMeta('downloadToken');
|
const VerificationMeta('downloadToken');
|
||||||
@override
|
@override
|
||||||
|
|
@ -2828,6 +2839,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
||||||
content,
|
content,
|
||||||
mediaId,
|
mediaId,
|
||||||
mediaStored,
|
mediaStored,
|
||||||
|
mediaReopened,
|
||||||
downloadToken,
|
downloadToken,
|
||||||
quotesMessageId,
|
quotesMessageId,
|
||||||
isDeletedFromSender,
|
isDeletedFromSender,
|
||||||
|
|
@ -2878,6 +2890,12 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
||||||
mediaStored.isAcceptableOrUnknown(
|
mediaStored.isAcceptableOrUnknown(
|
||||||
data['media_stored']!, _mediaStoredMeta));
|
data['media_stored']!, _mediaStoredMeta));
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('media_reopened')) {
|
||||||
|
context.handle(
|
||||||
|
_mediaReopenedMeta,
|
||||||
|
mediaReopened.isAcceptableOrUnknown(
|
||||||
|
data['media_reopened']!, _mediaReopenedMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('download_token')) {
|
if (data.containsKey('download_token')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_downloadTokenMeta,
|
_downloadTokenMeta,
|
||||||
|
|
@ -2951,6 +2969,8 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
||||||
.read(DriftSqlType.string, data['${effectivePrefix}media_id']),
|
.read(DriftSqlType.string, data['${effectivePrefix}media_id']),
|
||||||
mediaStored: attachedDatabase.typeMapping
|
mediaStored: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.bool, data['${effectivePrefix}media_stored'])!,
|
.read(DriftSqlType.bool, data['${effectivePrefix}media_stored'])!,
|
||||||
|
mediaReopened: attachedDatabase.typeMapping
|
||||||
|
.read(DriftSqlType.bool, data['${effectivePrefix}media_reopened'])!,
|
||||||
downloadToken: attachedDatabase.typeMapping
|
downloadToken: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.blob, data['${effectivePrefix}download_token']),
|
.read(DriftSqlType.blob, data['${effectivePrefix}download_token']),
|
||||||
quotesMessageId: attachedDatabase.typeMapping.read(
|
quotesMessageId: attachedDatabase.typeMapping.read(
|
||||||
|
|
@ -2989,6 +3009,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
final String? content;
|
final String? content;
|
||||||
final String? mediaId;
|
final String? mediaId;
|
||||||
final bool mediaStored;
|
final bool mediaStored;
|
||||||
|
final bool mediaReopened;
|
||||||
final Uint8List? downloadToken;
|
final Uint8List? downloadToken;
|
||||||
final String? quotesMessageId;
|
final String? quotesMessageId;
|
||||||
final bool isDeletedFromSender;
|
final bool isDeletedFromSender;
|
||||||
|
|
@ -3006,6 +3027,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
this.content,
|
this.content,
|
||||||
this.mediaId,
|
this.mediaId,
|
||||||
required this.mediaStored,
|
required this.mediaStored,
|
||||||
|
required this.mediaReopened,
|
||||||
this.downloadToken,
|
this.downloadToken,
|
||||||
this.quotesMessageId,
|
this.quotesMessageId,
|
||||||
required this.isDeletedFromSender,
|
required this.isDeletedFromSender,
|
||||||
|
|
@ -3033,6 +3055,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
map['media_id'] = Variable<String>(mediaId);
|
map['media_id'] = Variable<String>(mediaId);
|
||||||
}
|
}
|
||||||
map['media_stored'] = Variable<bool>(mediaStored);
|
map['media_stored'] = Variable<bool>(mediaStored);
|
||||||
|
map['media_reopened'] = Variable<bool>(mediaReopened);
|
||||||
if (!nullToAbsent || downloadToken != null) {
|
if (!nullToAbsent || downloadToken != null) {
|
||||||
map['download_token'] = Variable<Uint8List>(downloadToken);
|
map['download_token'] = Variable<Uint8List>(downloadToken);
|
||||||
}
|
}
|
||||||
|
|
@ -3074,6 +3097,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(mediaId),
|
: Value(mediaId),
|
||||||
mediaStored: Value(mediaStored),
|
mediaStored: Value(mediaStored),
|
||||||
|
mediaReopened: Value(mediaReopened),
|
||||||
downloadToken: downloadToken == null && nullToAbsent
|
downloadToken: downloadToken == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(downloadToken),
|
: Value(downloadToken),
|
||||||
|
|
@ -3112,6 +3136,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
content: serializer.fromJson<String?>(json['content']),
|
content: serializer.fromJson<String?>(json['content']),
|
||||||
mediaId: serializer.fromJson<String?>(json['mediaId']),
|
mediaId: serializer.fromJson<String?>(json['mediaId']),
|
||||||
mediaStored: serializer.fromJson<bool>(json['mediaStored']),
|
mediaStored: serializer.fromJson<bool>(json['mediaStored']),
|
||||||
|
mediaReopened: serializer.fromJson<bool>(json['mediaReopened']),
|
||||||
downloadToken: serializer.fromJson<Uint8List?>(json['downloadToken']),
|
downloadToken: serializer.fromJson<Uint8List?>(json['downloadToken']),
|
||||||
quotesMessageId: serializer.fromJson<String?>(json['quotesMessageId']),
|
quotesMessageId: serializer.fromJson<String?>(json['quotesMessageId']),
|
||||||
isDeletedFromSender:
|
isDeletedFromSender:
|
||||||
|
|
@ -3136,6 +3161,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
'content': serializer.toJson<String?>(content),
|
'content': serializer.toJson<String?>(content),
|
||||||
'mediaId': serializer.toJson<String?>(mediaId),
|
'mediaId': serializer.toJson<String?>(mediaId),
|
||||||
'mediaStored': serializer.toJson<bool>(mediaStored),
|
'mediaStored': serializer.toJson<bool>(mediaStored),
|
||||||
|
'mediaReopened': serializer.toJson<bool>(mediaReopened),
|
||||||
'downloadToken': serializer.toJson<Uint8List?>(downloadToken),
|
'downloadToken': serializer.toJson<Uint8List?>(downloadToken),
|
||||||
'quotesMessageId': serializer.toJson<String?>(quotesMessageId),
|
'quotesMessageId': serializer.toJson<String?>(quotesMessageId),
|
||||||
'isDeletedFromSender': serializer.toJson<bool>(isDeletedFromSender),
|
'isDeletedFromSender': serializer.toJson<bool>(isDeletedFromSender),
|
||||||
|
|
@ -3156,6 +3182,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
Value<String?> content = const Value.absent(),
|
Value<String?> content = const Value.absent(),
|
||||||
Value<String?> mediaId = const Value.absent(),
|
Value<String?> mediaId = const Value.absent(),
|
||||||
bool? mediaStored,
|
bool? mediaStored,
|
||||||
|
bool? mediaReopened,
|
||||||
Value<Uint8List?> downloadToken = const Value.absent(),
|
Value<Uint8List?> downloadToken = const Value.absent(),
|
||||||
Value<String?> quotesMessageId = const Value.absent(),
|
Value<String?> quotesMessageId = const Value.absent(),
|
||||||
bool? isDeletedFromSender,
|
bool? isDeletedFromSender,
|
||||||
|
|
@ -3173,6 +3200,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
content: content.present ? content.value : this.content,
|
content: content.present ? content.value : this.content,
|
||||||
mediaId: mediaId.present ? mediaId.value : this.mediaId,
|
mediaId: mediaId.present ? mediaId.value : this.mediaId,
|
||||||
mediaStored: mediaStored ?? this.mediaStored,
|
mediaStored: mediaStored ?? this.mediaStored,
|
||||||
|
mediaReopened: mediaReopened ?? this.mediaReopened,
|
||||||
downloadToken:
|
downloadToken:
|
||||||
downloadToken.present ? downloadToken.value : this.downloadToken,
|
downloadToken.present ? downloadToken.value : this.downloadToken,
|
||||||
quotesMessageId: quotesMessageId.present
|
quotesMessageId: quotesMessageId.present
|
||||||
|
|
@ -3196,6 +3224,9 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId,
|
mediaId: data.mediaId.present ? data.mediaId.value : this.mediaId,
|
||||||
mediaStored:
|
mediaStored:
|
||||||
data.mediaStored.present ? data.mediaStored.value : this.mediaStored,
|
data.mediaStored.present ? data.mediaStored.value : this.mediaStored,
|
||||||
|
mediaReopened: data.mediaReopened.present
|
||||||
|
? data.mediaReopened.value
|
||||||
|
: this.mediaReopened,
|
||||||
downloadToken: data.downloadToken.present
|
downloadToken: data.downloadToken.present
|
||||||
? data.downloadToken.value
|
? data.downloadToken.value
|
||||||
: this.downloadToken,
|
: this.downloadToken,
|
||||||
|
|
@ -3227,6 +3258,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('mediaId: $mediaId, ')
|
..write('mediaId: $mediaId, ')
|
||||||
..write('mediaStored: $mediaStored, ')
|
..write('mediaStored: $mediaStored, ')
|
||||||
|
..write('mediaReopened: $mediaReopened, ')
|
||||||
..write('downloadToken: $downloadToken, ')
|
..write('downloadToken: $downloadToken, ')
|
||||||
..write('quotesMessageId: $quotesMessageId, ')
|
..write('quotesMessageId: $quotesMessageId, ')
|
||||||
..write('isDeletedFromSender: $isDeletedFromSender, ')
|
..write('isDeletedFromSender: $isDeletedFromSender, ')
|
||||||
|
|
@ -3249,6 +3281,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
content,
|
content,
|
||||||
mediaId,
|
mediaId,
|
||||||
mediaStored,
|
mediaStored,
|
||||||
|
mediaReopened,
|
||||||
$driftBlobEquality.hash(downloadToken),
|
$driftBlobEquality.hash(downloadToken),
|
||||||
quotesMessageId,
|
quotesMessageId,
|
||||||
isDeletedFromSender,
|
isDeletedFromSender,
|
||||||
|
|
@ -3269,6 +3302,7 @@ class Message extends DataClass implements Insertable<Message> {
|
||||||
other.content == this.content &&
|
other.content == this.content &&
|
||||||
other.mediaId == this.mediaId &&
|
other.mediaId == this.mediaId &&
|
||||||
other.mediaStored == this.mediaStored &&
|
other.mediaStored == this.mediaStored &&
|
||||||
|
other.mediaReopened == this.mediaReopened &&
|
||||||
$driftBlobEquality.equals(other.downloadToken, this.downloadToken) &&
|
$driftBlobEquality.equals(other.downloadToken, this.downloadToken) &&
|
||||||
other.quotesMessageId == this.quotesMessageId &&
|
other.quotesMessageId == this.quotesMessageId &&
|
||||||
other.isDeletedFromSender == this.isDeletedFromSender &&
|
other.isDeletedFromSender == this.isDeletedFromSender &&
|
||||||
|
|
@ -3288,6 +3322,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
final Value<String?> content;
|
final Value<String?> content;
|
||||||
final Value<String?> mediaId;
|
final Value<String?> mediaId;
|
||||||
final Value<bool> mediaStored;
|
final Value<bool> mediaStored;
|
||||||
|
final Value<bool> mediaReopened;
|
||||||
final Value<Uint8List?> downloadToken;
|
final Value<Uint8List?> downloadToken;
|
||||||
final Value<String?> quotesMessageId;
|
final Value<String?> quotesMessageId;
|
||||||
final Value<bool> isDeletedFromSender;
|
final Value<bool> isDeletedFromSender;
|
||||||
|
|
@ -3306,6 +3341,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
this.content = const Value.absent(),
|
this.content = const Value.absent(),
|
||||||
this.mediaId = const Value.absent(),
|
this.mediaId = const Value.absent(),
|
||||||
this.mediaStored = const Value.absent(),
|
this.mediaStored = const Value.absent(),
|
||||||
|
this.mediaReopened = const Value.absent(),
|
||||||
this.downloadToken = const Value.absent(),
|
this.downloadToken = const Value.absent(),
|
||||||
this.quotesMessageId = const Value.absent(),
|
this.quotesMessageId = const Value.absent(),
|
||||||
this.isDeletedFromSender = const Value.absent(),
|
this.isDeletedFromSender = const Value.absent(),
|
||||||
|
|
@ -3325,6 +3361,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
this.content = const Value.absent(),
|
this.content = const Value.absent(),
|
||||||
this.mediaId = const Value.absent(),
|
this.mediaId = const Value.absent(),
|
||||||
this.mediaStored = const Value.absent(),
|
this.mediaStored = const Value.absent(),
|
||||||
|
this.mediaReopened = const Value.absent(),
|
||||||
this.downloadToken = const Value.absent(),
|
this.downloadToken = const Value.absent(),
|
||||||
this.quotesMessageId = const Value.absent(),
|
this.quotesMessageId = const Value.absent(),
|
||||||
this.isDeletedFromSender = const Value.absent(),
|
this.isDeletedFromSender = const Value.absent(),
|
||||||
|
|
@ -3346,6 +3383,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
Expression<String>? content,
|
Expression<String>? content,
|
||||||
Expression<String>? mediaId,
|
Expression<String>? mediaId,
|
||||||
Expression<bool>? mediaStored,
|
Expression<bool>? mediaStored,
|
||||||
|
Expression<bool>? mediaReopened,
|
||||||
Expression<Uint8List>? downloadToken,
|
Expression<Uint8List>? downloadToken,
|
||||||
Expression<String>? quotesMessageId,
|
Expression<String>? quotesMessageId,
|
||||||
Expression<bool>? isDeletedFromSender,
|
Expression<bool>? isDeletedFromSender,
|
||||||
|
|
@ -3365,6 +3403,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
if (content != null) 'content': content,
|
if (content != null) 'content': content,
|
||||||
if (mediaId != null) 'media_id': mediaId,
|
if (mediaId != null) 'media_id': mediaId,
|
||||||
if (mediaStored != null) 'media_stored': mediaStored,
|
if (mediaStored != null) 'media_stored': mediaStored,
|
||||||
|
if (mediaReopened != null) 'media_reopened': mediaReopened,
|
||||||
if (downloadToken != null) 'download_token': downloadToken,
|
if (downloadToken != null) 'download_token': downloadToken,
|
||||||
if (quotesMessageId != null) 'quotes_message_id': quotesMessageId,
|
if (quotesMessageId != null) 'quotes_message_id': quotesMessageId,
|
||||||
if (isDeletedFromSender != null)
|
if (isDeletedFromSender != null)
|
||||||
|
|
@ -3387,6 +3426,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
Value<String?>? content,
|
Value<String?>? content,
|
||||||
Value<String?>? mediaId,
|
Value<String?>? mediaId,
|
||||||
Value<bool>? mediaStored,
|
Value<bool>? mediaStored,
|
||||||
|
Value<bool>? mediaReopened,
|
||||||
Value<Uint8List?>? downloadToken,
|
Value<Uint8List?>? downloadToken,
|
||||||
Value<String?>? quotesMessageId,
|
Value<String?>? quotesMessageId,
|
||||||
Value<bool>? isDeletedFromSender,
|
Value<bool>? isDeletedFromSender,
|
||||||
|
|
@ -3405,6 +3445,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
content: content ?? this.content,
|
content: content ?? this.content,
|
||||||
mediaId: mediaId ?? this.mediaId,
|
mediaId: mediaId ?? this.mediaId,
|
||||||
mediaStored: mediaStored ?? this.mediaStored,
|
mediaStored: mediaStored ?? this.mediaStored,
|
||||||
|
mediaReopened: mediaReopened ?? this.mediaReopened,
|
||||||
downloadToken: downloadToken ?? this.downloadToken,
|
downloadToken: downloadToken ?? this.downloadToken,
|
||||||
quotesMessageId: quotesMessageId ?? this.quotesMessageId,
|
quotesMessageId: quotesMessageId ?? this.quotesMessageId,
|
||||||
isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender,
|
isDeletedFromSender: isDeletedFromSender ?? this.isDeletedFromSender,
|
||||||
|
|
@ -3443,6 +3484,9 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
if (mediaStored.present) {
|
if (mediaStored.present) {
|
||||||
map['media_stored'] = Variable<bool>(mediaStored.value);
|
map['media_stored'] = Variable<bool>(mediaStored.value);
|
||||||
}
|
}
|
||||||
|
if (mediaReopened.present) {
|
||||||
|
map['media_reopened'] = Variable<bool>(mediaReopened.value);
|
||||||
|
}
|
||||||
if (downloadToken.present) {
|
if (downloadToken.present) {
|
||||||
map['download_token'] = Variable<Uint8List>(downloadToken.value);
|
map['download_token'] = Variable<Uint8List>(downloadToken.value);
|
||||||
}
|
}
|
||||||
|
|
@ -3486,6 +3530,7 @@ class MessagesCompanion extends UpdateCompanion<Message> {
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('mediaId: $mediaId, ')
|
..write('mediaId: $mediaId, ')
|
||||||
..write('mediaStored: $mediaStored, ')
|
..write('mediaStored: $mediaStored, ')
|
||||||
|
..write('mediaReopened: $mediaReopened, ')
|
||||||
..write('downloadToken: $downloadToken, ')
|
..write('downloadToken: $downloadToken, ')
|
||||||
..write('quotesMessageId: $quotesMessageId, ')
|
..write('quotesMessageId: $quotesMessageId, ')
|
||||||
..write('isDeletedFromSender: $isDeletedFromSender, ')
|
..write('isDeletedFromSender: $isDeletedFromSender, ')
|
||||||
|
|
@ -8495,6 +8540,7 @@ typedef $$GroupsTableCreateCompanionBuilder = GroupsCompanion Function({
|
||||||
Value<Uint8List?> stateEncryptionKey,
|
Value<Uint8List?> stateEncryptionKey,
|
||||||
Value<Uint8List?> myGroupPrivateKey,
|
Value<Uint8List?> myGroupPrivateKey,
|
||||||
required String groupName,
|
required String groupName,
|
||||||
|
Value<String?> draftMessage,
|
||||||
Value<int> totalMediaCounter,
|
Value<int> totalMediaCounter,
|
||||||
Value<bool> alsoBestFriend,
|
Value<bool> alsoBestFriend,
|
||||||
Value<int> deleteMessagesAfterMilliseconds,
|
Value<int> deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -8522,6 +8568,7 @@ typedef $$GroupsTableUpdateCompanionBuilder = GroupsCompanion Function({
|
||||||
Value<Uint8List?> stateEncryptionKey,
|
Value<Uint8List?> stateEncryptionKey,
|
||||||
Value<Uint8List?> myGroupPrivateKey,
|
Value<Uint8List?> myGroupPrivateKey,
|
||||||
Value<String> groupName,
|
Value<String> groupName,
|
||||||
|
Value<String?> draftMessage,
|
||||||
Value<int> totalMediaCounter,
|
Value<int> totalMediaCounter,
|
||||||
Value<bool> alsoBestFriend,
|
Value<bool> alsoBestFriend,
|
||||||
Value<int> deleteMessagesAfterMilliseconds,
|
Value<int> deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -8637,6 +8684,9 @@ class $$GroupsTableFilterComposer extends Composer<_$TwonlyDB, $GroupsTable> {
|
||||||
ColumnFilters<String> get groupName => $composableBuilder(
|
ColumnFilters<String> get groupName => $composableBuilder(
|
||||||
column: $table.groupName, builder: (column) => ColumnFilters(column));
|
column: $table.groupName, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
ColumnFilters<String> get draftMessage => $composableBuilder(
|
||||||
|
column: $table.draftMessage, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
ColumnFilters<int> get totalMediaCounter => $composableBuilder(
|
ColumnFilters<int> get totalMediaCounter => $composableBuilder(
|
||||||
column: $table.totalMediaCounter,
|
column: $table.totalMediaCounter,
|
||||||
builder: (column) => ColumnFilters(column));
|
builder: (column) => ColumnFilters(column));
|
||||||
|
|
@ -8796,6 +8846,10 @@ class $$GroupsTableOrderingComposer extends Composer<_$TwonlyDB, $GroupsTable> {
|
||||||
ColumnOrderings<String> get groupName => $composableBuilder(
|
ColumnOrderings<String> get groupName => $composableBuilder(
|
||||||
column: $table.groupName, builder: (column) => ColumnOrderings(column));
|
column: $table.groupName, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
ColumnOrderings<String> get draftMessage => $composableBuilder(
|
||||||
|
column: $table.draftMessage,
|
||||||
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
ColumnOrderings<int> get totalMediaCounter => $composableBuilder(
|
ColumnOrderings<int> get totalMediaCounter => $composableBuilder(
|
||||||
column: $table.totalMediaCounter,
|
column: $table.totalMediaCounter,
|
||||||
builder: (column) => ColumnOrderings(column));
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
@ -8890,6 +8944,9 @@ class $$GroupsTableAnnotationComposer
|
||||||
GeneratedColumn<String> get groupName =>
|
GeneratedColumn<String> get groupName =>
|
||||||
$composableBuilder(column: $table.groupName, builder: (column) => column);
|
$composableBuilder(column: $table.groupName, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get draftMessage => $composableBuilder(
|
||||||
|
column: $table.draftMessage, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<int> get totalMediaCounter => $composableBuilder(
|
GeneratedColumn<int> get totalMediaCounter => $composableBuilder(
|
||||||
column: $table.totalMediaCounter, builder: (column) => column);
|
column: $table.totalMediaCounter, builder: (column) => column);
|
||||||
|
|
||||||
|
|
@ -9028,6 +9085,7 @@ class $$GroupsTableTableManager extends RootTableManager<
|
||||||
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
||||||
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
||||||
Value<String> groupName = const Value.absent(),
|
Value<String> groupName = const Value.absent(),
|
||||||
|
Value<String?> draftMessage = const Value.absent(),
|
||||||
Value<int> totalMediaCounter = const Value.absent(),
|
Value<int> totalMediaCounter = const Value.absent(),
|
||||||
Value<bool> alsoBestFriend = const Value.absent(),
|
Value<bool> alsoBestFriend = const Value.absent(),
|
||||||
Value<int> deleteMessagesAfterMilliseconds = const Value.absent(),
|
Value<int> deleteMessagesAfterMilliseconds = const Value.absent(),
|
||||||
|
|
@ -9055,6 +9113,7 @@ class $$GroupsTableTableManager extends RootTableManager<
|
||||||
stateEncryptionKey: stateEncryptionKey,
|
stateEncryptionKey: stateEncryptionKey,
|
||||||
myGroupPrivateKey: myGroupPrivateKey,
|
myGroupPrivateKey: myGroupPrivateKey,
|
||||||
groupName: groupName,
|
groupName: groupName,
|
||||||
|
draftMessage: draftMessage,
|
||||||
totalMediaCounter: totalMediaCounter,
|
totalMediaCounter: totalMediaCounter,
|
||||||
alsoBestFriend: alsoBestFriend,
|
alsoBestFriend: alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds,
|
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -9082,6 +9141,7 @@ class $$GroupsTableTableManager extends RootTableManager<
|
||||||
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
Value<Uint8List?> stateEncryptionKey = const Value.absent(),
|
||||||
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
Value<Uint8List?> myGroupPrivateKey = const Value.absent(),
|
||||||
required String groupName,
|
required String groupName,
|
||||||
|
Value<String?> draftMessage = const Value.absent(),
|
||||||
Value<int> totalMediaCounter = const Value.absent(),
|
Value<int> totalMediaCounter = const Value.absent(),
|
||||||
Value<bool> alsoBestFriend = const Value.absent(),
|
Value<bool> alsoBestFriend = const Value.absent(),
|
||||||
Value<int> deleteMessagesAfterMilliseconds = const Value.absent(),
|
Value<int> deleteMessagesAfterMilliseconds = const Value.absent(),
|
||||||
|
|
@ -9109,6 +9169,7 @@ class $$GroupsTableTableManager extends RootTableManager<
|
||||||
stateEncryptionKey: stateEncryptionKey,
|
stateEncryptionKey: stateEncryptionKey,
|
||||||
myGroupPrivateKey: myGroupPrivateKey,
|
myGroupPrivateKey: myGroupPrivateKey,
|
||||||
groupName: groupName,
|
groupName: groupName,
|
||||||
|
draftMessage: draftMessage,
|
||||||
totalMediaCounter: totalMediaCounter,
|
totalMediaCounter: totalMediaCounter,
|
||||||
alsoBestFriend: alsoBestFriend,
|
alsoBestFriend: alsoBestFriend,
|
||||||
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds,
|
deleteMessagesAfterMilliseconds: deleteMessagesAfterMilliseconds,
|
||||||
|
|
@ -9203,7 +9264,6 @@ typedef $$MediaFilesTableCreateCompanionBuilder = MediaFilesCompanion Function({
|
||||||
Value<UploadState?> uploadState,
|
Value<UploadState?> uploadState,
|
||||||
Value<DownloadState?> downloadState,
|
Value<DownloadState?> downloadState,
|
||||||
Value<bool> requiresAuthentication,
|
Value<bool> requiresAuthentication,
|
||||||
Value<bool> reopenByContact,
|
|
||||||
Value<bool> stored,
|
Value<bool> stored,
|
||||||
Value<bool> isDraftMedia,
|
Value<bool> isDraftMedia,
|
||||||
Value<List<int>?> reuploadRequestedBy,
|
Value<List<int>?> reuploadRequestedBy,
|
||||||
|
|
@ -9222,7 +9282,6 @@ typedef $$MediaFilesTableUpdateCompanionBuilder = MediaFilesCompanion Function({
|
||||||
Value<UploadState?> uploadState,
|
Value<UploadState?> uploadState,
|
||||||
Value<DownloadState?> downloadState,
|
Value<DownloadState?> downloadState,
|
||||||
Value<bool> requiresAuthentication,
|
Value<bool> requiresAuthentication,
|
||||||
Value<bool> reopenByContact,
|
|
||||||
Value<bool> stored,
|
Value<bool> stored,
|
||||||
Value<bool> isDraftMedia,
|
Value<bool> isDraftMedia,
|
||||||
Value<List<int>?> reuploadRequestedBy,
|
Value<List<int>?> reuploadRequestedBy,
|
||||||
|
|
@ -9287,10 +9346,6 @@ class $$MediaFilesTableFilterComposer
|
||||||
column: $table.requiresAuthentication,
|
column: $table.requiresAuthentication,
|
||||||
builder: (column) => ColumnFilters(column));
|
builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
ColumnFilters<bool> get reopenByContact => $composableBuilder(
|
|
||||||
column: $table.reopenByContact,
|
|
||||||
builder: (column) => ColumnFilters(column));
|
|
||||||
|
|
||||||
ColumnFilters<bool> get stored => $composableBuilder(
|
ColumnFilters<bool> get stored => $composableBuilder(
|
||||||
column: $table.stored, builder: (column) => ColumnFilters(column));
|
column: $table.stored, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
|
@ -9373,10 +9428,6 @@ class $$MediaFilesTableOrderingComposer
|
||||||
column: $table.requiresAuthentication,
|
column: $table.requiresAuthentication,
|
||||||
builder: (column) => ColumnOrderings(column));
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
ColumnOrderings<bool> get reopenByContact => $composableBuilder(
|
|
||||||
column: $table.reopenByContact,
|
|
||||||
builder: (column) => ColumnOrderings(column));
|
|
||||||
|
|
||||||
ColumnOrderings<bool> get stored => $composableBuilder(
|
ColumnOrderings<bool> get stored => $composableBuilder(
|
||||||
column: $table.stored, builder: (column) => ColumnOrderings(column));
|
column: $table.stored, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
|
@ -9441,9 +9492,6 @@ class $$MediaFilesTableAnnotationComposer
|
||||||
GeneratedColumn<bool> get requiresAuthentication => $composableBuilder(
|
GeneratedColumn<bool> get requiresAuthentication => $composableBuilder(
|
||||||
column: $table.requiresAuthentication, builder: (column) => column);
|
column: $table.requiresAuthentication, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<bool> get reopenByContact => $composableBuilder(
|
|
||||||
column: $table.reopenByContact, builder: (column) => column);
|
|
||||||
|
|
||||||
GeneratedColumn<bool> get stored =>
|
GeneratedColumn<bool> get stored =>
|
||||||
$composableBuilder(column: $table.stored, builder: (column) => column);
|
$composableBuilder(column: $table.stored, builder: (column) => column);
|
||||||
|
|
||||||
|
|
@ -9525,7 +9573,6 @@ class $$MediaFilesTableTableManager extends RootTableManager<
|
||||||
Value<UploadState?> uploadState = const Value.absent(),
|
Value<UploadState?> uploadState = const Value.absent(),
|
||||||
Value<DownloadState?> downloadState = const Value.absent(),
|
Value<DownloadState?> downloadState = const Value.absent(),
|
||||||
Value<bool> requiresAuthentication = const Value.absent(),
|
Value<bool> requiresAuthentication = const Value.absent(),
|
||||||
Value<bool> reopenByContact = const Value.absent(),
|
|
||||||
Value<bool> stored = const Value.absent(),
|
Value<bool> stored = const Value.absent(),
|
||||||
Value<bool> isDraftMedia = const Value.absent(),
|
Value<bool> isDraftMedia = const Value.absent(),
|
||||||
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
||||||
|
|
@ -9544,7 +9591,6 @@ class $$MediaFilesTableTableManager extends RootTableManager<
|
||||||
uploadState: uploadState,
|
uploadState: uploadState,
|
||||||
downloadState: downloadState,
|
downloadState: downloadState,
|
||||||
requiresAuthentication: requiresAuthentication,
|
requiresAuthentication: requiresAuthentication,
|
||||||
reopenByContact: reopenByContact,
|
|
||||||
stored: stored,
|
stored: stored,
|
||||||
isDraftMedia: isDraftMedia,
|
isDraftMedia: isDraftMedia,
|
||||||
reuploadRequestedBy: reuploadRequestedBy,
|
reuploadRequestedBy: reuploadRequestedBy,
|
||||||
|
|
@ -9563,7 +9609,6 @@ class $$MediaFilesTableTableManager extends RootTableManager<
|
||||||
Value<UploadState?> uploadState = const Value.absent(),
|
Value<UploadState?> uploadState = const Value.absent(),
|
||||||
Value<DownloadState?> downloadState = const Value.absent(),
|
Value<DownloadState?> downloadState = const Value.absent(),
|
||||||
Value<bool> requiresAuthentication = const Value.absent(),
|
Value<bool> requiresAuthentication = const Value.absent(),
|
||||||
Value<bool> reopenByContact = const Value.absent(),
|
|
||||||
Value<bool> stored = const Value.absent(),
|
Value<bool> stored = const Value.absent(),
|
||||||
Value<bool> isDraftMedia = const Value.absent(),
|
Value<bool> isDraftMedia = const Value.absent(),
|
||||||
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
Value<List<int>?> reuploadRequestedBy = const Value.absent(),
|
||||||
|
|
@ -9582,7 +9627,6 @@ class $$MediaFilesTableTableManager extends RootTableManager<
|
||||||
uploadState: uploadState,
|
uploadState: uploadState,
|
||||||
downloadState: downloadState,
|
downloadState: downloadState,
|
||||||
requiresAuthentication: requiresAuthentication,
|
requiresAuthentication: requiresAuthentication,
|
||||||
reopenByContact: reopenByContact,
|
|
||||||
stored: stored,
|
stored: stored,
|
||||||
isDraftMedia: isDraftMedia,
|
isDraftMedia: isDraftMedia,
|
||||||
reuploadRequestedBy: reuploadRequestedBy,
|
reuploadRequestedBy: reuploadRequestedBy,
|
||||||
|
|
@ -9648,6 +9692,7 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({
|
||||||
Value<String?> content,
|
Value<String?> content,
|
||||||
Value<String?> mediaId,
|
Value<String?> mediaId,
|
||||||
Value<bool> mediaStored,
|
Value<bool> mediaStored,
|
||||||
|
Value<bool> mediaReopened,
|
||||||
Value<Uint8List?> downloadToken,
|
Value<Uint8List?> downloadToken,
|
||||||
Value<String?> quotesMessageId,
|
Value<String?> quotesMessageId,
|
||||||
Value<bool> isDeletedFromSender,
|
Value<bool> isDeletedFromSender,
|
||||||
|
|
@ -9667,6 +9712,7 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({
|
||||||
Value<String?> content,
|
Value<String?> content,
|
||||||
Value<String?> mediaId,
|
Value<String?> mediaId,
|
||||||
Value<bool> mediaStored,
|
Value<bool> mediaStored,
|
||||||
|
Value<bool> mediaReopened,
|
||||||
Value<Uint8List?> downloadToken,
|
Value<Uint8List?> downloadToken,
|
||||||
Value<String?> quotesMessageId,
|
Value<String?> quotesMessageId,
|
||||||
Value<bool> isDeletedFromSender,
|
Value<bool> isDeletedFromSender,
|
||||||
|
|
@ -9817,6 +9863,9 @@ class $$MessagesTableFilterComposer
|
||||||
ColumnFilters<bool> get mediaStored => $composableBuilder(
|
ColumnFilters<bool> get mediaStored => $composableBuilder(
|
||||||
column: $table.mediaStored, builder: (column) => ColumnFilters(column));
|
column: $table.mediaStored, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
ColumnFilters<bool> get mediaReopened => $composableBuilder(
|
||||||
|
column: $table.mediaReopened, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
ColumnFilters<Uint8List> get downloadToken => $composableBuilder(
|
ColumnFilters<Uint8List> get downloadToken => $composableBuilder(
|
||||||
column: $table.downloadToken, builder: (column) => ColumnFilters(column));
|
column: $table.downloadToken, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
|
@ -10012,6 +10061,10 @@ class $$MessagesTableOrderingComposer
|
||||||
ColumnOrderings<bool> get mediaStored => $composableBuilder(
|
ColumnOrderings<bool> get mediaStored => $composableBuilder(
|
||||||
column: $table.mediaStored, builder: (column) => ColumnOrderings(column));
|
column: $table.mediaStored, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
ColumnOrderings<bool> get mediaReopened => $composableBuilder(
|
||||||
|
column: $table.mediaReopened,
|
||||||
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
ColumnOrderings<Uint8List> get downloadToken => $composableBuilder(
|
ColumnOrderings<Uint8List> get downloadToken => $composableBuilder(
|
||||||
column: $table.downloadToken,
|
column: $table.downloadToken,
|
||||||
builder: (column) => ColumnOrderings(column));
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
@ -10124,6 +10177,9 @@ class $$MessagesTableAnnotationComposer
|
||||||
GeneratedColumn<bool> get mediaStored => $composableBuilder(
|
GeneratedColumn<bool> get mediaStored => $composableBuilder(
|
||||||
column: $table.mediaStored, builder: (column) => column);
|
column: $table.mediaStored, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<bool> get mediaReopened => $composableBuilder(
|
||||||
|
column: $table.mediaReopened, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<Uint8List> get downloadToken => $composableBuilder(
|
GeneratedColumn<Uint8List> get downloadToken => $composableBuilder(
|
||||||
column: $table.downloadToken, builder: (column) => column);
|
column: $table.downloadToken, builder: (column) => column);
|
||||||
|
|
||||||
|
|
@ -10333,6 +10389,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
||||||
Value<String?> content = const Value.absent(),
|
Value<String?> content = const Value.absent(),
|
||||||
Value<String?> mediaId = const Value.absent(),
|
Value<String?> mediaId = const Value.absent(),
|
||||||
Value<bool> mediaStored = const Value.absent(),
|
Value<bool> mediaStored = const Value.absent(),
|
||||||
|
Value<bool> mediaReopened = const Value.absent(),
|
||||||
Value<Uint8List?> downloadToken = const Value.absent(),
|
Value<Uint8List?> downloadToken = const Value.absent(),
|
||||||
Value<String?> quotesMessageId = const Value.absent(),
|
Value<String?> quotesMessageId = const Value.absent(),
|
||||||
Value<bool> isDeletedFromSender = const Value.absent(),
|
Value<bool> isDeletedFromSender = const Value.absent(),
|
||||||
|
|
@ -10352,6 +10409,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
||||||
content: content,
|
content: content,
|
||||||
mediaId: mediaId,
|
mediaId: mediaId,
|
||||||
mediaStored: mediaStored,
|
mediaStored: mediaStored,
|
||||||
|
mediaReopened: mediaReopened,
|
||||||
downloadToken: downloadToken,
|
downloadToken: downloadToken,
|
||||||
quotesMessageId: quotesMessageId,
|
quotesMessageId: quotesMessageId,
|
||||||
isDeletedFromSender: isDeletedFromSender,
|
isDeletedFromSender: isDeletedFromSender,
|
||||||
|
|
@ -10371,6 +10429,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
||||||
Value<String?> content = const Value.absent(),
|
Value<String?> content = const Value.absent(),
|
||||||
Value<String?> mediaId = const Value.absent(),
|
Value<String?> mediaId = const Value.absent(),
|
||||||
Value<bool> mediaStored = const Value.absent(),
|
Value<bool> mediaStored = const Value.absent(),
|
||||||
|
Value<bool> mediaReopened = const Value.absent(),
|
||||||
Value<Uint8List?> downloadToken = const Value.absent(),
|
Value<Uint8List?> downloadToken = const Value.absent(),
|
||||||
Value<String?> quotesMessageId = const Value.absent(),
|
Value<String?> quotesMessageId = const Value.absent(),
|
||||||
Value<bool> isDeletedFromSender = const Value.absent(),
|
Value<bool> isDeletedFromSender = const Value.absent(),
|
||||||
|
|
@ -10390,6 +10449,7 @@ class $$MessagesTableTableManager extends RootTableManager<
|
||||||
content: content,
|
content: content,
|
||||||
mediaId: mediaId,
|
mediaId: mediaId,
|
||||||
mediaStored: mediaStored,
|
mediaStored: mediaStored,
|
||||||
|
mediaReopened: mediaReopened,
|
||||||
downloadToken: downloadToken,
|
downloadToken: downloadToken,
|
||||||
quotesMessageId: quotesMessageId,
|
quotesMessageId: quotesMessageId,
|
||||||
isDeletedFromSender: isDeletedFromSender,
|
isDeletedFromSender: isDeletedFromSender,
|
||||||
|
|
|
||||||
1599
lib/src/database/twonly.db.steps.dart
Normal file
1599
lib/src/database/twonly.db.steps.dart
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -822,5 +822,12 @@
|
||||||
"dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?",
|
"dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?",
|
||||||
"dialogAskDeleteMediaFilePopDelete": "Löschen",
|
"dialogAskDeleteMediaFilePopDelete": "Löschen",
|
||||||
"allowErrorTracking": "Fehler und Crashes mit uns teilen",
|
"allowErrorTracking": "Fehler und Crashes mit uns teilen",
|
||||||
"allowErrorTrackingSubtitle": "Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen."
|
"allowErrorTrackingSubtitle": "Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen.",
|
||||||
|
"avatarSaveChanges": "Möchtest du die Änderungen speichern?",
|
||||||
|
"avatarSaveChangesStore": "Speichern",
|
||||||
|
"avatarSaveChangesDiscard": "Verwerfen",
|
||||||
|
"inProcess": "Wird verarbeitet",
|
||||||
|
"draftMessage": "Entwurf",
|
||||||
|
"exportMemories": "Memories exportieren (Beta)",
|
||||||
|
"importMemories": "Memories importieren (Beta)"
|
||||||
}
|
}
|
||||||
|
|
@ -600,5 +600,12 @@
|
||||||
"dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?",
|
"dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?",
|
||||||
"dialogAskDeleteMediaFilePopDelete": "Delete",
|
"dialogAskDeleteMediaFilePopDelete": "Delete",
|
||||||
"allowErrorTracking": "Share errors and crashes with us",
|
"allowErrorTracking": "Share errors and crashes with us",
|
||||||
"allowErrorTrackingSubtitle": "If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded."
|
"allowErrorTrackingSubtitle": "If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.",
|
||||||
|
"avatarSaveChanges": "Would you like to save the changes?",
|
||||||
|
"avatarSaveChangesStore": "Save",
|
||||||
|
"avatarSaveChangesDiscard": "Discard",
|
||||||
|
"inProcess": "In process",
|
||||||
|
"draftMessage": "Draft",
|
||||||
|
"exportMemories": "Export memories (Beta)",
|
||||||
|
"importMemories": "Import memories (Beta)"
|
||||||
}
|
}
|
||||||
|
|
@ -2707,6 +2707,48 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.'**
|
/// **'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.'**
|
||||||
String get allowErrorTrackingSubtitle;
|
String get allowErrorTrackingSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @avatarSaveChanges.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Would you like to save the changes?'**
|
||||||
|
String get avatarSaveChanges;
|
||||||
|
|
||||||
|
/// No description provided for @avatarSaveChangesStore.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Save'**
|
||||||
|
String get avatarSaveChangesStore;
|
||||||
|
|
||||||
|
/// No description provided for @avatarSaveChangesDiscard.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Discard'**
|
||||||
|
String get avatarSaveChangesDiscard;
|
||||||
|
|
||||||
|
/// No description provided for @inProcess.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'In process'**
|
||||||
|
String get inProcess;
|
||||||
|
|
||||||
|
/// No description provided for @draftMessage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Draft'**
|
||||||
|
String get draftMessage;
|
||||||
|
|
||||||
|
/// No description provided for @exportMemories.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Export memories (Beta)'**
|
||||||
|
String get exportMemories;
|
||||||
|
|
||||||
|
/// No description provided for @importMemories.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Import memories (Beta)'**
|
||||||
|
String get importMemories;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -1495,4 +1495,25 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get allowErrorTrackingSubtitle =>
|
String get allowErrorTrackingSubtitle =>
|
||||||
'Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen.';
|
'Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChanges => 'Möchtest du die Änderungen speichern?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChangesStore => 'Speichern';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChangesDiscard => 'Verwerfen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get inProcess => 'Wird verarbeitet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get draftMessage => 'Entwurf';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportMemories => 'Memories exportieren (Beta)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get importMemories => 'Memories importieren (Beta)';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1485,4 +1485,25 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get allowErrorTrackingSubtitle =>
|
String get allowErrorTrackingSubtitle =>
|
||||||
'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.';
|
'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChanges => 'Would you like to save the changes?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChangesStore => 'Save';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get avatarSaveChangesDiscard => 'Discard';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get inProcess => 'In process';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get draftMessage => 'Draft';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportMemories => 'Export memories (Beta)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get importMemories => 'Import memories (Beta)';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
import 'package:web_socket_channel/io.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
|
||||||
|
|
||||||
final lockConnecting = Mutex();
|
final lockConnecting = Mutex();
|
||||||
final lockRetransStore = Mutex();
|
final lockRetransStore = Mutex();
|
||||||
|
|
@ -78,12 +77,7 @@ class ApiService {
|
||||||
await _channel!.ready;
|
await _channel!.ready;
|
||||||
Log.info('websocket connected to $apiUrl');
|
Log.info('websocket connected to $apiUrl');
|
||||||
return true;
|
return true;
|
||||||
} on WebSocketChannelException catch (e) {
|
} catch (_) {
|
||||||
if (!e.message
|
|
||||||
.toString()
|
|
||||||
.contains('No address associated with hostname')) {
|
|
||||||
Log.error('could not connect to api got: $e');
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -311,17 +305,17 @@ class ApiService {
|
||||||
|
|
||||||
final res = asResult(await _waitForResponse(seq));
|
final res = asResult(await _waitForResponse(seq));
|
||||||
if (res.isError) {
|
if (res.isError) {
|
||||||
Log.error('got error from server: ${res.error}');
|
Log.warn('Got error from server: ${res.error}');
|
||||||
if (res.error == ErrorCode.AppVersionOutdated) {
|
if (res.error == ErrorCode.AppVersionOutdated) {
|
||||||
globalCallbackAppIsOutdated();
|
globalCallbackAppIsOutdated();
|
||||||
Log.error('App Version is OUTDATED.');
|
Log.warn('App Version is OUTDATED.');
|
||||||
appIsOutdated = true;
|
appIsOutdated = true;
|
||||||
await close(() {});
|
await close(() {});
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
if (res.error == ErrorCode.NewDeviceRegistered) {
|
if (res.error == ErrorCode.NewDeviceRegistered) {
|
||||||
globalCallbackNewDeviceRegistered();
|
globalCallbackNewDeviceRegistered();
|
||||||
Log.error(
|
Log.warn(
|
||||||
'Device is disabled, as a newer device restore twonly Backup.',
|
'Device is disabled, as a newer device restore twonly Backup.',
|
||||||
);
|
);
|
||||||
appIsOutdated = true;
|
appIsOutdated = true;
|
||||||
|
|
@ -336,13 +330,13 @@ class ApiService {
|
||||||
// this will send the request one more time.
|
// this will send the request one more time.
|
||||||
return sendRequestSync(request, authenticated: false);
|
return sendRequestSync(request, authenticated: false);
|
||||||
} else {
|
} else {
|
||||||
Log.error('session is not authenticated');
|
Log.warn('Session is not authenticated');
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res.error == ErrorCode.UserIdNotFound && contactId != null) {
|
if (res.error == ErrorCode.UserIdNotFound && contactId != null) {
|
||||||
Log.error('Contact deleted their account $contactId.');
|
Log.warn('Contact deleted their account $contactId.');
|
||||||
final contact = await twonlyDB.contactsDao
|
final contact = await twonlyDB.contactsDao
|
||||||
.getContactByUserId(contactId)
|
.getContactByUserId(contactId)
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
|
|
|
||||||
|
|
@ -148,16 +148,22 @@ Future<void> handleMediaUpdate(
|
||||||
switch (mediaUpdate.type) {
|
switch (mediaUpdate.type) {
|
||||||
case EncryptedContent_MediaUpdate_Type.REOPENED:
|
case EncryptedContent_MediaUpdate_Type.REOPENED:
|
||||||
Log.info('Got media file reopened ${mediaFile.mediaId}');
|
Log.info('Got media file reopened ${mediaFile.mediaId}');
|
||||||
await twonlyDB.mediaFilesDao.updateMedia(
|
await twonlyDB.messagesDao.updateMessageId(
|
||||||
mediaFile.mediaId,
|
message.messageId,
|
||||||
const MediaFilesCompanion(
|
const MessagesCompanion(
|
||||||
reopenByContact: Value(true),
|
mediaReopened: Value(true),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case EncryptedContent_MediaUpdate_Type.STORED:
|
case EncryptedContent_MediaUpdate_Type.STORED:
|
||||||
Log.info('Got media file stored ${mediaFile.mediaId}');
|
Log.info('Got media file stored ${mediaFile.mediaId}');
|
||||||
final mediaService = await MediaFileService.fromMedia(mediaFile);
|
final mediaService = await MediaFileService.fromMedia(mediaFile);
|
||||||
await mediaService.storeMediaFile();
|
await mediaService.storeMediaFile();
|
||||||
|
await twonlyDB.messagesDao.updateMessageId(
|
||||||
|
message.messageId,
|
||||||
|
const MessagesCompanion(
|
||||||
|
mediaStored: Value(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
case EncryptedContent_MediaUpdate_Type.DECRYPTION_ERROR:
|
case EncryptedContent_MediaUpdate_Type.DECRYPTION_ERROR:
|
||||||
Log.info('Got media file decryption error ${mediaFile.mediaId}');
|
Log.info('Got media file decryption error ${mediaFile.mediaId}');
|
||||||
|
|
|
||||||
|
|
@ -13,33 +13,45 @@ Future<void> handleMessageUpdate(
|
||||||
Log.info(
|
Log.info(
|
||||||
'Opened message $targetMessageId',
|
'Opened message $targetMessageId',
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
await twonlyDB.messagesDao.handleMessageOpened(
|
await twonlyDB.messagesDao.handleMessageOpened(
|
||||||
contactId,
|
contactId,
|
||||||
targetMessageId,
|
targetMessageId,
|
||||||
fromTimestamp(messageUpdate.timestamp),
|
fromTimestamp(messageUpdate.timestamp),
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case EncryptedContent_MessageUpdate_Type.DELETE:
|
case EncryptedContent_MessageUpdate_Type.DELETE:
|
||||||
if (!await isSender(contactId, messageUpdate.senderMessageId)) {
|
if (!await isSender(contactId, messageUpdate.senderMessageId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.info('Delete message ${messageUpdate.senderMessageId}');
|
Log.info('Delete message ${messageUpdate.senderMessageId}');
|
||||||
|
try {
|
||||||
await twonlyDB.messagesDao.handleMessageDeletion(
|
await twonlyDB.messagesDao.handleMessageDeletion(
|
||||||
contactId,
|
contactId,
|
||||||
messageUpdate.senderMessageId,
|
messageUpdate.senderMessageId,
|
||||||
fromTimestamp(messageUpdate.timestamp),
|
fromTimestamp(messageUpdate.timestamp),
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn(e);
|
||||||
|
}
|
||||||
case EncryptedContent_MessageUpdate_Type.EDIT_TEXT:
|
case EncryptedContent_MessageUpdate_Type.EDIT_TEXT:
|
||||||
if (!await isSender(contactId, messageUpdate.senderMessageId)) {
|
if (!await isSender(contactId, messageUpdate.senderMessageId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.info('Edit message ${messageUpdate.senderMessageId}');
|
Log.info('Edit message ${messageUpdate.senderMessageId}');
|
||||||
|
try {
|
||||||
await twonlyDB.messagesDao.handleTextEdit(
|
await twonlyDB.messagesDao.handleTextEdit(
|
||||||
contactId,
|
contactId,
|
||||||
messageUpdate.senderMessageId,
|
messageUpdate.senderMessageId,
|
||||||
messageUpdate.text,
|
messageUpdate.text,
|
||||||
fromTimestamp(messageUpdate.timestamp),
|
fromTimestamp(messageUpdate.timestamp),
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ Future<void> finishStartedPreprocessing() async {
|
||||||
}
|
}
|
||||||
await startBackgroundMediaUpload(service);
|
await startBackgroundMediaUpload(service);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.warn(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ Future<(Uint8List, Uint8List?)?> tryToSendCompleteMessage({
|
||||||
);
|
);
|
||||||
|
|
||||||
if (resp.isError) {
|
if (resp.isError) {
|
||||||
Log.error('Could not transmit message $receiptId got ${resp.error}.');
|
Log.warn('Could not transmit message got ${resp.error}.');
|
||||||
if (resp.error == ErrorCode.UserIdNotFound) {
|
if (resp.error == ErrorCode.UserIdNotFound) {
|
||||||
await twonlyDB.receiptsDao.deleteReceipt(receiptId);
|
await twonlyDB.receiptsDao.deleteReceipt(receiptId);
|
||||||
await twonlyDB.contactsDao.updateContact(
|
await twonlyDB.contactsDao.updateContact(
|
||||||
|
|
@ -162,6 +162,12 @@ Future<void> insertAndSendTextMessage(
|
||||||
String textMessage,
|
String textMessage,
|
||||||
String? quotesMessageId,
|
String? quotesMessageId,
|
||||||
) async {
|
) async {
|
||||||
|
await twonlyDB.groupsDao.updateGroup(
|
||||||
|
groupId,
|
||||||
|
const GroupsCompanion(
|
||||||
|
draftMessage: Value(null),
|
||||||
|
),
|
||||||
|
);
|
||||||
final message = await twonlyDB.messagesDao.insertMessage(
|
final message = await twonlyDB.messagesDao.insertMessage(
|
||||||
MessagesCompanion(
|
MessagesCompanion(
|
||||||
groupId: Value(groupId),
|
groupId: Value(groupId),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:hashlib/random.dart';
|
import 'package:hashlib/random.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
|
|
@ -63,7 +62,7 @@ Future<void> handleClient2ClientMessage(int fromUserId, Uint8List body) async {
|
||||||
|
|
||||||
await protectReceiptCheck.protect(() async {
|
await protectReceiptCheck.protect(() async {
|
||||||
if (await twonlyDB.receiptsDao.isDuplicated(receiptId)) {
|
if (await twonlyDB.receiptsDao.isDuplicated(receiptId)) {
|
||||||
Log.error('Got duplicated message from the server. Ignoring it.');
|
Log.warn('Got duplicated message from the server.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await twonlyDB.receiptsDao.gotReceipt(receiptId);
|
await twonlyDB.receiptsDao.gotReceipt(receiptId);
|
||||||
|
|
@ -135,11 +134,12 @@ Future<void> handleClient2ClientMessage(int fromUserId, Uint8List body) async {
|
||||||
..receiptId = receiptId
|
..receiptId = receiptId
|
||||||
..type = Message_Type.PLAINTEXT_CONTENT
|
..type = Message_Type.PLAINTEXT_CONTENT
|
||||||
..plaintextContent = responsePlaintextContent;
|
..plaintextContent = responsePlaintextContent;
|
||||||
Log.error('Sending decryption error ($receiptId)');
|
Log.error('Sending decryption error');
|
||||||
} else {
|
} else {
|
||||||
response = Message()..type = Message_Type.SENDER_DELIVERY_RECEIPT;
|
response = Message()..type = Message_Type.SENDER_DELIVERY_RECEIPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
await twonlyDB.receiptsDao.insertReceipt(
|
await twonlyDB.receiptsDao.insertReceipt(
|
||||||
ReceiptsCompanion(
|
ReceiptsCompanion(
|
||||||
receiptId: Value(receiptId),
|
receiptId: Value(receiptId),
|
||||||
|
|
@ -148,6 +148,9 @@ Future<void> handleClient2ClientMessage(int fromUserId, Uint8List body) async {
|
||||||
contactWillSendsReceipt: const Value(false),
|
contactWillSendsReceipt: const Value(false),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.warn(e);
|
||||||
|
}
|
||||||
await tryToSendCompleteMessage(receiptId: receiptId);
|
await tryToSendCompleteMessage(receiptId: receiptId);
|
||||||
}
|
}
|
||||||
case Message_Type.TEST_NOTIFICATION:
|
case Message_Type.TEST_NOTIFICATION:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ Future<void> compressImage(
|
||||||
|
|
||||||
if (compressedBytes == null) {
|
if (compressedBytes == null) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Could not compress media file: $sourceFile. Sending original file.',
|
'Could not compress media file: Sending original file.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ Future<void> compressImage(
|
||||||
|
|
||||||
await destinationFile.writeAsBytes(compressedBytes);
|
await destinationFile.writeAsBytes(compressedBytes);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('$e');
|
Log.warn('$e');
|
||||||
sourceFile.copySync(destinationFile.path);
|
sourceFile.copySync(destinationFile.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class MediaFileService {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> purgeTempFolder() async {
|
static Future<void> purgeTempFolder() async {
|
||||||
final tempDirectory = MediaFileService._buildDirectoryPath(
|
final tempDirectory = MediaFileService.buildDirectoryPath(
|
||||||
'tmp',
|
'tmp',
|
||||||
await getApplicationSupportDirectory(),
|
await getApplicationSupportDirectory(),
|
||||||
);
|
);
|
||||||
|
|
@ -224,12 +224,6 @@ class MediaFileService {
|
||||||
stored: Value(true),
|
stored: Value(true),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await twonlyDB.messagesDao.updateMessagesByMediaId(
|
|
||||||
mediaFile.mediaId,
|
|
||||||
const MessagesCompanion(
|
|
||||||
mediaStored: Value(true),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (originalPath.existsSync() && !tempPath.existsSync()) {
|
if (originalPath.existsSync() && !tempPath.existsSync()) {
|
||||||
await compressMedia();
|
await compressMedia();
|
||||||
|
|
@ -245,7 +239,7 @@ class MediaFileService {
|
||||||
await updateFromDB();
|
await updateFromDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Directory _buildDirectoryPath(
|
static Directory buildDirectoryPath(
|
||||||
String directory,
|
String directory,
|
||||||
Directory applicationSupportDirectory,
|
Directory applicationSupportDirectory,
|
||||||
) {
|
) {
|
||||||
|
|
@ -281,7 +275,7 @@ class MediaFileService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final mediaBaseDir =
|
final mediaBaseDir =
|
||||||
_buildDirectoryPath(directory, applicationSupportDirectory);
|
buildDirectoryPath(directory, applicationSupportDirectory);
|
||||||
return File(
|
return File(
|
||||||
join(mediaBaseDir.path, '${mediaFile.mediaId}$namePrefix.$extension'),
|
join(mediaBaseDir.path, '${mediaFile.mediaId}$namePrefix.$extension'),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -325,7 +325,7 @@ Future<Uint8List?> encryptPushNotification(
|
||||||
content.kind != PushKind.testNotification) {
|
content.kind != PushKind.testNotification) {
|
||||||
// this will be enforced after every app uses this system... :/
|
// this will be enforced after every app uses this system... :/
|
||||||
// return null;
|
// return null;
|
||||||
Log.error('Using insecure key as the receiver does not send a push key!');
|
Log.warn('Using insecure key as the receiver does not send a push key!');
|
||||||
|
|
||||||
await sendCipherText(
|
await sendCipherText(
|
||||||
toUserId,
|
toUserId,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ Future<void> removeTwonlySafeFromServer() async {
|
||||||
);
|
);
|
||||||
Log.info('Download deleted with: ${response.statusCode}');
|
Log.info('Download deleted with: ${response.statusCode}');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('Could not connect to the server.');
|
Log.error('Could not connect upload the backup.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
} else if (update.status == TaskStatus.complete) {
|
} else if (update.status == TaskStatus.complete) {
|
||||||
Log.error(
|
Log.info(
|
||||||
'twonly Backup uploaded with status code ${update.responseStatusCode}',
|
'twonly Backup uploaded with status code ${update.responseStatusCode}',
|
||||||
);
|
);
|
||||||
await updateUserdata((user) {
|
await updateUserdata((user) {
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,6 @@ bool isUUIDNewer(String uuid1, String uuid2) {
|
||||||
final timestamp2 = int.parse(uuid2.substring(0, 8), radix: 16);
|
final timestamp2 = int.parse(uuid2.substring(0, 8), radix: 16);
|
||||||
return timestamp1 > timestamp2;
|
return timestamp1 > timestamp2;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,7 @@ class SaveToGalleryButtonState extends State<SaveToGalleryButton> {
|
||||||
_imageSaving = true;
|
_imageSaving = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (widget.mediaService.mediaFile.type == MediaType.image ||
|
|
||||||
widget.mediaService.mediaFile.type == MediaType.gif) {
|
|
||||||
await widget.storeImageAsOriginal();
|
await widget.storeImageAsOriginal();
|
||||||
}
|
|
||||||
|
|
||||||
String? res;
|
String? res;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
bool showWideAngleZoom = false;
|
bool showWideAngleZoom = false;
|
||||||
bool showWideAngleZoomIOS = false;
|
bool showWideAngleZoomIOS = false;
|
||||||
bool _isDisposed = false;
|
bool _isDisposed = false;
|
||||||
|
int? _wideCameraIndex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -51,7 +52,19 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
|
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
|
||||||
Log.info('Found ${gCameras.length} cameras for zoom.');
|
Log.info('Found ${gCameras.length} cameras for zoom.');
|
||||||
if (!showWideAngleZoom && Platform.isIOS && gCameras.length == 3) {
|
|
||||||
|
var index =
|
||||||
|
gCameras.indexWhere((t) => t.lensType == CameraLensType.ultraWide);
|
||||||
|
if (index == -1) {
|
||||||
|
index = gCameras.indexWhere(
|
||||||
|
(t) => t.lensType == CameraLensType.wide,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (index != -1) {
|
||||||
|
_wideCameraIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showWideAngleZoom && Platform.isIOS && _wideCameraIndex != null) {
|
||||||
showWideAngleZoomIOS = true;
|
showWideAngleZoomIOS = true;
|
||||||
}
|
}
|
||||||
if (_isDisposed) return;
|
if (_isDisposed) return;
|
||||||
|
|
@ -76,10 +89,12 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
|
|
||||||
const zoomTextStyle = TextStyle(fontSize: 13);
|
const zoomTextStyle = TextStyle(fontSize: 13);
|
||||||
final isSmallerFocused = widget.scaleFactor < 1 ||
|
final isSmallerFocused = widget.scaleFactor < 1 ||
|
||||||
(showWideAngleZoomIOS && widget.selectedCameraDetails.cameraId == 2);
|
(showWideAngleZoomIOS &&
|
||||||
|
widget.selectedCameraDetails.cameraId == _wideCameraIndex);
|
||||||
final isMiddleFocused = widget.scaleFactor >= 1 &&
|
final isMiddleFocused = widget.scaleFactor >= 1 &&
|
||||||
widget.scaleFactor < 2 &&
|
widget.scaleFactor < 2 &&
|
||||||
!(showWideAngleZoomIOS && widget.selectedCameraDetails.cameraId == 2);
|
!(showWideAngleZoomIOS &&
|
||||||
|
widget.selectedCameraDetails.cameraId == _wideCameraIndex);
|
||||||
|
|
||||||
final maxLevel = max(
|
final maxLevel = max(
|
||||||
min(widget.selectedCameraDetails.maxAvailableZoom, 2),
|
min(widget.selectedCameraDetails.maxAvailableZoom, 2),
|
||||||
|
|
@ -106,7 +121,9 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (showWideAngleZoomIOS) {
|
if (showWideAngleZoomIOS) {
|
||||||
await widget.selectCamera(2, true);
|
if (_wideCameraIndex != null) {
|
||||||
|
await widget.selectCamera(_wideCameraIndex!, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final level = await widget.controller.getMinZoomLevel();
|
final level = await widget.controller.getMinZoomLevel();
|
||||||
widget.updateScaleFactor(level);
|
widget.updateScaleFactor(level);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_android_volume_keydown/flutter_android_volume_keydown.dart';
|
import 'package:flutter_android_volume_keydown/flutter_android_volume_keydown.dart';
|
||||||
|
|
@ -224,7 +225,13 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
androidVolumeDownSub = FlutterAndroidVolumeKeydown.stream.listen((event) {
|
if ((await DeviceInfoPlugin().androidInfo).version.release == '9') {
|
||||||
|
// MissingPluginException: MissingPluginException(No implementation found for method cancel on channel dart-tools.dev/flutter_…
|
||||||
|
// Maybe this is the reason?
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
androidVolumeDownSub =
|
||||||
|
FlutterAndroidVolumeKeydown.stream.listen((event) {
|
||||||
if (widget.isVisible) {
|
if (widget.isVisible) {
|
||||||
takePicture();
|
takePicture();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -234,6 +241,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> deInitVolumeControl() async {
|
Future<void> deInitVolumeControl() async {
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class EmojiPickerBottom extends StatelessWidget {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
height: 450,
|
height: 480,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(32),
|
topLeft: Radius.circular(32),
|
||||||
|
|
@ -30,7 +30,7 @@ class EmojiPickerBottom extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.all(30),
|
margin: const EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
|
|
@ -52,11 +52,6 @@ class EmojiPickerBottom extends StatelessWidget {
|
||||||
config: Config(
|
config: Config(
|
||||||
height: 400,
|
height: 400,
|
||||||
locale: Localizations.localeOf(context),
|
locale: Localizations.localeOf(context),
|
||||||
viewOrderConfig: const ViewOrderConfig(
|
|
||||||
top: EmojiPickerItem.searchBar,
|
|
||||||
// middle: EmojiPickerItem.emojiView,
|
|
||||||
bottom: EmojiPickerItem.categoryBar,
|
|
||||||
),
|
|
||||||
emojiTextStyle:
|
emojiTextStyle:
|
||||||
TextStyle(fontSize: 24 * (Platform.isIOS ? 1.2 : 1)),
|
TextStyle(fontSize: 24 * (Platform.isIOS ? 1.2 : 1)),
|
||||||
emojiViewConfig: EmojiViewConfig(
|
emojiViewConfig: EmojiViewConfig(
|
||||||
|
|
@ -68,7 +63,7 @@ class EmojiPickerBottom extends StatelessWidget {
|
||||||
),
|
),
|
||||||
categoryViewConfig: CategoryViewConfig(
|
categoryViewConfig: CategoryViewConfig(
|
||||||
backgroundColor: context.color.surfaceContainer,
|
backgroundColor: context.color.surfaceContainer,
|
||||||
dividerColor: Colors.white,
|
dividerColor: context.color.surfaceContainerHigh,
|
||||||
indicatorColor: context.color.primary,
|
indicatorColor: context.color.primary,
|
||||||
iconColorSelected: context.color.primary,
|
iconColorSelected: context.color.primary,
|
||||||
iconColor: context.color.secondary,
|
iconColor: context.color.secondary,
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ class _UserListItem extends State<GroupListItem> {
|
||||||
_previewMessages,
|
_previewMessages,
|
||||||
_previewMediaFiles,
|
_previewMediaFiles,
|
||||||
lastReaction: _lastReaction,
|
lastReaction: _lastReaction,
|
||||||
|
group: widget.group,
|
||||||
),
|
),
|
||||||
const Text('•'),
|
const Text('•'),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,13 @@ class _LastMessageTimeState extends State<LastMessageTime> {
|
||||||
lastMessageInSeconds =
|
lastMessageInSeconds =
|
||||||
DateTime.now().difference(widget.dateTime!).inSeconds;
|
DateTime.now().difference(widget.dateTime!).inSeconds;
|
||||||
}
|
}
|
||||||
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (lastMessageInSeconds < 0) {
|
if (lastMessageInSeconds < 0) {
|
||||||
lastMessageInSeconds = 0;
|
lastMessageInSeconds = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:audio_waveforms/audio_waveforms.dart';
|
import 'package:audio_waveforms/audio_waveforms.dart';
|
||||||
|
import 'package:drift/drift.dart' show Value;
|
||||||
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||||
|
|
@ -57,10 +59,13 @@ class _MessageInputState extends State<MessageInput> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
_textFieldController = TextEditingController();
|
_textFieldController = TextEditingController();
|
||||||
|
if (widget.group.draftMessage != null) {
|
||||||
|
_textFieldController.text = widget.group.draftMessage!;
|
||||||
|
}
|
||||||
widget.textFieldFocus.addListener(_handleTextFocusChange);
|
widget.textFieldFocus.addListener(_handleTextFocusChange);
|
||||||
_initializeControllers();
|
_initializeControllers();
|
||||||
super.initState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -196,8 +201,15 @@ class _MessageInputState extends State<MessageInput> {
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
maxLines: 4,
|
maxLines: 4,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
onChanged: (value) {
|
onChanged: (value) async {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
await twonlyDB.groupsDao.updateGroup(
|
||||||
|
widget.group.groupId,
|
||||||
|
GroupsCompanion(
|
||||||
|
draftMessage:
|
||||||
|
Value(_textFieldController.text),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onSubmitted: (_) {
|
onSubmitted: (_) {
|
||||||
_sendMessage();
|
_sendMessage();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'dart:collection';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/tables/messages.table.dart';
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
|
@ -45,6 +46,7 @@ class MessageSendStateIcon extends StatefulWidget {
|
||||||
this.mediaFiles, {
|
this.mediaFiles, {
|
||||||
super.key,
|
super.key,
|
||||||
this.canBeReopened = false,
|
this.canBeReopened = false,
|
||||||
|
this.group,
|
||||||
this.lastReaction,
|
this.lastReaction,
|
||||||
this.mainAxisAlignment = MainAxisAlignment.end,
|
this.mainAxisAlignment = MainAxisAlignment.end,
|
||||||
});
|
});
|
||||||
|
|
@ -53,6 +55,7 @@ class MessageSendStateIcon extends StatefulWidget {
|
||||||
final Reaction? lastReaction;
|
final Reaction? lastReaction;
|
||||||
final MainAxisAlignment mainAxisAlignment;
|
final MainAxisAlignment mainAxisAlignment;
|
||||||
final bool canBeReopened;
|
final bool canBeReopened;
|
||||||
|
final Group? group;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MessageSendStateIcon> createState() => _MessageSendStateIconState();
|
State<MessageSendStateIcon> createState() => _MessageSendStateIconState();
|
||||||
|
|
@ -172,7 +175,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (mediaFile.uploadState == UploadState.preprocessing) {
|
if (mediaFile.uploadState == UploadState.preprocessing) {
|
||||||
text = 'Wird verarbeitet';
|
text = context.lang.inProcess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +192,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaFile != null) {
|
if (mediaFile != null) {
|
||||||
if (mediaFile.reopenByContact) {
|
if (message.mediaReopened) {
|
||||||
icon = FaIcon(FontAwesomeIcons.repeat, size: 12, color: color);
|
icon = FaIcon(FontAwesomeIcons.repeat, size: 12, color: color);
|
||||||
text = context.lang.messageReopened;
|
text = context.lang.messageReopened;
|
||||||
}
|
}
|
||||||
|
|
@ -221,10 +224,9 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget.lastReaction != null &&
|
if (!widget.messages.any((t) => t.openedAt == null)) {
|
||||||
!widget.messages.any((t) => t.openedAt == null)) {
|
if (widget.lastReaction != null) {
|
||||||
/// No messages are still open, so check if the reaction is the last message received.
|
/// No messages are still open, so check if the reaction is the last message received.
|
||||||
|
|
||||||
if (!widget.messages
|
if (!widget.messages
|
||||||
.any((m) => m.createdAt.isAfter(widget.lastReaction!.createdAt))) {
|
.any((m) => m.createdAt.isAfter(widget.lastReaction!.createdAt))) {
|
||||||
if (EmojiAnimation.animatedIcons
|
if (EmojiAnimation.animatedIcons
|
||||||
|
|
@ -255,6 +257,17 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
// Log.info("DISPLAY REACTION");
|
// Log.info("DISPLAY REACTION");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (widget.group != null &&
|
||||||
|
widget.group!.draftMessage != null &&
|
||||||
|
widget.group!.draftMessage != '') {
|
||||||
|
icons = [
|
||||||
|
const FaIcon(FontAwesomeIcons.pen, size: 12, color: Colors.grey),
|
||||||
|
];
|
||||||
|
textWidget = Text(
|
||||||
|
'${context.lang.draftMessage}: ${substringBy(widget.group!.draftMessage!, 10)}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (icons.isEmpty) return Container();
|
if (icons.isEmpty) return Container();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
import 'package:drift/drift.dart' show Value;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:lottie/lottie.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:no_screenshot/no_screenshot.dart';
|
import 'package:no_screenshot/no_screenshot.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart'
|
import 'package:twonly/src/database/tables/mediafiles.table.dart'
|
||||||
show DownloadState, MediaType;
|
show DownloadState, MediaType;
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
|
@ -56,6 +58,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
bool imageSaved = false;
|
bool imageSaved = false;
|
||||||
bool imageSaving = false;
|
bool imageSaving = false;
|
||||||
bool displayTwonlyPresent = false;
|
bool displayTwonlyPresent = false;
|
||||||
|
late String _currentMediaSender;
|
||||||
final emojiKey = GlobalKey<EmojiFloatWidgetState>();
|
final emojiKey = GlobalKey<EmojiFloatWidgetState>();
|
||||||
|
|
||||||
StreamSubscription<MediaFile?>? downloadStateListener;
|
StreamSubscription<MediaFile?>? downloadStateListener;
|
||||||
|
|
@ -69,6 +72,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_currentMediaSender = widget.group.groupName;
|
||||||
|
|
||||||
if (widget.initialMessage != null) {
|
if (widget.initialMessage != null) {
|
||||||
allMediaFiles = [widget.initialMessage!];
|
allMediaFiles = [widget.initialMessage!];
|
||||||
|
|
@ -237,6 +241,15 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
displayTwonlyPresent = false;
|
displayTwonlyPresent = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!widget.group.isDirectChat) {
|
||||||
|
final sender =
|
||||||
|
await twonlyDB.contactsDao.getContactById(currentMessage!.senderId!);
|
||||||
|
if (sender != null) {
|
||||||
|
_currentMediaSender =
|
||||||
|
'${getContactDisplayName(sender)} (${widget.group.groupName})';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await notifyContactAboutOpeningMessage(
|
await notifyContactAboutOpeningMessage(
|
||||||
currentMessage!.senderId!,
|
currentMessage!.senderId!,
|
||||||
[currentMessage!.messageId],
|
[currentMessage!.messageId],
|
||||||
|
|
@ -585,7 +598,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
left: showSendTextMessageInput ? 0 : null,
|
left: showSendTextMessageInput ? 0 : null,
|
||||||
right: showSendTextMessageInput ? 0 : 15,
|
right: showSendTextMessageInput ? 0 : 15,
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.group.groupName,
|
_currentMediaSender,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: showSendTextMessageInput ? 24 : 14,
|
fontSize: showSendTextMessageInput ? 24 : 14,
|
||||||
|
|
@ -630,6 +643,14 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
controller: textMessageController,
|
controller: textMessageController,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await twonlyDB.groupsDao.updateGroup(
|
||||||
|
widget.group.groupId,
|
||||||
|
GroupsCompanion(
|
||||||
|
draftMessage: Value(textMessageController.text),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
onEditingComplete: () {
|
onEditingComplete: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
showSendTextMessageInput = false;
|
showSendTextMessageInput = false;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
|
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
import 'package:twonly/src/views/settings/data_and_storage/export_media.view.dart';
|
||||||
|
import 'package:twonly/src/views/settings/data_and_storage/import_media.view.dart';
|
||||||
|
|
||||||
class DataAndStorageView extends StatefulWidget {
|
class DataAndStorageView extends StatefulWidget {
|
||||||
const DataAndStorageView({super.key});
|
const DataAndStorageView({super.key});
|
||||||
|
|
@ -62,6 +64,36 @@ class _DataAndStorageViewState extends State<DataAndStorageView> {
|
||||||
onChanged: (a) => toggleStoreInGallery(),
|
onChanged: (a) => toggleStoreInGallery(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
context.lang.exportMemories,
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) {
|
||||||
|
return const ExportMediaView();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
context.lang.importMemories,
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) {
|
||||||
|
return const ImportMediaView();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
|
|
|
||||||
175
lib/src/views/settings/data_and_storage/export_media.view.dart
Normal file
175
lib/src/views/settings/data_and_storage/export_media.view.dart
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:archive/archive_io.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
|
|
||||||
|
class ExportMediaView extends StatefulWidget {
|
||||||
|
const ExportMediaView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ExportMediaView> createState() => _ExportMediaViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExportMediaViewState extends State<ExportMediaView> {
|
||||||
|
double _progress = 0;
|
||||||
|
String? _status;
|
||||||
|
File? _zipFile;
|
||||||
|
bool _isZipping = false;
|
||||||
|
bool _zipSaved = false;
|
||||||
|
|
||||||
|
Future<Directory> _mediaFolder() async {
|
||||||
|
final dir = MediaFileService.buildDirectoryPath(
|
||||||
|
'stored',
|
||||||
|
await getApplicationSupportDirectory(),
|
||||||
|
);
|
||||||
|
if (!dir.existsSync()) await dir.create(recursive: true);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _createZipFromMediaFolder() async {
|
||||||
|
setState(() {
|
||||||
|
_isZipping = true;
|
||||||
|
_progress = 0.0;
|
||||||
|
_status = 'Preparing...';
|
||||||
|
_zipFile = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
final folder = await _mediaFolder();
|
||||||
|
final allFiles =
|
||||||
|
folder.listSync(recursive: true).whereType<File>().toList();
|
||||||
|
|
||||||
|
final mediaFiles = allFiles.where((f) {
|
||||||
|
final name = p.basename(f.path).toLowerCase();
|
||||||
|
if (name.contains('thumbnail')) return false;
|
||||||
|
return true;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
if (mediaFiles.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'No memories found.';
|
||||||
|
_isZipping = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute total bytes for progress
|
||||||
|
var totalBytes = 0;
|
||||||
|
for (final f in mediaFiles) {
|
||||||
|
totalBytes += await f.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
final tempDir = await getTemporaryDirectory();
|
||||||
|
final zipPath = p.join(
|
||||||
|
tempDir.path,
|
||||||
|
'memories.zip',
|
||||||
|
);
|
||||||
|
final encoder = ZipFileEncoder()..create(zipPath);
|
||||||
|
|
||||||
|
var processedBytes = 0;
|
||||||
|
for (final f in mediaFiles) {
|
||||||
|
final relative = p.relative(f.path, from: folder.path);
|
||||||
|
setState(() {
|
||||||
|
_status = 'Adding $relative';
|
||||||
|
});
|
||||||
|
|
||||||
|
// ZipFileEncoder doesn't give per-file progress; update after adding.
|
||||||
|
await encoder.addFile(f, relative);
|
||||||
|
|
||||||
|
processedBytes += await f.length();
|
||||||
|
setState(() {
|
||||||
|
_progress = totalBytes > 0 ? processedBytes / totalBytes : 0.0;
|
||||||
|
});
|
||||||
|
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(milliseconds: 10),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await encoder.close();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_zipFile = File(zipPath);
|
||||||
|
_status = 'ZIP created: ${p.basename(zipPath)}';
|
||||||
|
_progress = 1.0;
|
||||||
|
_isZipping = false;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Error: $e';
|
||||||
|
_isZipping = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveZip() async {
|
||||||
|
if (_zipFile == null) return;
|
||||||
|
try {
|
||||||
|
final outputFile = await FilePicker.platform.saveFile(
|
||||||
|
dialogTitle: 'Save your memories to desired location',
|
||||||
|
fileName: p.basename(_zipFile!.path),
|
||||||
|
bytes: _zipFile!.readAsBytesSync(),
|
||||||
|
);
|
||||||
|
if (outputFile == null) return;
|
||||||
|
_zipSaved = true;
|
||||||
|
_status = 'ZIP stored: ${p.basename(_zipFile!.path)}';
|
||||||
|
setState(() {});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() => _status = 'Save failed: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Export memories'),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
margin: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Here, you can export all you memories.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
if (_isZipping || _zipFile != null)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value: _isZipping ? _progress : (_zipFile != null ? 1.0 : 0.0),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (_status != null)
|
||||||
|
Text(
|
||||||
|
_status!,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
if (_zipFile == null)
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.archive),
|
||||||
|
label: Text(
|
||||||
|
_isZipping ? 'Zipping...' : 'Create ZIP from mediafiles',
|
||||||
|
),
|
||||||
|
onPressed: _isZipping ? null : _createZipFromMediaFolder,
|
||||||
|
)
|
||||||
|
else if (!_zipSaved)
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.save_alt),
|
||||||
|
label: const Text('Save ZIP'),
|
||||||
|
onPressed: (_zipFile != null && !_isZipping) ? _saveZip : null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
192
lib/src/views/settings/data_and_storage/import_media.view.dart
Normal file
192
lib/src/views/settings/data_and_storage/import_media.view.dart
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:archive/archive_io.dart';
|
||||||
|
import 'package:drift/drift.dart' show Value;
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
|
|
||||||
|
class ImportMediaView extends StatefulWidget {
|
||||||
|
const ImportMediaView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ImportMediaView> createState() => _ImportMediaViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImportMediaViewState extends State<ImportMediaView> {
|
||||||
|
double _progress = 0;
|
||||||
|
String? _status;
|
||||||
|
File? _zipFile;
|
||||||
|
bool _isProcessing = false;
|
||||||
|
|
||||||
|
Future<void> _pickAndImportZip() async {
|
||||||
|
setState(() {
|
||||||
|
_status = null;
|
||||||
|
_progress = 0;
|
||||||
|
_zipFile = null;
|
||||||
|
_isProcessing = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.custom,
|
||||||
|
allowedExtensions: ['zip'],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == null || result.files.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'No file selected.';
|
||||||
|
_isProcessing = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final pickedPath = result.files.single.path;
|
||||||
|
if (pickedPath == null) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Selected file has no path.';
|
||||||
|
_isProcessing = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final pickedFile = File(pickedPath);
|
||||||
|
if (!pickedFile.existsSync()) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Selected file does not exist.';
|
||||||
|
_isProcessing = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_zipFile = pickedFile;
|
||||||
|
_status = 'Selected ${p.basename(pickedPath)}';
|
||||||
|
});
|
||||||
|
|
||||||
|
await _extractZipToMediaFolder(pickedFile);
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Error: $e';
|
||||||
|
_isProcessing = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _extractZipToMediaFolder(File zipFile) async {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Reading archive...';
|
||||||
|
_progress = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read zip bytes and decode
|
||||||
|
final bytes = await zipFile.readAsBytes();
|
||||||
|
final archive = ZipDecoder().decodeBytes(bytes);
|
||||||
|
|
||||||
|
// Optionally: compute total entries to show progress
|
||||||
|
final entries = archive.where((e) => e.isFile).toList();
|
||||||
|
final total = entries.length;
|
||||||
|
var processed = 0;
|
||||||
|
|
||||||
|
for (final file in entries) {
|
||||||
|
if (!file.isFile || file.isSymbolicLink) continue;
|
||||||
|
|
||||||
|
final extSplit = file.name.split('.');
|
||||||
|
if (extSplit.isEmpty) continue;
|
||||||
|
final ext = extSplit.last;
|
||||||
|
|
||||||
|
late MediaType type;
|
||||||
|
switch (ext) {
|
||||||
|
case 'webp':
|
||||||
|
type = MediaType.image;
|
||||||
|
case 'mp4':
|
||||||
|
type = MediaType.video;
|
||||||
|
case 'gif':
|
||||||
|
type = MediaType.gif;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final mediaFile = await twonlyDB.mediaFilesDao.insertMedia(
|
||||||
|
MediaFilesCompanion(
|
||||||
|
type: Value(type),
|
||||||
|
createdAt: Value(file.lastModDateTime),
|
||||||
|
stored: const Value(true),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final mediaService = await MediaFileService.fromMedia(mediaFile!);
|
||||||
|
await mediaService.storedPath.writeAsBytes(file.content);
|
||||||
|
|
||||||
|
processed++;
|
||||||
|
setState(() {
|
||||||
|
_progress = total > 0 ? processed / total : 0;
|
||||||
|
_status = 'Imported ${file.name}';
|
||||||
|
});
|
||||||
|
|
||||||
|
// allow UI to update for large archives
|
||||||
|
await Future.delayed(const Duration(milliseconds: 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_status = 'Import complete. ${entries.length} entries processed.';
|
||||||
|
_isProcessing = false;
|
||||||
|
_progress = 1;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
_status = 'Extraction failed: $e';
|
||||||
|
_isProcessing = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Import memories'),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
margin: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Here, you can import exported memories.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
if (_isProcessing || _zipFile != null)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value:
|
||||||
|
_isProcessing ? _progress : (_zipFile != null ? 1.0 : 0.0),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (_status != null)
|
||||||
|
Text(
|
||||||
|
_status!,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.file_upload),
|
||||||
|
label: Text(
|
||||||
|
_isProcessing
|
||||||
|
? 'Processing...'
|
||||||
|
: 'Select memories.zip to import',
|
||||||
|
),
|
||||||
|
onPressed: _isProcessing ? null : _pickAndImportZip,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import 'dart:math';
|
||||||
import 'package:avatar_maker/avatar_maker.dart';
|
import 'package:avatar_maker/avatar_maker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/services/api/messages.dart';
|
import 'package:twonly/src/services/api/messages.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
@ -77,9 +78,60 @@ class _ModifyAvatarState extends State<ModifyAvatar> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool?> _showBackDialog() {
|
||||||
|
return showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
context.lang.avatarSaveChanges,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
FilledButton(
|
||||||
|
child: Text(context.lang.avatarSaveChangesStore),
|
||||||
|
onPressed: () async {
|
||||||
|
await storeAvatarAndExit();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text(context.lang.avatarSaveChangesDiscard),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> storeAvatarAndExit() async {
|
||||||
|
await _avatarMakerController.saveAvatarSVG();
|
||||||
|
final json = _avatarMakerController.getJsonOptionsSync();
|
||||||
|
final svg = _avatarMakerController.getAvatarSVGSync();
|
||||||
|
await updateUserAvatar(json, svg);
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return PopScope<bool?>(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvokedWithResult: (bool didPop, bool? result) async {
|
||||||
|
if (didPop) return;
|
||||||
|
if (_avatarMakerController.getJsonOptionsSync() != gUser.avatarJson) {
|
||||||
|
// there where changes
|
||||||
|
final shouldPop = await _showBackDialog() ?? false;
|
||||||
|
if (context.mounted && shouldPop) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.lang.settingsProfileCustomizeAvatar),
|
title: Text(context.lang.settingsProfileCustomizeAvatar),
|
||||||
),
|
),
|
||||||
|
|
@ -101,16 +153,7 @@ class _ModifyAvatarState extends State<ModifyAvatar> {
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const FaIcon(FontAwesomeIcons.floppyDisk),
|
icon: const FaIcon(FontAwesomeIcons.floppyDisk),
|
||||||
onPressed: () async {
|
onPressed: storeAvatarAndExit,
|
||||||
await _avatarMakerController.saveAvatarSVG();
|
|
||||||
final json =
|
|
||||||
_avatarMakerController.getJsonOptionsSync();
|
|
||||||
final svg = _avatarMakerController.getAvatarSVGSync();
|
|
||||||
await updateUserAvatar(json, svg);
|
|
||||||
if (context.mounted) {
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const FaIcon(FontAwesomeIcons.shuffle),
|
icon: const FaIcon(FontAwesomeIcons.shuffle),
|
||||||
|
|
@ -143,6 +186,7 @@ class _ModifyAvatarState extends State<ModifyAvatar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
pubspec.lock
10
pubspec.lock
|
|
@ -34,7 +34,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.1"
|
version: "8.4.1"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
|
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
|
||||||
|
|
@ -442,6 +442,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: f8f4ea435f791ab1f817b4e338ed958cb3d04ba43d6736ffc39958d950754967
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.3.6"
|
||||||
file_selector_linux:
|
file_selector_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.67+67
|
version: 0.0.69+69
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.6.0
|
sdk: ^3.6.0
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
archive: ^4.0.7
|
||||||
audio_waveforms: ^1.3.0
|
audio_waveforms: ^1.3.0
|
||||||
avatar_maker: ^0.4.0
|
avatar_maker: ^0.4.0
|
||||||
background_downloader: ^9.2.2
|
background_downloader: ^9.2.2
|
||||||
|
|
@ -23,6 +24,7 @@ dependencies:
|
||||||
drift_flutter: ^0.2.4
|
drift_flutter: ^0.2.4
|
||||||
emoji_picker_flutter: ^4.3.0
|
emoji_picker_flutter: ^4.3.0
|
||||||
ffmpeg_kit_flutter_new: ^4.1.0
|
ffmpeg_kit_flutter_new: ^4.1.0
|
||||||
|
file_picker: ^10.3.6
|
||||||
firebase_core: ^4.2.0
|
firebase_core: ^4.2.0
|
||||||
firebase_messaging: ^16.0.3
|
firebase_messaging: ^16.0.3
|
||||||
fixnum: ^1.1.1
|
fixnum: ^1.1.1
|
||||||
|
|
@ -109,6 +111,7 @@ flutter_launcher_icons:
|
||||||
ios: false
|
ios: false
|
||||||
image_path: "assets/images/logo.png"
|
image_path: "assets/images/logo.png"
|
||||||
adaptive_icon_foreground: "assets/images/logo.png"
|
adaptive_icon_foreground: "assets/images/logo.png"
|
||||||
|
adaptive_icon_monochrome: "assets/images/logo.png"
|
||||||
min_sdk_android: 21 # android min sdk min:16, default 21
|
min_sdk_android: 21 # android min sdk min:16, default 21
|
||||||
remove_alpha_ios: true
|
remove_alpha_ios: true
|
||||||
adaptive_icon_background: "#FF57CC99"
|
adaptive_icon_background: "#FF57CC99"
|
||||||
|
|
|
||||||
26
test/drift/twonly_db/generated/schema.dart
Normal file
26
test/drift/twonly_db/generated/schema.dart
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// dart format width=80
|
||||||
|
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:drift/internal/migrations.dart';
|
||||||
|
import 'schema_v1.dart' as v1;
|
||||||
|
import 'schema_v2.dart' as v2;
|
||||||
|
import 'schema_v3.dart' as v3;
|
||||||
|
|
||||||
|
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||||
|
@override
|
||||||
|
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
|
||||||
|
switch (version) {
|
||||||
|
case 1:
|
||||||
|
return v1.DatabaseAtV1(db);
|
||||||
|
case 2:
|
||||||
|
return v2.DatabaseAtV2(db);
|
||||||
|
case 3:
|
||||||
|
return v3.DatabaseAtV3(db);
|
||||||
|
default:
|
||||||
|
throw MissingSchemaException(version, versions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const versions = const [1, 2, 3];
|
||||||
|
}
|
||||||
6384
test/drift/twonly_db/generated/schema_v1.dart
Normal file
6384
test/drift/twonly_db/generated/schema_v1.dart
Normal file
File diff suppressed because it is too large
Load diff
6384
test/drift/twonly_db/generated/schema_v2.dart
Normal file
6384
test/drift/twonly_db/generated/schema_v2.dart
Normal file
File diff suppressed because it is too large
Load diff
6420
test/drift/twonly_db/generated/schema_v3.dart
Normal file
6420
test/drift/twonly_db/generated/schema_v3.dart
Normal file
File diff suppressed because it is too large
Load diff
172
test/drift/twonly_db/migration_test.dart
Normal file
172
test/drift/twonly_db/migration_test.dart
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: unused_local_variable, unused_import
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:drift_dev/api/migrations_native.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'generated/schema.dart';
|
||||||
|
|
||||||
|
import 'generated/schema_v1.dart' as v1;
|
||||||
|
import 'generated/schema_v2.dart' as v2;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||||
|
late SchemaVerifier verifier;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
verifier = SchemaVerifier(GeneratedHelper());
|
||||||
|
});
|
||||||
|
|
||||||
|
group('simple database migrations', () {
|
||||||
|
// These simple tests verify all possible schema updates with a simple (no
|
||||||
|
// data) migration. This is a quick way to ensure that written database
|
||||||
|
// migrations properly alter the schema.
|
||||||
|
const versions = GeneratedHelper.versions;
|
||||||
|
for (final (i, fromVersion) in versions.indexed) {
|
||||||
|
group('from $fromVersion', () {
|
||||||
|
for (final toVersion in versions.skip(i + 1)) {
|
||||||
|
test('to $toVersion', () async {
|
||||||
|
final schema = await verifier.schemaAt(fromVersion);
|
||||||
|
final db = TwonlyDB(schema.newConnection());
|
||||||
|
await verifier.migrateAndValidate(db, toVersion);
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// The following template shows how to write tests ensuring your migrations
|
||||||
|
// preserve existing data.
|
||||||
|
// Testing this can be useful for migrations that change existing columns
|
||||||
|
// (e.g. by alterating their type or constraints). Migrations that only add
|
||||||
|
// tables or columns typically don't need these advanced tests. For more
|
||||||
|
// information, see https://drift.simonbinder.eu/migrations/tests/#verifying-data-integrity
|
||||||
|
// TODO: This generated template shows how these tests could be written. Adopt
|
||||||
|
// it to your own needs when testing migrations with data integrity.
|
||||||
|
test('migration from v1 to v2 does not corrupt data', () async {
|
||||||
|
// Add data to insert into the old database, and the expected rows after the
|
||||||
|
// migration.
|
||||||
|
// TODO: Fill these lists
|
||||||
|
final oldContactsData = <v1.ContactsData>[];
|
||||||
|
final expectedNewContactsData = <v2.ContactsData>[];
|
||||||
|
|
||||||
|
final oldGroupsData = <v1.GroupsData>[];
|
||||||
|
final expectedNewGroupsData = <v2.GroupsData>[];
|
||||||
|
|
||||||
|
final oldMediaFilesData = <v1.MediaFilesData>[];
|
||||||
|
final expectedNewMediaFilesData = <v2.MediaFilesData>[];
|
||||||
|
|
||||||
|
final oldMessagesData = <v1.MessagesData>[];
|
||||||
|
final expectedNewMessagesData = <v2.MessagesData>[];
|
||||||
|
|
||||||
|
final oldMessageHistoriesData = <v1.MessageHistoriesData>[];
|
||||||
|
final expectedNewMessageHistoriesData = <v2.MessageHistoriesData>[];
|
||||||
|
|
||||||
|
final oldReactionsData = <v1.ReactionsData>[];
|
||||||
|
final expectedNewReactionsData = <v2.ReactionsData>[];
|
||||||
|
|
||||||
|
final oldGroupMembersData = <v1.GroupMembersData>[];
|
||||||
|
final expectedNewGroupMembersData = <v2.GroupMembersData>[];
|
||||||
|
|
||||||
|
final oldReceiptsData = <v1.ReceiptsData>[];
|
||||||
|
final expectedNewReceiptsData = <v2.ReceiptsData>[];
|
||||||
|
|
||||||
|
final oldReceivedReceiptsData = <v1.ReceivedReceiptsData>[];
|
||||||
|
final expectedNewReceivedReceiptsData = <v2.ReceivedReceiptsData>[];
|
||||||
|
|
||||||
|
final oldSignalIdentityKeyStoresData = <v1.SignalIdentityKeyStoresData>[];
|
||||||
|
final expectedNewSignalIdentityKeyStoresData =
|
||||||
|
<v2.SignalIdentityKeyStoresData>[];
|
||||||
|
|
||||||
|
final oldSignalPreKeyStoresData = <v1.SignalPreKeyStoresData>[];
|
||||||
|
final expectedNewSignalPreKeyStoresData = <v2.SignalPreKeyStoresData>[];
|
||||||
|
|
||||||
|
final oldSignalSenderKeyStoresData = <v1.SignalSenderKeyStoresData>[];
|
||||||
|
final expectedNewSignalSenderKeyStoresData =
|
||||||
|
<v2.SignalSenderKeyStoresData>[];
|
||||||
|
|
||||||
|
final oldSignalSessionStoresData = <v1.SignalSessionStoresData>[];
|
||||||
|
final expectedNewSignalSessionStoresData = <v2.SignalSessionStoresData>[];
|
||||||
|
|
||||||
|
final oldSignalContactPreKeysData = <v1.SignalContactPreKeysData>[];
|
||||||
|
final expectedNewSignalContactPreKeysData = <v2.SignalContactPreKeysData>[];
|
||||||
|
|
||||||
|
final oldSignalContactSignedPreKeysData =
|
||||||
|
<v1.SignalContactSignedPreKeysData>[];
|
||||||
|
final expectedNewSignalContactSignedPreKeysData =
|
||||||
|
<v2.SignalContactSignedPreKeysData>[];
|
||||||
|
|
||||||
|
final oldMessageActionsData = <v1.MessageActionsData>[];
|
||||||
|
final expectedNewMessageActionsData = <v2.MessageActionsData>[];
|
||||||
|
|
||||||
|
final oldGroupHistoriesData = <v1.GroupHistoriesData>[];
|
||||||
|
final expectedNewGroupHistoriesData = <v2.GroupHistoriesData>[];
|
||||||
|
|
||||||
|
await verifier.testWithDataIntegrity(
|
||||||
|
oldVersion: 1,
|
||||||
|
newVersion: 2,
|
||||||
|
createOld: v1.DatabaseAtV1.new,
|
||||||
|
createNew: v2.DatabaseAtV2.new,
|
||||||
|
openTestedDatabase: TwonlyDB.new,
|
||||||
|
createItems: (batch, oldDb) {
|
||||||
|
batch.insertAll(oldDb.contacts, oldContactsData);
|
||||||
|
batch.insertAll(oldDb.groups, oldGroupsData);
|
||||||
|
batch.insertAll(oldDb.mediaFiles, oldMediaFilesData);
|
||||||
|
batch.insertAll(oldDb.messages, oldMessagesData);
|
||||||
|
batch.insertAll(oldDb.messageHistories, oldMessageHistoriesData);
|
||||||
|
batch.insertAll(oldDb.reactions, oldReactionsData);
|
||||||
|
batch.insertAll(oldDb.groupMembers, oldGroupMembersData);
|
||||||
|
batch.insertAll(oldDb.receipts, oldReceiptsData);
|
||||||
|
batch.insertAll(oldDb.receivedReceipts, oldReceivedReceiptsData);
|
||||||
|
batch.insertAll(
|
||||||
|
oldDb.signalIdentityKeyStores, oldSignalIdentityKeyStoresData);
|
||||||
|
batch.insertAll(oldDb.signalPreKeyStores, oldSignalPreKeyStoresData);
|
||||||
|
batch.insertAll(
|
||||||
|
oldDb.signalSenderKeyStores, oldSignalSenderKeyStoresData);
|
||||||
|
batch.insertAll(oldDb.signalSessionStores, oldSignalSessionStoresData);
|
||||||
|
batch.insertAll(
|
||||||
|
oldDb.signalContactPreKeys, oldSignalContactPreKeysData);
|
||||||
|
batch.insertAll(oldDb.signalContactSignedPreKeys,
|
||||||
|
oldSignalContactSignedPreKeysData);
|
||||||
|
batch.insertAll(oldDb.messageActions, oldMessageActionsData);
|
||||||
|
batch.insertAll(oldDb.groupHistories, oldGroupHistoriesData);
|
||||||
|
},
|
||||||
|
validateItems: (newDb) async {
|
||||||
|
expect(
|
||||||
|
expectedNewContactsData, await newDb.select(newDb.contacts).get());
|
||||||
|
expect(expectedNewGroupsData, await newDb.select(newDb.groups).get());
|
||||||
|
expect(expectedNewMediaFilesData,
|
||||||
|
await newDb.select(newDb.mediaFiles).get());
|
||||||
|
expect(
|
||||||
|
expectedNewMessagesData, await newDb.select(newDb.messages).get());
|
||||||
|
expect(expectedNewMessageHistoriesData,
|
||||||
|
await newDb.select(newDb.messageHistories).get());
|
||||||
|
expect(expectedNewReactionsData,
|
||||||
|
await newDb.select(newDb.reactions).get());
|
||||||
|
expect(expectedNewGroupMembersData,
|
||||||
|
await newDb.select(newDb.groupMembers).get());
|
||||||
|
expect(
|
||||||
|
expectedNewReceiptsData, await newDb.select(newDb.receipts).get());
|
||||||
|
expect(expectedNewReceivedReceiptsData,
|
||||||
|
await newDb.select(newDb.receivedReceipts).get());
|
||||||
|
expect(expectedNewSignalIdentityKeyStoresData,
|
||||||
|
await newDb.select(newDb.signalIdentityKeyStores).get());
|
||||||
|
expect(expectedNewSignalPreKeyStoresData,
|
||||||
|
await newDb.select(newDb.signalPreKeyStores).get());
|
||||||
|
expect(expectedNewSignalSenderKeyStoresData,
|
||||||
|
await newDb.select(newDb.signalSenderKeyStores).get());
|
||||||
|
expect(expectedNewSignalSessionStoresData,
|
||||||
|
await newDb.select(newDb.signalSessionStores).get());
|
||||||
|
expect(expectedNewSignalContactPreKeysData,
|
||||||
|
await newDb.select(newDb.signalContactPreKeys).get());
|
||||||
|
expect(expectedNewSignalContactSignedPreKeysData,
|
||||||
|
await newDb.select(newDb.signalContactSignedPreKeys).get());
|
||||||
|
expect(expectedNewMessageActionsData,
|
||||||
|
await newDb.select(newDb.messageActions).get());
|
||||||
|
expect(expectedNewGroupHistoriesData,
|
||||||
|
await newDb.select(newDb.groupHistories).get());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue