Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions lib/services/config/service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,29 @@ class ConfigService {

_pref.setConfigs(response);

final configs = (response as List).map((e) => Config.fromJson(e)).toList();
// The API returns an array of wrapper objects with the config nested in the 'json' field
final configs = (response as List).map((e) {
final configData = e['json'] as Map<String, dynamic>;
return Config.fromJson(configData);
}).toList();

return configs;
}

Future<List<Config>> getLocalConfigs() async {
final localConfigs = jsonDecode(await rootBundle.loadString(
'assets/config/v$version/$communityConfigListFileName.json'));
try {
final localConfigs = jsonDecode(await rootBundle.loadString(
'assets/config/v$version/$communityConfigListFileName.json'));

final configs =
(localConfigs as List).map((e) => Config.fromJson(e)).toList();
final configs =
(localConfigs as List).map((e) => Config.fromJson(e)).toList();

return configs;
return configs;
} catch (e, s) {
debugPrint('ERROR in getLocalConfigs: $e');
debugPrintStack(stackTrace: s);
return [];
}
}

Future<Config?> getRemoteConfig(String remoteConfigUrl) async {
Expand All @@ -190,7 +200,19 @@ class ConfigService {
final dynamic response =
await remote.get(url: '?cachebuster=${generateCacheBusterValue()}');

final config = Config.fromJson(response);
if (response == null) {
debugPrint('Empty response for remote config');
return null;
}

// The API returns a wrapper object with the config nested in the 'json' field
final configData = response['json'] as Map<String, dynamic>?;
if (configData == null) {
debugPrint('No json field in response for remote config');
return null;
}

final config = Config.fromJson(configData);

return config;
} catch (e, s) {
Expand All @@ -214,8 +236,11 @@ class ConfigService {

final List<dynamic> response = await _api.get(url: '/api/communities');

final List<Config> communities =
response.map((item) => Config.fromJson(item)).toList();
// The API returns an array of wrapper objects with the config nested in the 'json' field
final List<Config> communities = response.map((item) {
final configData = item['json'] as Map<String, dynamic>;
return Config.fromJson(configData);
}).toList();

return communities;
}
Expand All @@ -232,7 +257,17 @@ class ConfigService {

try {
final response = await _api.get(url: '/api/communities/$alias');
return Config.fromJson(response);
if (response == null) {
debugPrint('Empty response for config: $alias');
return null;
}
// The API returns a wrapper object with the config nested in the 'json' field
final configData = response['json'] as Map<String, dynamic>?;
if (configData == null) {
debugPrint('No json field in response for config: $alias');
return null;
}
return Config.fromJson(configData);
} catch (e, s) {
debugPrint('Error fetching config for $alias: $e');
debugPrint('Stacktrace: $s');
Expand Down
91 changes: 75 additions & 16 deletions lib/services/db/app/communities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:citizenwallet/services/config/config.dart';
import 'package:citizenwallet/services/config/legacy.dart';
import 'package:citizenwallet/services/config/service.dart';
import 'package:citizenwallet/services/db/db.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:sqflite/sqflite.dart';

Expand All @@ -28,6 +29,50 @@ Future<List<DBCommunity>> legacyToV4(Database db, String name) async {
return v4Configs;
}

Future<List<DBCommunity>> V5Migration(Database db, String name) async {
try {
final ConfigService config = ConfigService();
final localConfigs = await config.getLocalConfigs();

final List<Map<String, dynamic>> maps = await db.query(name);
final existingCommunities = List.generate(maps.length, (i) {
return DBCommunity.fromMap(maps[i]);
});

final List<DBCommunity> updatedConfigs = [];

for (final localConfig in localConfigs) {
final existingCommunity = existingCommunities.firstWhereOrNull(
(c) => c.alias == localConfig.community.alias,
);

if (existingCommunity != null) {
// Update existing community, preserve online status
final updatedCommunity = DBCommunity(
alias: localConfig.community.alias,
config: localConfig.toJson(),
hidden: localConfig.community.hidden,
version: localConfig.version,
online: existingCommunity.online,
);
updatedConfigs.add(updatedCommunity);
} else {
// New community in v5
updatedConfigs.add(DBCommunity.fromConfig(localConfig));
}
}

return updatedConfigs;
} catch (e, s) {
debugPrint('ERROR in V5Migration: $e');
debugPrintStack(stackTrace: s);

// Return existing data unchanged on error
final List<Map<String, dynamic>> maps = await db.query(name);
return List.generate(maps.length, (i) => DBCommunity.fromMap(maps[i]));
}
}

class DBCommunity {
final String alias; // index
final bool hidden;
Expand Down Expand Up @@ -118,6 +163,9 @@ class CommunityTable extends DBTable {
2: [
'V4Migration',
],
3: [
'V5Migration',
],
};

for (var i = oldVersion + 1; i <= newVersion; i++) {
Expand All @@ -131,6 +179,11 @@ class CommunityTable extends DBTable {
final updatedConfigs = await legacyToV4(db, name);
await upsert(updatedConfigs);
continue;
case 'V5Migration':
debugPrint('V5Migration');
final updatedConfigs = await V5Migration(db, name);
await upsert(updatedConfigs);
continue;
}

await db.execute(query);
Expand All @@ -144,26 +197,32 @@ class CommunityTable extends DBTable {
}

Future<void> seed() async {
final localConfigs = await _config.getLocalConfigs();
try {
// Check if the table is empty
final count = Sqflite.firstIntValue(
await db.rawQuery('SELECT COUNT(*) FROM $name'));

// Check if the table is empty
final count =
Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM $name'));
if (count != null && count > 0) {
return; // Table is not empty, skip seeding
}
if (count != null && count > 0) {
return; // Table is not empty, skip seeding
}

// Prepare batch operation for efficient insertion
final batch = db.batch();
final localConfigs = await _config.getLocalConfigs();

for (final config in localConfigs) {
batch.insert(
name,
DBCommunity.fromConfig(config).toMap(),
);
}
// Prepare batch operation for efficient insertion
final batch = db.batch();

await batch.commit(noResult: true);
for (final config in localConfigs) {
batch.insert(
name,
DBCommunity.fromConfig(config).toMap(),
);
}

await batch.commit(noResult: true);
} catch (e, s) {
print('Error seeding communities table: $e');
print('Stack trace: $s');
}
}

Future<void> upsert(List<DBCommunity> communities) async {
Expand Down
2 changes: 1 addition & 1 deletion lib/services/db/app/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AppDBService extends DBService {
await communities.migrate(db, oldVersion, newVersion);
return;
},
version: 2,
version: 3,
);

final db = await databaseFactory.openDatabase(
Expand Down
Loading