refactor(core): consolidate shared app foundations
This commit is contained in:
@@ -81,38 +81,34 @@ class _LibraryCollectionsTabState extends BaseLibraryTabState<MediaItem, Library
|
||||
|
||||
@override
|
||||
Future<void> loadItems() async {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
items = [];
|
||||
resetPaginationState();
|
||||
});
|
||||
|
||||
try {
|
||||
final initialPage = await loadInitialPageWithStatus(_pageSize);
|
||||
if (!initialPage.applied || !mounted) return;
|
||||
|
||||
setState(() {
|
||||
items = loadedItems.values.toList();
|
||||
await loadInitialPaginatedItems(
|
||||
pageSize: _pageSize,
|
||||
resetViewState: () {
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
items = [];
|
||||
},
|
||||
applyLoadedItems: (loaded) {
|
||||
items = loaded;
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
hasLoadedData = true;
|
||||
tryFocus();
|
||||
|
||||
if (widget.onDataLoaded != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) widget.onDataLoaded!();
|
||||
});
|
||||
}
|
||||
} catch (e, st) {
|
||||
appLogger.e('Error loading $errorContext', error: e, stackTrace: st);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
errorMessage = 'Failed to load $errorContext: ${e.toString()}';
|
||||
},
|
||||
applyError: (error, _) {
|
||||
errorMessage = 'Failed to load $errorContext: ${error.toString()}';
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoaded: (_, _) {
|
||||
hasLoadedData = true;
|
||||
tryFocus();
|
||||
if (widget.onDataLoaded != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) widget.onDataLoaded!();
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
appLogger.e('Error loading $errorContext', error: error, stackTrace: stackTrace);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -86,38 +86,34 @@ class _LibraryPlaylistsTabState extends BaseLibraryTabState<MediaPlaylist, Libra
|
||||
|
||||
@override
|
||||
Future<void> loadItems() async {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
items = [];
|
||||
resetPaginationState();
|
||||
});
|
||||
|
||||
try {
|
||||
final initialPage = await loadInitialPageWithStatus(_pageSize);
|
||||
if (!initialPage.applied || !mounted) return;
|
||||
|
||||
setState(() {
|
||||
items = loadedItems.values.toList();
|
||||
await loadInitialPaginatedItems(
|
||||
pageSize: _pageSize,
|
||||
resetViewState: () {
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
items = [];
|
||||
},
|
||||
applyLoadedItems: (loaded) {
|
||||
items = loaded;
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
hasLoadedData = true;
|
||||
tryFocus();
|
||||
|
||||
if (widget.onDataLoaded != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) widget.onDataLoaded!();
|
||||
});
|
||||
}
|
||||
} catch (e, st) {
|
||||
appLogger.e('Error loading $errorContext', error: e, stackTrace: st);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
errorMessage = 'Failed to load $errorContext: ${e.toString()}';
|
||||
},
|
||||
applyError: (error, _) {
|
||||
errorMessage = 'Failed to load $errorContext: ${error.toString()}';
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoaded: (_, _) {
|
||||
hasLoadedData = true;
|
||||
tryFocus();
|
||||
if (widget.onDataLoaded != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) widget.onDataLoaded!();
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
appLogger.e('Error loading $errorContext', error: error, stackTrace: stackTrace);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -4,6 +4,7 @@ import '../../../media/ids.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import '../../../focus/hub_vertical_navigation.dart';
|
||||
import '../../../i18n/strings.g.dart';
|
||||
import '../../../media/media_hub.dart';
|
||||
import '../../../media/media_item.dart';
|
||||
@@ -267,27 +268,15 @@ class _LibraryRecommendedTabState extends BaseLibraryTabState<MediaHub, LibraryR
|
||||
|
||||
/// Handle vertical navigation between hubs
|
||||
bool _handleVerticalNavigation(int hubIndex, bool isUp) {
|
||||
final targetIndex = isUp ? hubIndex - 1 : hubIndex + 1;
|
||||
|
||||
// Check if target is valid
|
||||
if (targetIndex < 0) {
|
||||
// At top boundary - return false to allow onNavigateUp to handle it
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetIndex >= _hubKeys.length) {
|
||||
// At bottom boundary, block navigation
|
||||
return true;
|
||||
}
|
||||
|
||||
// Navigate to target hub with column memory
|
||||
final targetState = _hubKeys[targetIndex].currentState;
|
||||
if (targetState != null) {
|
||||
targetState.requestFocusFromMemory();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return navigateVerticalHubRows(
|
||||
hubCount: items.length,
|
||||
hubIndex: hubIndex,
|
||||
isUp: isUp,
|
||||
propagateTopBoundary: true,
|
||||
requestFocus: (targetIndex) {
|
||||
_hubKeys[targetIndex].currentState?.requestFocusFromMemory();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Focus the first item in the first hub (for tab activation)
|
||||
|
||||
Reference in New Issue
Block a user