Skip to content

Commit 86b7270

Browse files
committed
added countries
1 parent c06dd50 commit 86b7270

File tree

11 files changed

+679
-9
lines changed

11 files changed

+679
-9
lines changed

lib/main.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'src/providers/genre_provider.dart';
77
import 'src/providers/series_provider.dart';
88
import 'src/providers/seasons_provider.dart';
99
import 'src/providers/search_provider.dart';
10+
import 'src/providers/countries_provider.dart';
1011

1112
void main() {
1213
runApp(
@@ -18,6 +19,8 @@ void main() {
1819
ChangeNotifierProvider(create: (_) => SeriesProvider()),
1920
ChangeNotifierProvider(create: (_) => SeasonsProvider()),
2021
ChangeNotifierProvider(create: (_) => SearchProvider()),
22+
ChangeNotifierProvider(create: (_) => CountriesProvider()),
23+
ChangeNotifierProvider(create: (_) => CountryMediaProvider()),
2124
],
2225
child: const CCloud(),
2326
),

lib/src/models/country.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class CountryModel {
2+
final int id;
3+
final String title;
4+
final String image;
5+
6+
CountryModel({
7+
required this.id,
8+
required this.title,
9+
required this.image,
10+
});
11+
12+
factory CountryModel.fromJson(Map<String, dynamic> json) {
13+
return CountryModel(
14+
id: json['id'] as int,
15+
title: json['title'] as String,
16+
image: json['image'] as String,
17+
);
18+
}
19+
20+
Map<String, dynamic> toJson() {
21+
return {
22+
'id': id,
23+
'title': title,
24+
'image': image,
25+
};
26+
}
27+
}

lib/src/navigation/app_router.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import '../screens/series_screen.dart';
55
import '../screens/search_screen.dart';
66
import '../screens/favorites_screen.dart';
77
import '../screens/settings_screen.dart';
8+
import '../screens/countries_screen.dart';
89
import '../widgets/app_shell.dart';
910

1011
final GoRouter appRouter = GoRouter(
@@ -40,5 +41,11 @@ final GoRouter appRouter = GoRouter(
4041
return AppShell(child: const SettingsScreen());
4142
},
4243
),
44+
GoRoute(
45+
path: '/countries',
46+
builder: (BuildContext context, GoRouterState state) {
47+
return AppShell(child: const CountriesScreen());
48+
},
49+
),
4350
],
4451
);

lib/src/navigation/app_screens.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22

3-
enum AppScreen { movies, series, search, favorites, settings }
3+
enum AppScreen { movies, series, search, favorites, countries, settings }
44

55
extension AppScreenExtension on AppScreen {
66
String get route {
@@ -15,6 +15,8 @@ extension AppScreenExtension on AppScreen {
1515
return '/favorites';
1616
case AppScreen.settings:
1717
return '/settings';
18+
case AppScreen.countries:
19+
return '/countries';
1820
}
1921
}
2022

@@ -30,6 +32,8 @@ extension AppScreenExtension on AppScreen {
3032
return 'علاقه‌مندی‌ها';
3133
case AppScreen.settings:
3234
return 'تنظیمات';
35+
case AppScreen.countries:
36+
return 'کشورها';
3337
}
3438
}
3539

