fixed some issues with the migration

This commit is contained in:
otsmr 2025-11-08 13:36:54 +01:00
parent 80d6f85350
commit d59b8602f9
3 changed files with 103 additions and 129 deletions

View file

@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:drift/drift.dart' show Value;
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';

View file

@ -218,7 +218,16 @@ class _UserListItem extends State<GroupListItem> {
subtitle: (_currentMessage == null) subtitle: (_currentMessage == null)
? (widget.group.totalMediaCounter == 0) ? (widget.group.totalMediaCounter == 0)
? Text(context.lang.chatsTapToSend) ? Text(context.lang.chatsTapToSend)
: LastMessageTime(dateTime: widget.group.lastMessageExchange) : Row(
children: [
LastMessageTime(
dateTime: widget.group.lastMessageExchange),
FlameCounterWidget(
groupId: widget.group.groupId,
prefix: true,
),
],
)
: Row( : Row(
children: [ children: [
MessageSendStateIcon( MessageSendStateIcon(

View file

@ -1,5 +1,7 @@
import 'dart:collection' show HashSet;
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:cryptography_plus/cryptography_plus.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
@ -8,13 +10,11 @@ import 'package:restart_app/restart_app.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/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/twonly.db.dart'; import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/database/twonly_database_old.dart' import 'package:twonly/src/database/twonly_database_old.dart'
show TwonlyDatabaseOld; show TwonlyDatabaseOld;
import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
class DatabaseMigrationView extends StatefulWidget { class DatabaseMigrationView extends StatefulWidget {
@ -37,141 +37,107 @@ class _DatabaseMigrationViewState extends State<DatabaseMigrationView> {
final oldDatabase = TwonlyDatabaseOld(); final oldDatabase = TwonlyDatabaseOld();
final oldContacts = await oldDatabase.contacts.select().get(); final oldContacts = await oldDatabase.contacts.select().get();
final oldMessages = await oldDatabase.messages.select().get();
for (final oldContact in oldContacts) { for (final oldContact in oldContacts) {
if (oldContact.deleted) continue; try {
Uint8List? avatarSvg; if (oldContact.deleted) continue;
if (oldContact.avatarSvg != null) { Uint8List? avatarSvg;
avatarSvg = if (oldContact.avatarSvg != null) {
Uint8List.fromList(gzip.encode(utf8.encode(oldContact.avatarSvg!))); avatarSvg = Uint8List.fromList(
} gzip.encode(utf8.encode(oldContact.avatarSvg!)));
await twonlyDB.contactsDao.insertContact(
ContactsCompanion(
userId: Value(oldContact.userId),
username: Value(oldContact.username),
displayName: Value(oldContact.displayName),
nickName: Value(oldContact.nickName),
avatarSvgCompressed: Value(avatarSvg),
senderProfileCounter: const Value(0),
accepted: Value(oldContact.accepted),
requested: Value(oldContact.requested),
blocked: Value(oldContact.blocked),
verified: Value(oldContact.verified),
createdAt: Value(oldContact.createdAt),
),
);
setState(() {
_contactsMigrated += 1;
});
final group = await twonlyDB.groupsDao.createNewDirectChat(
oldContact.userId,
GroupsCompanion(
pinned: Value(oldContact.pinned),
archived: Value(oldContact.archived),
groupName: Value(getContactDisplayNameOld(oldContact)),
totalMediaCounter: Value(oldContact.totalMediaCounter),
alsoBestFriend: Value(oldContact.alsoBestFriend),
createdAt: Value(oldContact.createdAt),
lastFlameCounterChange: Value(oldContact.lastFlameCounterChange),
lastFlameSync: Value(oldContact.lastFlameSync),
lastMessageExchange: Value(oldContact.lastMessageExchange),
lastMessageReceived: Value(oldContact.lastMessageReceived),
lastMessageSend: Value(oldContact.lastMessageSend),
flameCounter: Value(oldContact.flameCounter),
),
);
if (group == null) continue;
for (final oldMessage in oldMessages) {
if (oldMessage.mediaUploadId == null &&
oldMessage.mediaDownloadId == null) {
/// only interested in media files...
continue;
} }
if (oldMessage.contactId != oldContact.userId) continue; await twonlyDB.contactsDao.insertContact(
if (!oldMessage.mediaStored) continue; ContactsCompanion(
userId: Value(oldContact.userId),
var storedMediaPath = username: Value(oldContact.username),
join((await getApplicationSupportDirectory()).path, 'media'); displayName: Value(oldContact.displayName),
if (oldMessage.mediaDownloadId != null) { nickName: Value(oldContact.nickName),
storedMediaPath = avatarSvgCompressed: Value(avatarSvg),
'${join(storedMediaPath, 'received')}/${oldMessage.mediaDownloadId}'; senderProfileCounter: const Value(0),
} else { accepted: Value(oldContact.accepted),
storedMediaPath = requested: Value(oldContact.requested),
'${join(storedMediaPath, 'send')}/${oldMessage.mediaDownloadId}'; blocked: Value(oldContact.blocked),
} verified: Value(oldContact.verified),
createdAt: Value(oldContact.createdAt),
var type = MediaType.image;
if (File('$storedMediaPath.mp4').existsSync()) {
type = MediaType.video;
storedMediaPath = '$storedMediaPath.mp4';
} else if (File('$storedMediaPath.png').existsSync()) {
type = MediaType.image;
storedMediaPath = '$storedMediaPath.png';
} else if (File('$storedMediaPath.webp').existsSync()) {
type = MediaType.image;
storedMediaPath = '$storedMediaPath.webp';
} else {
continue;
}
final uniqueId = Value(
getUUIDforDirectChat(
oldMessage.messageOtherId ?? oldMessage.messageId,
oldMessage.contactId ^ gUser.userId,
), ),
); );
final mediaFile = await twonlyDB.mediaFilesDao.insertMedia(
MediaFilesCompanion(
mediaId: uniqueId,
stored: const Value(true),
type: Value(type),
createdAt: Value(oldMessage.sendAt),
),
);
if (mediaFile == null) continue;
final message = await twonlyDB.messagesDao.insertMessage(
MessagesCompanion(
messageId: uniqueId,
groupId: Value(group.groupId),
mediaId: uniqueId,
type: const Value(MessageType.media),
),
);
if (message == null) continue;
final mediaService = await MediaFileService.fromMedia(mediaFile);
File(storedMediaPath).copySync(mediaService.storedPath.path);
setState(() { setState(() {
_storedMediaFiles += 1; _contactsMigrated += 1;
}); });
await twonlyDB.groupsDao.createNewDirectChat(
oldContact.userId,
GroupsCompanion(
pinned: Value(oldContact.pinned),
archived: Value(oldContact.archived),
groupName: Value(getContactDisplayNameOld(oldContact)),
totalMediaCounter: Value(oldContact.totalMediaCounter),
alsoBestFriend: Value(oldContact.alsoBestFriend),
createdAt: Value(oldContact.createdAt),
lastFlameCounterChange: Value(oldContact.lastFlameCounterChange),
lastFlameSync: Value(oldContact.lastFlameSync),
lastMessageExchange: Value(oldContact.lastMessageExchange),
lastMessageReceived: Value(oldContact.lastMessageReceived),
lastMessageSend: Value(oldContact.lastMessageSend),
flameCounter: Value(oldContact.flameCounter),
maxFlameCounter: Value(oldContact.flameCounter),
maxFlameCounterFrom: Value(DateTime.now()),
),
);
} catch (e) {
Log.error(e);
} }
} }
final memoriesPath = Directory( final folders = ['memories', 'send', 'received'];
join((await getApplicationSupportDirectory()).path, 'media', 'memories'),
); final alreadyCopied = HashSet();
if (memoriesPath.existsSync()) {
final files = memoriesPath.listSync(); for (final folder in folders) {
for (final file in files) { final memoriesPath = Directory(
if (file.path.contains('thumbnail')) continue; join(
final type = (await getApplicationSupportDirectory()).path,
file.path.contains('mp4') ? MediaType.video : MediaType.image; 'media',
final stat = FileStat.statSync(file.path); folder,
final mediaFile = await twonlyDB.mediaFilesDao.insertMedia( ),
MediaFilesCompanion( );
type: Value(type), if (memoriesPath.existsSync()) {
createdAt: Value(stat.modified), final files = memoriesPath.listSync();
stored: const Value(true), for (final file in files) {
), try {
); if (file.path.contains('thumbnail')) continue;
final mediaService = await MediaFileService.fromMedia(mediaFile!); late MediaType type;
File(file.path).copySync(mediaService.storedPath.path); if (file.path.contains('mp4')) {
setState(() { type = MediaType.video;
_storedMediaFiles += 1; } else if (file.path.contains('png')) {
}); type = MediaType.image;
} else {
continue;
}
final bytes = File(file.path).readAsBytesSync();
final digest = (await Sha256().hash(bytes)).bytes;
if (alreadyCopied.contains(digest)) {
continue;
}
alreadyCopied.add(digest);
final stat = FileStat.statSync(file.path);
final mediaFile = await twonlyDB.mediaFilesDao.insertMedia(
MediaFilesCompanion(
type: Value(type),
createdAt: Value(stat.modified),
stored: const Value(true),
),
);
final mediaService = await MediaFileService.fromMedia(mediaFile!);
File(file.path).copySync(mediaService.storedPath.path);
setState(() {
_storedMediaFiles += 1;
});
} catch (e) {
Log.error(e);
}
}
} }
} }