mirror of
https://github.com/R0m1k3/xtremobile.git
synced 2026-10-22 06:38:16 +02:00
init: Initial Flutter project setup with Android and iOS platform files.
This commit is contained in:
1 parent
0dd3edfc79
commit
d0c5c4ff3a
73 files changed
+3288
-329
No files matched your search
@@ -0,0 +1,206 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
/// Mobile-specific settings (stored locally in Hive)
|
||||
/// Simplified version without server API dependencies
|
||||
class MobileSettings {
|
||||
final List<String> liveTvKeywords;
|
||||
final List<String> moviesKeywords;
|
||||
final List<String> seriesKeywords;
|
||||
|
||||
const MobileSettings({
|
||||
this.liveTvKeywords = const [],
|
||||
this.moviesKeywords = const [],
|
||||
this.seriesKeywords = const [],
|
||||
});
|
||||
|
||||
MobileSettings copyWith({
|
||||
List<String>? liveTvKeywords,
|
||||
List<String>? moviesKeywords,
|
||||
List<String>? seriesKeywords,
|
||||
}) {
|
||||
return MobileSettings(
|
||||
liveTvKeywords: liveTvKeywords ?? this.liveTvKeywords,
|
||||
moviesKeywords: moviesKeywords ?? this.moviesKeywords,
|
||||
seriesKeywords: seriesKeywords ?? this.seriesKeywords,
|
||||
);
|
||||
}
|
||||
|
||||
/// Check if category matches Live TV filter
|
||||
bool matchesLiveTvFilter(String? category) {
|
||||
if (liveTvKeywords.isEmpty) return true;
|
||||
if (category == null) return true;
|
||||
final lowerCategory = category.toLowerCase();
|
||||
return liveTvKeywords.any((keyword) =>
|
||||
lowerCategory.contains(keyword.toLowerCase()));
|
||||
}
|
||||
|
||||
/// Check if category matches Movies filter
|
||||
bool matchesMoviesFilter(String? category) {
|
||||
if (moviesKeywords.isEmpty) return true;
|
||||
if (category == null) return true;
|
||||
final lowerCategory = category.toLowerCase();
|
||||
return moviesKeywords.any((keyword) =>
|
||||
lowerCategory.contains(keyword.toLowerCase()));
|
||||
}
|
||||
|
||||
/// Check if category matches Series filter
|
||||
bool matchesSeriesFilter(String? category) {
|
||||
if (seriesKeywords.isEmpty) return true;
|
||||
if (category == null) return true;
|
||||
final lowerCategory = category.toLowerCase();
|
||||
return seriesKeywords.any((keyword) =>
|
||||
lowerCategory.contains(keyword.toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
class MobileSettingsNotifier extends StateNotifier<MobileSettings> {
|
||||
static const String _boxName = 'mobile_settings';
|
||||
Box? _box;
|
||||
|
||||
MobileSettingsNotifier() : super(const MobileSettings()) {
|
||||
_init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
_box = await Hive.openBox(_boxName);
|
||||
|
||||
final liveTv = _box?.get('liveTvKeywords', defaultValue: <String>[]) as List?;
|
||||
final movies = _box?.get('moviesKeywords', defaultValue: <String>[]) as List?;
|
||||
final series = _box?.get('seriesKeywords', defaultValue: <String>[]) as List?;
|
||||
|
||||
state = MobileSettings(
|
||||
liveTvKeywords: liveTv?.cast<String>() ?? [],
|
||||
moviesKeywords: movies?.cast<String>() ?? [],
|
||||
seriesKeywords: series?.cast<String>() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
void setLiveTvKeywords(List<String> keywords) {
|
||||
state = state.copyWith(liveTvKeywords: keywords);
|
||||
_box?.put('liveTvKeywords', keywords);
|
||||
}
|
||||
|
||||
void setMoviesKeywords(List<String> keywords) {
|
||||
state = state.copyWith(moviesKeywords: keywords);
|
||||
_box?.put('moviesKeywords', keywords);
|
||||
}
|
||||
|
||||
void setSeriesKeywords(List<String> keywords) {
|
||||
state = state.copyWith(seriesKeywords: keywords);
|
||||
_box?.put('seriesKeywords', keywords);
|
||||
}
|
||||
}
|
||||
|
||||
final mobileSettingsProvider = StateNotifierProvider<MobileSettingsNotifier, MobileSettings>((ref) {
|
||||
return MobileSettingsNotifier();
|
||||
});
|
||||
|
||||
/// Watch history for mobile (stored locally)
|
||||
class MobileWatchHistory {
|
||||
final Set<String> watchedMovies;
|
||||
final Set<String> watchedEpisodes;
|
||||
|
||||
const MobileWatchHistory({
|
||||
this.watchedMovies = const {},
|
||||
this.watchedEpisodes = const {},
|
||||
});
|
||||
|
||||
MobileWatchHistory copyWith({
|
||||
Set<String>? watchedMovies,
|
||||
Set<String>? watchedEpisodes,
|
||||
}) {
|
||||
return MobileWatchHistory(
|
||||
watchedMovies: watchedMovies ?? this.watchedMovies,
|
||||
watchedEpisodes: watchedEpisodes ?? this.watchedEpisodes,
|
||||
);
|
||||
}
|
||||
|
||||
bool isMovieWatched(String streamId) => watchedMovies.contains(streamId);
|
||||
bool isEpisodeWatched(String episodeKey) => watchedEpisodes.contains(episodeKey);
|
||||
|
||||
static String episodeKey(dynamic seriesId, int season, int episodeNum) {
|
||||
return '$seriesId:$season:$episodeNum';
|
||||
}
|
||||
}
|
||||
|
||||
class MobileWatchHistoryNotifier extends StateNotifier<MobileWatchHistory> {
|
||||
static const String _boxName = 'mobile_watch_history';
|
||||
Box? _box;
|
||||
|
||||
MobileWatchHistoryNotifier() : super(const MobileWatchHistory()) {
|
||||
_init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
_box = await Hive.openBox(_boxName);
|
||||
|
||||
final movies = _box?.get('watchedMovies', defaultValue: <String>[]) as List?;
|
||||
final episodes = _box?.get('watchedEpisodes', defaultValue: <String>[]) as List?;
|
||||
|
||||
state = MobileWatchHistory(
|
||||
watchedMovies: movies?.cast<String>().toSet() ?? {},
|
||||
watchedEpisodes: episodes?.cast<String>().toSet() ?? {},
|
||||
);
|
||||
}
|
||||
|
||||
void markMovieWatched(String streamId) {
|
||||
final updated = {...state.watchedMovies, streamId};
|
||||
state = state.copyWith(watchedMovies: updated);
|
||||
_box?.put('watchedMovies', updated.toList());
|
||||
}
|
||||
|
||||
void toggleMovieWatched(String streamId) {
|
||||
final movies = {...state.watchedMovies};
|
||||
if (movies.contains(streamId)) {
|
||||
movies.remove(streamId);
|
||||
} else {
|
||||
movies.add(streamId);
|
||||
}
|
||||
state = state.copyWith(watchedMovies: movies);
|
||||
_box?.put('watchedMovies', movies.toList());
|
||||
}
|
||||
|
||||
void markEpisodeWatched(String episodeKey) {
|
||||
final updated = {...state.watchedEpisodes, episodeKey};
|
||||
state = state.copyWith(watchedEpisodes: updated);
|
||||
_box?.put('watchedEpisodes', updated.toList());
|
||||
}
|
||||
}
|
||||
|
||||
final mobileWatchHistoryProvider = StateNotifierProvider<MobileWatchHistoryNotifier, MobileWatchHistory>((ref) {
|
||||
return MobileWatchHistoryNotifier();
|
||||
});
|
||||
|
||||
/// Favorites for mobile (stored locally)
|
||||
class MobileFavoritesNotifier extends StateNotifier<Set<String>> {
|
||||
static const String _boxName = 'mobile_favorites';
|
||||
Box? _box;
|
||||
|
||||
MobileFavoritesNotifier() : super({}) {
|
||||
_init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
_box = await Hive.openBox(_boxName);
|
||||
final favorites = _box?.get('favorites', defaultValue: <String>[]) as List?;
|
||||
state = favorites?.cast<String>().toSet() ?? {};
|
||||
}
|
||||
|
||||
void toggle(String streamId) {
|
||||
final updated = {...state};
|
||||
if (updated.contains(streamId)) {
|
||||
updated.remove(streamId);
|
||||
} else {
|
||||
updated.add(streamId);
|
||||
}
|
||||
state = updated;
|
||||
_box?.put('favorites', updated.toList());
|
||||
}
|
||||
|
||||
bool isFavorite(String streamId) => state.contains(streamId);
|
||||
}
|
||||
|
||||
final mobileFavoritesProvider = StateNotifierProvider<MobileFavoritesNotifier, Set<String>>((ref) {
|
||||
return MobileFavoritesNotifier();
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../core/models/playlist_config.dart';
|
||||
import '../../core/models/iptv_models.dart' show Channel;
|
||||
import '../../features/iptv/services/xtream_service_mobile.dart';
|
||||
import '../../features/iptv/models/xtream_models.dart';
|
||||
|
||||
export '../../features/iptv/models/xtream_models.dart';
|
||||
|
||||
/// Mobile-specific Xtream service provider (no dart:html dependency)
|
||||
final mobileXtreamServiceProvider = Provider.family<XtreamServiceMobile, PlaylistConfig>((ref, playlist) {
|
||||
final service = XtreamServiceMobile();
|
||||
service.setPlaylist(playlist);
|
||||
return service;
|
||||
});
|
||||
|
||||
/// Mobile-specific live channels provider
|
||||
final mobileLiveChannelsProvider = FutureProvider.family<Map<String, List<Channel>>, PlaylistConfig>((ref, playlist) async {
|
||||
final service = ref.read(mobileXtreamServiceProvider(playlist));
|
||||
return service.getLiveChannels();
|
||||
});
|
||||
|
||||
/// Mobile-specific movies pagination provider
|
||||
final mobileMoviesProvider = FutureProvider.family<List<Movie>, PlaylistConfig>((ref, playlist) async {
|
||||
final service = ref.read(mobileXtreamServiceProvider(playlist));
|
||||
return service.getMoviesPaginated(offset: 0, limit: 100);
|
||||
});
|
||||
|
||||
/// Mobile-specific series pagination provider
|
||||
final mobileSeriesProvider = FutureProvider.family<List<Series>, PlaylistConfig>((ref, playlist) async {
|
||||
final service = ref.read(mobileXtreamServiceProvider(playlist));
|
||||
return service.getSeriesPaginated(offset: 0, limit: 100);
|
||||
});
|
||||
|
||||
/// Mobile-specific series info provider
|
||||
final mobileSeriesInfoProvider = FutureProvider.family<SeriesInfo, String>((ref, seriesId) {
|
||||
throw UnimplementedError('Use mobileSeriesInfoByPlaylistProvider instead');
|
||||
});
|
||||
|
||||
/// Series info with playlist context
|
||||
class SeriesInfoRequest {
|
||||
final PlaylistConfig playlist;
|
||||
final String seriesId;
|
||||
|
||||
SeriesInfoRequest({required this.playlist, required this.seriesId});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is SeriesInfoRequest &&
|
||||
runtimeType == other.runtimeType &&
|
||||
playlist == other.playlist &&
|
||||
seriesId == other.seriesId;
|
||||
|
||||
@override
|
||||
int get hashCode => playlist.hashCode ^ seriesId.hashCode;
|
||||
}
|
||||
|
||||
final mobileSeriesInfoByPlaylistProvider = FutureProvider.family<SeriesInfo, SeriesInfoRequest>((ref, request) async {
|
||||
final service = ref.read(mobileXtreamServiceProvider(request.playlist));
|
||||
return service.getSeriesInfo(request.seriesId);
|
||||
});
|
||||
Reference in new issue
Block a user