@@ -45,6 +49,8 @@ extension AppScreenExtension on AppScreen {
4549
return Icons.favorite;
4650
case AppScreen.settings:
4751
return Icons.settings;
52+
case AppScreen.countries:
53+
return Icons.flag;
4854
}
4955
}
5056

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import 'package:flutter/material.dart';
2+
import '../models/country.dart';
3+
import '../models/poster.dart';
4+
import '../models/media_item.dart';
5+
import '../repositories/countries_repository.dart';
6+
7+
class CountriesProvider with ChangeNotifier {
8+
final CountriesRepository _repository = CountriesRepository();
9+
10+
List<CountryModel> _countries = [];
11+
bool _isLoading = false;
12+
String? _errorMessage;
13+
14+
List<CountryModel> get countries => _countries;
15+
bool get isLoading => _isLoading;
16+
String? get errorMessage => _errorMessage;
17+
18+
Future<void> loadCountries() async {
19+
if (_isLoading) return;
20+
21+
_isLoading = true;
22+
_errorMessage = null;
23+
notifyListeners();
24+
25+
try {
26+
_countries = await _repository.getCountries();
27+
} catch (e) {
28+
_errorMessage = e.toString();
29+
_countries = [];
30+
} finally {
31+
_isLoading = false;
32+
notifyListeners();
33+
}
34+
}
35+
}
36+
37+
class CountryMediaProvider with ChangeNotifier {
38+
final CountriesRepository _repository = CountriesRepository();
39+
40+
List<Poster> _mediaItems = [];
41+
bool _isLoading = false;
42+
String? _errorMessage;
43+
FilterType _currentFilter = FilterType.defaultFilter;
44+
45+
List<Poster> get mediaItems => _mediaItems;
46+
bool get isLoading => _isLoading;
47+
String? get errorMessage => _errorMessage;
48+
FilterType get currentFilter => _currentFilter;
49+
50+
Future<void> loadMediaByCountry(int countryId, {FilterType? filterType}) async {
51+
if (_isLoading) return;
52+
53+
_isLoading = true;
54+
_errorMessage = null;
55+
_mediaItems = [];
56+
if (filterType != null) {
57+
_currentFilter = filterType;
58+
}
59+
notifyListeners();
60+
61+
try {
62+
_mediaItems = await _repository.getPostersByCountry(countryId, filterType: _currentFilter);
63+
} catch (e) {
64+
_errorMessage = e.toString();
65+
_mediaItems = [];
66+
} finally {
67+
_isLoading = false;
68+
notifyListeners();
69+
}
70+
}
71+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import 'dart:convert';
2+
import '../models/country.dart';
3+
import '../models/poster.dart';
4+
import '../models/media_item.dart';
5+
import 'base_repository.dart';
6+
7+
class CountriesRepository extends BaseRepository {
8+
static const String _countriesEndpoint = '/country/all';
9+
static const String _postersEndpoint = '/poster/by/filtres';
10+
11+
/// Fetch all countries from the API
12+
Future<List<CountryModel>> getCountries() async {
13+
try {
14+
final url = '${baseUrl}$_countriesEndpoint/${apiKey}/';
15+
final jsonData = await executeRequest(url);
16+
return parseCountries(jsonData);
17+
} catch (e) {
18+
throw Exception('Error fetching countries: $e');
19+
}
20+
}
21+
22+
List<CountryModel> parseCountries(String jsonData) {
23+
final countries = <CountryModel>[];
24+
final jsonArray = json.decode(jsonData) as List;
25+
26+
for (var item in jsonArray) {
27+
try {
28+
final countryObj = item as Map<String, dynamic>;
29+
final country = CountryModel.fromJson(countryObj);
30+
countries.add(country);
31+
} catch (e) {
32+
continue;
33+
}
34+
}
35+
36+
return countries;
37+
}
38+
39+
/// Fetch posters by country ID
40+
Future<List<Poster>> getPostersByCountry(int countryId, {int page = 0, FilterType filterType = FilterType.defaultFilter}) async {
41+
try {
42+
final url = '${baseUrl}$_postersEndpoint/0/$countryId/${filterType.apiValue}/$page/${apiKey}';
43+
final jsonData = await executeRequest(url);
44+
return parsePosters(jsonData);
45+
} catch (e) {
46+
throw Exception('Error fetching posters for country $countryId: $e');
47+
}
48+
}
49+
50+
List<Poster> parsePosters(String jsonData) {
51+
final posters = <Poster>[];
52+
final jsonArray = json.decode(jsonData) as List;
53+
54+
for (var item in jsonArray) {
55+
try {
56+
final posterObj = item as Map<String, dynamic>;
57+
final poster = Poster.fromJson(posterObj);
58+
posters.add(poster);
59+
} catch (e) {
60+
continue;
61+
}
62+
}
63+
64+
return posters;
65+
}
66+
}

0 commit comments

Comments
 (0)