mirror of
https://gitlab.com/foxixus/neomovies_mobile.git
synced 2025-10-28 03:58:50 +05:00
v0.0.2
This commit is contained in:
@@ -1,332 +1,110 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:neomovies_mobile/data/models/auth_response.dart';
|
||||
import 'package:neomovies_mobile/data/models/favorite.dart';
|
||||
import 'package:neomovies_mobile/data/models/movie.dart';
|
||||
import 'package:neomovies_mobile/data/models/favorite.dart';
|
||||
import 'package:neomovies_mobile/data/models/reaction.dart';
|
||||
import 'package:neomovies_mobile/data/models/auth_response.dart';
|
||||
import 'package:neomovies_mobile/data/models/user.dart';
|
||||
import 'package:neomovies_mobile/data/api/neomovies_api_client.dart'; // новый клиент
|
||||
|
||||
class ApiClient {
|
||||
final http.Client _client;
|
||||
final String _baseUrl = dotenv.env['API_URL']!;
|
||||
final NeoMoviesApiClient _neoClient;
|
||||
|
||||
ApiClient(this._client);
|
||||
ApiClient(http.Client client)
|
||||
: _neoClient = NeoMoviesApiClient(client);
|
||||
|
||||
Future<List<Movie>> getPopularMovies({int page = 1}) async {
|
||||
return _fetchMovies('/movies/popular', page: page);
|
||||
// ---- Movies ----
|
||||
Future<List<Movie>> getPopularMovies({int page = 1}) {
|
||||
return _neoClient.getPopularMovies(page: page);
|
||||
}
|
||||
|
||||
Future<List<Movie>> getTopRatedMovies({int page = 1}) async {
|
||||
return _fetchMovies('/movies/top-rated', page: page);
|
||||
Future<List<Movie>> getTopRatedMovies({int page = 1}) {
|
||||
return _neoClient.getTopRatedMovies(page: page);
|
||||
}
|
||||
|
||||
Future<List<Movie>> getUpcomingMovies({int page = 1}) async {
|
||||
return _fetchMovies('/movies/upcoming', page: page);
|
||||
Future<List<Movie>> getUpcomingMovies({int page = 1}) {
|
||||
return _neoClient.getUpcomingMovies(page: page);
|
||||
}
|
||||
|
||||
Future<Movie> getMovieById(String id) async {
|
||||
return _fetchMovieDetail('/movies/$id');
|
||||
Future<Movie> getMovieById(String id) {
|
||||
return _neoClient.getMovieById(id);
|
||||
}
|
||||
|
||||
Future<Movie> getTvById(String id) async {
|
||||
return _fetchMovieDetail('/tv/$id');
|
||||
Future<Movie> getTvById(String id) {
|
||||
return _neoClient.getTvShowById(id);
|
||||
}
|
||||
|
||||
// Получение IMDB ID для фильмов
|
||||
Future<String?> getMovieImdbId(int movieId) async {
|
||||
try {
|
||||
final uri = Uri.parse('$_baseUrl/movies/$movieId/external-ids');
|
||||
final response = await _client.get(uri).timeout(const Duration(seconds: 30));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
return data['imdb_id'] as String?;
|
||||
} else {
|
||||
print('Failed to get movie IMDB ID: ${response.statusCode}');
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error getting movie IMDB ID: $e');
|
||||
return null;
|
||||
}
|
||||
// ---- Search ----
|
||||
Future<List<Movie>> searchMovies(String query, {int page = 1}) {
|
||||
return _neoClient.search(query, page: page);
|
||||
}
|
||||
|
||||
// Получение IMDB ID для сериалов
|
||||
Future<String?> getTvImdbId(int showId) async {
|
||||
try {
|
||||
final uri = Uri.parse('$_baseUrl/tv/$showId/external-ids');
|
||||
final response = await _client.get(uri).timeout(const Duration(seconds: 30));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
return data['imdb_id'] as String?;
|
||||
} else {
|
||||
print('Failed to get TV IMDB ID: ${response.statusCode}');
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error getting TV IMDB ID: $e');
|
||||
return null;
|
||||
}
|
||||
// ---- Favorites ----
|
||||
Future<List<Favorite>> getFavorites() {
|
||||
return _neoClient.getFavorites();
|
||||
}
|
||||
|
||||
// Универсальный метод получения IMDB ID
|
||||
Future<String?> getImdbId(int mediaId, String mediaType) async {
|
||||
if (mediaType == 'tv') {
|
||||
return getTvImdbId(mediaId);
|
||||
} else {
|
||||
return getMovieImdbId(mediaId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Movie>> searchMovies(String query, {int page = 1}) async {
|
||||
final moviesUri = Uri.parse('$_baseUrl/movies/search?query=${Uri.encodeQueryComponent(query)}&page=$page');
|
||||
final tvUri = Uri.parse('$_baseUrl/tv/search?query=${Uri.encodeQueryComponent(query)}&page=$page');
|
||||
|
||||
final responses = await Future.wait([
|
||||
_client.get(moviesUri),
|
||||
_client.get(tvUri),
|
||||
]);
|
||||
|
||||
List<Movie> combined = [];
|
||||
|
||||
for (final response in responses) {
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
List<dynamic> listData;
|
||||
if (decoded is List) {
|
||||
listData = decoded;
|
||||
} else if (decoded is Map && decoded['results'] is List) {
|
||||
listData = decoded['results'];
|
||||
} else {
|
||||
listData = [];
|
||||
}
|
||||
combined.addAll(listData.map((json) => Movie.fromJson(json)));
|
||||
} else {
|
||||
// ignore non-200 but log maybe
|
||||
}
|
||||
}
|
||||
|
||||
if (combined.isEmpty) {
|
||||
throw Exception('Failed to search movies/tv');
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
Future<Movie> _fetchMovieDetail(String path) async {
|
||||
final uri = Uri.parse('$_baseUrl$path');
|
||||
final response = await _client.get(uri);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
return Movie.fromJson(data);
|
||||
} else {
|
||||
throw Exception('Failed to load media details: ${response.statusCode}');
|
||||
}
|
||||
}
|
||||
|
||||
// Favorites
|
||||
Future<List<Favorite>> getFavorites() async {
|
||||
final response = await _client.get(Uri.parse('$_baseUrl/favorites'));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final List<dynamic> data = json.decode(response.body);
|
||||
return data.map((json) => Favorite.fromJson(json)).toList();
|
||||
} else {
|
||||
throw Exception('Failed to fetch favorites');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addFavorite(String mediaId, String mediaType, String title, String posterPath) async {
|
||||
final response = await _client.post(
|
||||
Uri.parse('$_baseUrl/favorites/$mediaId?mediaType=$mediaType'),
|
||||
body: json.encode({
|
||||
'title': title,
|
||||
'posterPath': posterPath,
|
||||
}),
|
||||
Future<void> addFavorite(
|
||||
String mediaId,
|
||||
String mediaType,
|
||||
String title,
|
||||
String posterPath,
|
||||
) {
|
||||
return _neoClient.addFavorite(
|
||||
mediaId: mediaId,
|
||||
mediaType: mediaType,
|
||||
title: title,
|
||||
posterPath: posterPath,
|
||||
);
|
||||
|
||||
if (response.statusCode != 201 && response.statusCode != 200) {
|
||||
throw Exception('Failed to add favorite');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> removeFavorite(String mediaId) async {
|
||||
final response = await _client.delete(
|
||||
Uri.parse('$_baseUrl/favorites/$mediaId'),
|
||||
Future<void> removeFavorite(String mediaId) {
|
||||
return _neoClient.removeFavorite(mediaId);
|
||||
}
|
||||
|
||||
// ---- Reactions ----
|
||||
Future<Map<String, int>> getReactionCounts(
|
||||
String mediaType, String mediaId) {
|
||||
return _neoClient.getReactionCounts(
|
||||
mediaType: mediaType,
|
||||
mediaId: mediaId,
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to remove favorite');
|
||||
}
|
||||
}
|
||||
|
||||
// Reactions
|
||||
Future<Map<String, int>> getReactionCounts(String mediaType, String mediaId) async {
|
||||
final response = await _client.get(
|
||||
Uri.parse('$_baseUrl/reactions/$mediaType/$mediaId/counts'),
|
||||
Future<void> setReaction(
|
||||
String mediaType, String mediaId, String reactionType) {
|
||||
return _neoClient.setReaction(
|
||||
mediaType: mediaType,
|
||||
mediaId: mediaId,
|
||||
reactionType: reactionType,
|
||||
);
|
||||
|
||||
print('REACTION COUNTS RESPONSE (${response.statusCode}): ${response.body}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
print('PARSED: $decoded');
|
||||
|
||||
if (decoded is Map) {
|
||||
final mapSrc = decoded.containsKey('data') && decoded['data'] is Map
|
||||
? decoded['data'] as Map<String, dynamic>
|
||||
: decoded;
|
||||
|
||||
print('MAPPING: $mapSrc');
|
||||
return mapSrc.map((k, v) {
|
||||
int count;
|
||||
if (v is num) {
|
||||
count = v.toInt();
|
||||
} else if (v is String) {
|
||||
count = int.tryParse(v) ?? 0;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
return MapEntry(k, count);
|
||||
});
|
||||
}
|
||||
if (decoded is List) {
|
||||
// list of {type,count}
|
||||
Map<String, int> res = {};
|
||||
for (var item in decoded) {
|
||||
if (item is Map && item['type'] != null) {
|
||||
res[item['type'].toString()] = (item['count'] as num?)?.toInt() ?? 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return {};
|
||||
} else {
|
||||
throw Exception('Failed to fetch reactions counts');
|
||||
}
|
||||
}
|
||||
|
||||
Future<UserReaction> getMyReaction(String mediaType, String mediaId) async {
|
||||
final response = await _client.get(
|
||||
Uri.parse('$_baseUrl/reactions/$mediaType/$mediaId/my-reaction'),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
if (decoded == null || (decoded is String && decoded.isEmpty)) {
|
||||
return UserReaction(reactionType: null);
|
||||
}
|
||||
return UserReaction.fromJson(decoded as Map<String, dynamic>);
|
||||
} else if (response.statusCode == 404) {
|
||||
return UserReaction(reactionType: 'none'); // No reaction found
|
||||
} else {
|
||||
throw Exception('Failed to fetch user reaction');
|
||||
}
|
||||
Future<List<UserReaction>> getMyReactions() {
|
||||
return _neoClient.getMyReactions();
|
||||
}
|
||||
|
||||
Future<void> setReaction(String mediaType, String mediaId, String reactionType) async {
|
||||
final response = await _client.post(
|
||||
Uri.parse('$_baseUrl/reactions'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'mediaId': '${mediaType}_${mediaId}', 'type': reactionType}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 201 && response.statusCode != 200 && response.statusCode != 204) {
|
||||
throw Exception('Failed to set reaction: ${response.statusCode} ${response.body}');
|
||||
}
|
||||
// ---- Auth ----
|
||||
Future<void> register(String name, String email, String password) {
|
||||
return _neoClient.register(
|
||||
name: name,
|
||||
email: email,
|
||||
password: password,
|
||||
).then((_) {}); // старый код ничего не возвращал
|
||||
}
|
||||
|
||||
// --- Auth Methods ---
|
||||
|
||||
Future<void> register(String name, String email, String password) async {
|
||||
final uri = Uri.parse('$_baseUrl/auth/register');
|
||||
final response = await _client.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'name': name, 'email': email, 'password': password}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||
if (decoded['success'] == true || decoded.containsKey('token')) {
|
||||
// registration succeeded; nothing further to return
|
||||
return;
|
||||
} else {
|
||||
throw Exception('Failed to register: ${decoded['message'] ?? 'Unknown error'}');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to register: ${response.statusCode} ${response.body}');
|
||||
}
|
||||
Future<AuthResponse> login(String email, String password) {
|
||||
return _neoClient.login(email: email, password: password);
|
||||
}
|
||||
|
||||
Future<AuthResponse> login(String email, String password) async {
|
||||
final uri = Uri.parse('$_baseUrl/auth/login');
|
||||
final response = await _client.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'email': email, 'password': password}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return AuthResponse.fromJson(json.decode(response.body));
|
||||
} else {
|
||||
throw Exception('Failed to login: ${response.body}');
|
||||
}
|
||||
Future<void> verify(String email, String code) {
|
||||
return _neoClient.verifyEmail(email: email, code: code).then((_) {});
|
||||
}
|
||||
|
||||
Future<void> verify(String email, String code) async {
|
||||
final uri = Uri.parse('$_baseUrl/auth/verify');
|
||||
final response = await _client.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'email': email, 'code': code}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to verify code: ${response.body}');
|
||||
}
|
||||
Future<void> resendCode(String email) {
|
||||
return _neoClient.resendVerificationCode(email);
|
||||
}
|
||||
|
||||
Future<void> resendCode(String email) async {
|
||||
final uri = Uri.parse('$_baseUrl/auth/resend-code');
|
||||
final response = await _client.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'email': email}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to resend code: ${response.body}');
|
||||
}
|
||||
Future<void> deleteAccount() {
|
||||
return _neoClient.deleteAccount();
|
||||
}
|
||||
|
||||
Future<void> deleteAccount() async {
|
||||
final uri = Uri.parse('$_baseUrl/auth/profile');
|
||||
final response = await _client.delete(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to delete account: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
// --- Movie Methods ---
|
||||
|
||||
Future<List<Movie>> _fetchMovies(String endpoint, {int page = 1}) async {
|
||||
final uri = Uri.parse('$_baseUrl$endpoint').replace(queryParameters: {
|
||||
'page': page.toString(),
|
||||
});
|
||||
final response = await _client.get(uri);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final List<dynamic> data = json.decode(response.body)['results'];
|
||||
if (data == null) {
|
||||
return [];
|
||||
}
|
||||
return data.map((json) => Movie.fromJson(json)).toList();
|
||||
} else {
|
||||
throw Exception('Failed to load movies from $endpoint');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user