feat: add mobile settings tab with player and content filter options, a new mobile scaffold, and logo asset.

This commit is contained in:
Michael committed 2025-12-20 10:23:16 +01:00
1 parent 4e00cc7dc7
commit 7e836f8ad3
8 files changed
+287 -121

No files matched your search

@@ -14,6 +14,7 @@ import '../../../theme/mobile_theme.dart';
import 'package:xtremflow/mobile/widgets/tv_focusable.dart';
import 'package:xtremflow/mobile/features/iptv/screens/lite_player_screen.dart';
import 'package:flutter/services.dart';
import '../../../../core/services/ip_service.dart';
class MobileLiveTVTab extends ConsumerStatefulWidget {
final PlaylistConfig playlist;
@@ -41,6 +42,10 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
_searchQuery = _searchController.text.toLowerCase();
});
});
// Trigger IP fetch for smart sorting
IpService().fetchIpDetails().then((_) {
if (mounted) setState(() {});
});
}
@override
@@ -111,8 +116,22 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
categories = categories
.where((cat) => settings.matchesLiveTvFilter(cat))
.toList();
categories.sort();
} else {
// Smart Sort (GeoIP)
final userCountry = IpService().country;
categories.sort((a, b) {
if (userCountry != null) {
final aMatches =
a.toLowerCase().contains(userCountry.toLowerCase());
final bMatches =
b.toLowerCase().contains(userCountry.toLowerCase());
if (aMatches && !bMatches) return -1;
if (!aMatches && bMatches) return 1;
}
return a.compareTo(b);
});
}
categories.sort();
// Prepare channels
List<Channel> displayedChannels = [];
@@ -151,6 +170,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
children: [
// Search Bar - Wrapped in TVFocusable for remote access
TVFocusable(
scale: 1.0, // Disable scaling to prevent overflow
onPressed: () {
setState(() => _isSearchEditing = true);
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -258,6 +258,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab>
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TVFocusable(
scale: 1.0, // Disable scaling to prevent overflow
onPressed: () {
setState(() => _isSearchEditing = true);
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -75,11 +75,13 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
padding: const EdgeInsets.only(bottom: 16),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
Container(
width: 48,
height: 48,
// No decoration for free-floating logo
child: Image.asset(
'assets/images/logo_xtremflow.png',
fit: BoxFit.cover,
fit: BoxFit.contain,
errorBuilder: (_, __, ___) => const Icon(
Icons.play_circle_filled,
color: AppColors.primary,