refactor: remove orphaned bridge, database, and queue helpers

This commit is contained in:
zarzet
2026-07-26 18:43:53 +07:00
parent d4f0b84615
commit 04a71d0211
20 changed files with 6 additions and 281 deletions
@@ -2386,14 +2386,6 @@ class MainActivity: FlutterFragmentActivity() {
}
result.success(tempPath)
}
"safReplaceFromPath" -> {
val uriStr = call.argument<String>("uri") ?: ""
val srcPath = call.argument<String>("src_path") ?: ""
val ok = withContext(Dispatchers.IO) {
writeUriFromPath(Uri.parse(uriStr), srcPath)
}
result.success(ok)
}
"safCreateFromPath" -> {
val treeUriStr = call.argument<String>("tree_uri") ?: ""
val relativeDir = call.argument<String>("relative_dir") ?: ""
@@ -3064,12 +3056,6 @@ class MainActivity: FlutterFragmentActivity() {
}
result.success(response)
}
"getLogs" -> {
val response = withContext(Dispatchers.IO) {
Gobackend.getLogs()
}
result.success(response)
}
"getLogsSince" -> {
val index = call.argument<Int>("index") ?: 0
val response = withContext(Dispatchers.IO) {
@@ -3108,12 +3094,6 @@ class MainActivity: FlutterFragmentActivity() {
}
result.success(null)
}
"getLogCount" -> {
val count = withContext(Dispatchers.IO) {
Gobackend.getLogCount()
}
result.success(count.toInt())
}
"setLoggingEnabled" -> {
val enabled = call.argument<Boolean>("enabled") ?: false
withContext(Dispatchers.IO) {
@@ -17,8 +17,8 @@ func TestLogBufferExportedHelpersAndRedaction(t *testing.T) {
SetLoggingEnabled(false)
LogInfo("test", "ignored access_token=secret")
LogError("test", "Authorization: Bearer secret-token api_key=value")
if GetLogCount() != 1 {
t.Fatalf("disabled logging should keep errors only, got %d", GetLogCount())
if GetLogBuffer().Count() != 1 {
t.Fatalf("disabled logging should keep errors only, got %d", GetLogBuffer().Count())
}
SetLoggingEnabled(true)
@@ -28,8 +28,8 @@ func TestLogBufferExportedHelpersAndRedaction(t *testing.T) {
GoLog("[GoTag] success token=abc")
var entries []LogEntry
if err := json.Unmarshal([]byte(GetLogs()), &entries); err != nil {
t.Fatalf("GetLogs JSON: %v", err)
if err := json.Unmarshal([]byte(GetLogBuffer().GetAll()), &entries); err != nil {
t.Fatalf("GetAll JSON: %v", err)
}
if len(entries) < 4 {
t.Fatalf("expected log entries, got %#v", entries)
@@ -52,8 +52,8 @@ func TestLogBufferExportedHelpersAndRedaction(t *testing.T) {
}
ClearLogs()
if GetLogCount() != 0 || GetLogs() != "[]" {
t.Fatalf("logs were not cleared: count=%d logs=%s", GetLogCount(), GetLogs())
if GetLogBuffer().Count() != 0 || GetLogBuffer().GetAll() != "[]" {
t.Fatalf("logs were not cleared: count=%d logs=%s", GetLogBuffer().Count(), GetLogBuffer().GetAll())
}
}
-8
View File
@@ -207,10 +207,6 @@ func GoLog(format string, args ...any) {
GetLogBuffer().Add(level, tag, message)
}
func GetLogs() string {
return GetLogBuffer().GetAll()
}
func GetLogsSince(index int) string {
entries, nextIndex := GetLogBuffer().getSince(index)
logsJson, _ := json.Marshal(entries)
@@ -222,10 +218,6 @@ func ClearLogs() {
GetLogBuffer().Clear()
}
func GetLogCount() int {
return GetLogBuffer().Count()
}
func SetLoggingEnabled(enabled bool) {
GetLogBuffer().SetLoggingEnabled(enabled)
}
-8
View File
@@ -665,10 +665,6 @@ import Gobackend
GobackendClearTrackIDCache()
return nil
case "getLogs":
let response = GobackendGetLogs()
return response
case "getLogsSince":
let args = call.arguments as! [String: Any]
let index = args["index"] as? Int ?? 0
@@ -690,10 +686,6 @@ import Gobackend
case "getGoRuntimeMetrics":
return GobackendGetRuntimeMetricsJSON()
case "getLogCount":
let response = GobackendGetLogCount()
return response
case "setLoggingEnabled":
let args = call.arguments as! [String: Any]
let enabled = args["enabled"] as? Bool ?? false
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -5226,10 +5226,6 @@
"@downloadNativeWorkerSubtitle": {
"description": "Setting subtitle for Android native download worker"
},
"badgeBeta": "BETA",
"@badgeBeta": {
"description": "Badge label for beta features"
},
"extensionServiceStatus": "Estado del servicio",
"@extensionServiceStatus": {
"description": "Extension detail section header for service status"
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BÊTA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -5365,10 +5365,6 @@
"@downloadNativeWorkerSubtitle": {
"description": "Setting subtitle for Android native download worker"
},
"badgeBeta": "베타",
"@badgeBeta": {
"description": "Badge label for beta features"
},
"extensionServiceStatus": "서비스 상태",
"@extensionServiceStatus": {
"description": "Extension detail section header for service status"
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
-4
View File
@@ -1033,9 +1033,6 @@
"@libraryFilterMetadataMissingLabel": {
"description": "Filter option - items missing record label"
},
"@badgeBeta": {
"description": "Badge label for beta features"
},
"@audioAnalysisLufs": {
"description": "Integrated loudness metric label"
},
@@ -2881,7 +2878,6 @@
"@collectionPlaylistEmptySubtitle": {
"description": "Playlist empty state subtitle"
},
"badgeBeta": "BETA",
"@tutorialSearchHint": {
"description": "Placeholder shown in the tutorial search demo"
},
@@ -983,10 +983,6 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
_lastNotifQueueCount = -1;
}
void setOutputDir(String dir) {
state = state.copyWith(outputDir: dir);
}
bool _isSafMode(AppSettings settings) {
return Platform.isAndroid &&
settings.storageMode == 'saf' &&
@@ -1452,39 +1448,6 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
}
}
void clearCompleted() {
final removedItems = state.items.where(
(item) =>
item.status == DownloadStatus.completed ||
item.status == DownloadStatus.failed ||
item.status == DownloadStatus.skipped,
);
bool hadFailedOrSkipped = false;
for (final item in removedItems) {
if (item.status == DownloadStatus.failed ||
item.status == DownloadStatus.skipped) {
hadFailedOrSkipped = true;
_purgeAlbumRgEntry(item.track);
}
}
final items = state.items
.where(
(item) =>
item.status != DownloadStatus.completed &&
item.status != DownloadStatus.failed &&
item.status != DownloadStatus.skipped,
)
.toList();
state = state.copyWith(items: items);
_saveQueueToStorage();
if (hadFailedOrSkipped) {
_retriggerAlbumRgChecks();
}
}
void clearAll() {
final wasProcessing = state.isProcessing;
final activeIds = state.items
@@ -1780,27 +1743,6 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
}
}
void clearFailedDownloads() {
final failedItems = state.items
.where((item) => item.status == DownloadStatus.failed)
.toList();
for (final item in failedItems) {
_purgeAlbumRgEntry(item.track);
}
final items = state.items
.where((item) => item.status != DownloadStatus.failed)
.toList();
state = state.copyWith(items: items);
_saveQueueToStorage();
_log.d('Cleared failed downloads from queue');
// Removing failed items may unblock album RG for affected albums.
if (failedItems.isNotEmpty) {
_retriggerAlbumRgChecks();
}
}
Future<String?> _runPostProcessingHooks(String filePath, Track track) async {
try {
final settings = ref.read(settingsProvider);
@@ -273,11 +273,6 @@ class AppRemoteConfigService {
this.endpoint = AppInfo.remoteConfigApiUrl,
}) : _client = client ?? http.Client();
Future<AppRemoteConfig?> fetchConfig({String? locale}) async {
final snapshot = await fetchConfigSnapshot(locale: locale);
return snapshot?.config;
}
Future<RemoteConfigSnapshot?> readCachedConfig() async {
final prefs = await SharedPreferences.getInstance();
final cachedJson = prefs.getString(_cachedConfigJsonKey);
-89
View File
@@ -694,11 +694,6 @@ class HistoryDatabase {
return _dbRowToJson(rows.first);
}
Future<bool> existsTrack(HistoryLookupRequest request) async {
final row = await findExistingTrack(request, columns: ['id']);
return row != null;
}
Future<Map<String, dynamic>?> findExistingTrack(
HistoryLookupRequest request, {
List<String>? columns,
@@ -830,80 +825,6 @@ class HistoryDatabase {
.toList(growable: false);
}
Future<Set<String>> existingTrackKeys(
List<HistoryLookupRequest> requests,
) async {
if (requests.isEmpty) return const <String>{};
final db = await database;
final found = <String>{};
final rawSpotifyToKeys = <String, Set<String>>{};
final normSpotifyToKeys = <String, Set<String>>{};
final isrcToKeys = <String, Set<String>>{};
final matchToKeys = <String, Set<String>>{};
void add(Map<String, Set<String>> map, String value, String key) {
if (value.isEmpty) return;
map.putIfAbsent(value, () => <String>{}).add(key);
}
for (final request in requests) {
final key = request.lookupKey;
for (final candidate in spotifyLookupCandidates(request.spotifyId)) {
add(rawSpotifyToKeys, candidate, key);
add(normSpotifyToKeys, normalizeSpotifyId(candidate), key);
}
add(isrcToKeys, normalizeIsrc(request.isrc), key);
add(matchToKeys, matchKeyFor(request.trackName, request.artistName), key);
}
Future<void> queryColumn(
String column,
Map<String, Set<String>> keyMap,
) async {
final values = keyMap.keys.toList(growable: false);
const chunkSize = 450;
for (var i = 0; i < values.length; i += chunkSize) {
final end = (i + chunkSize < values.length)
? i + chunkSize
: values.length;
final chunk = values.sublist(i, end);
final placeholders = List.filled(chunk.length, '?').join(',');
final rows = await db.rawQuery(
'SELECT DISTINCT $column AS lookup_value FROM history WHERE $column IN ($placeholders)',
chunk,
);
for (final row in rows) {
final value = row['lookup_value'] as String?;
if (value == null) continue;
found.addAll(keyMap[value] ?? const <String>{});
}
}
}
await queryColumn('spotify_id', rawSpotifyToKeys);
await queryColumn('spotify_id_norm', normSpotifyToKeys);
await queryColumn('isrc_norm', isrcToKeys);
await queryColumn('match_key', matchToKeys);
return found;
}
Future<bool> existsBySpotifyId(String spotifyId) async {
final db = await database;
final result = await db.rawQuery(
'SELECT 1 FROM history WHERE spotify_id = ? LIMIT 1',
[spotifyId],
);
return result.isNotEmpty;
}
Future<Set<String>> getAllSpotifyIds() async {
final db = await database;
final rows = await db.rawQuery(
'SELECT spotify_id FROM history WHERE spotify_id IS NOT NULL AND spotify_id != ""',
);
return rows.map((r) => r['spotify_id'] as String).toSet();
}
Future<void> deleteById(String id) async {
final db = await database;
await db.transaction((txn) async {
@@ -1071,16 +992,6 @@ class HistoryDatabase {
return rows.map((r) => r['file_path'] as String).toSet();
}
Future<List<Map<String, dynamic>>> getAllEntriesWithPaths() async {
final db = await database;
final rows = await db.rawQuery('''
SELECT id, file_path, storage_mode, download_tree_uri, saf_relative_dir, saf_file_name
FROM history
WHERE file_path IS NOT NULL AND file_path != ""
''');
return rows.map((r) => Map<String, dynamic>.from(r)).toList();
}
Future<List<Map<String, dynamic>>> getEntriesWithPathsPage({
required int limit,
int offset = 0,
-4
View File
@@ -436,10 +436,6 @@ class NotificationService {
);
}
Future<void> cancelLibraryScanNotification() async {
await _notifications.cancel(id: libraryScanId);
}
Future<void> showUpdateDownloadProgress({
required String version,
required int received,
-16
View File
@@ -642,17 +642,6 @@ class PlatformBridge {
return result as String?;
}
static Future<bool> replaceContentUriFromPath(
String uri,
String srcPath,
) async {
final result = await _channel.invokeMethod('safReplaceFromPath', {
'uri': uri,
'src_path': srcPath,
});
return result as bool;
}
static Future<String?> createSafFileFromPath({
required String treeUri,
required String relativeDir,
@@ -1188,11 +1177,6 @@ class PlatformBridge {
} catch (_) {}
}
static Future<int> getGoLogCount() async {
final result = await _channel.invokeMethod('getLogCount');
return result as int;
}
static Future<void> setGoLoggingEnabled(bool enabled) async {
await _channel.invokeMethod('setLoggingEnabled', {'enabled': enabled});
}
-27
View File
@@ -297,30 +297,3 @@ class SettingsSectionHeader extends StatelessWidget {
);
}
}
/// Small "BETA" pill, used as a [SettingsItem.titleTrailing] /
/// [SettingsSwitchItem.titleTrailing] marker for experimental features.
class BetaBadge extends StatelessWidget {
final String label;
const BetaBadge({super.key, required this.label});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: colorScheme.tertiaryContainer,
borderRadius: BorderRadius.circular(6),
),
child: Text(
label,
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: colorScheme.onTertiaryContainer,
fontWeight: FontWeight.w700,
),
),
);
}
}