272 lines
7.9 KiB
Dart
272 lines
7.9 KiB
Dart
import 'package:jwt_decoder/jwt_decoder.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||
import 'package:chepuhagram/core/constants.dart';
|
||
import 'package:http/http.dart' as http;
|
||
import 'dart:convert';
|
||
|
||
class ApiService extends ChangeNotifier {
|
||
final _client = http.Client();
|
||
final _storage = const FlutterSecureStorage();
|
||
|
||
Future<bool> refreshToken() async {
|
||
notifyListeners();
|
||
|
||
try {
|
||
final refreshToken = await _storage.read(key: 'refresh_token');
|
||
final response = await _client.post(
|
||
Uri.http(AppConstants.baseUrl, 'auth/refresh'),
|
||
body: jsonEncode({'refresh_token': refreshToken}),
|
||
headers: {'Content-Type': 'application/json'},
|
||
);
|
||
|
||
final decodedResponse =
|
||
jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||
|
||
if (response.statusCode == 200) {
|
||
await _storage.write(
|
||
key: 'access_token',
|
||
value: decodedResponse['access_token'],
|
||
);
|
||
await _storage.write(
|
||
key: 'refresh_token',
|
||
value: decodedResponse['refresh_token'],
|
||
);
|
||
notifyListeners();
|
||
return true;
|
||
} else {
|
||
notifyListeners();
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
notifyListeners();
|
||
rethrow;
|
||
}
|
||
}
|
||
|
||
Future<String?> getAccessToken() async {
|
||
String? token = await _storage.read(key: 'access_token');
|
||
|
||
if (token != null) {
|
||
bool isExpiredSoon =
|
||
JwtDecoder.isExpired(token) ||
|
||
JwtDecoder.getRemainingTime(token).inMinutes < 2;
|
||
|
||
if (isExpiredSoon) {
|
||
bool refreshed = await refreshToken();
|
||
if (refreshed) {
|
||
token = await _storage.read(key: 'access_token');
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
return token;
|
||
}
|
||
|
||
Future<bool> updateFcmToken(String fcmtoken) async {
|
||
notifyListeners();
|
||
|
||
try {
|
||
final token = await getAccessToken();
|
||
final response = await _client.post(
|
||
Uri.http(AppConstants.baseUrl, 'auth/update-fcm', {'token': fcmtoken}),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
return true;
|
||
} else {
|
||
print("Ошибка установки ключа: ${response.statusCode}");
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
rethrow;
|
||
} finally {
|
||
notifyListeners();
|
||
}
|
||
}
|
||
|
||
Future<bool> setPublicKey(String publicKey) async {
|
||
notifyListeners();
|
||
|
||
try {
|
||
final token = await getAccessToken();
|
||
final response = await _client.post(
|
||
Uri.http(AppConstants.baseUrl, 'auth/set-public-key'),
|
||
body: jsonEncode({'public_key': publicKey}),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
return true;
|
||
} else {
|
||
print("Ошибка установки ключа: ${response.statusCode}");
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
rethrow;
|
||
} finally {
|
||
notifyListeners();
|
||
}
|
||
}
|
||
|
||
Future<Map<String, dynamic>> getMe() async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.get(
|
||
Uri.http(AppConstants.baseUrl, 'users/me'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
return jsonDecode(utf8.decode(response.bodyBytes)) as Map<String, dynamic>;
|
||
}
|
||
throw Exception('Не удалось получить данные пользователя');
|
||
}
|
||
|
||
Future<bool> updateEncryptedPrivateKey(String encryptedPrivateKey) async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.put(
|
||
Uri.http(AppConstants.baseUrl, 'users/me/encryption-key'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
body: jsonEncode({'encrypted_private_key': encryptedPrivateKey}),
|
||
);
|
||
|
||
return response.statusCode == 200;
|
||
}
|
||
|
||
Future<bool> changePassword(String currentPassword, String newPassword) async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.put(
|
||
Uri.http(AppConstants.baseUrl, 'users/me/password'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
body: jsonEncode({
|
||
'current_password': currentPassword,
|
||
'new_password': newPassword,
|
||
}),
|
||
);
|
||
|
||
return response.statusCode == 200;
|
||
}
|
||
|
||
Future<List<dynamic>> getChatHistory(int contactId) async {
|
||
final token = await getAccessToken();
|
||
final response = await http.get(
|
||
Uri.http(
|
||
AppConstants.baseUrl,
|
||
'messages/history/${contactId.toString()}',
|
||
),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
"Authorization": "Bearer $token",
|
||
},
|
||
);
|
||
return jsonDecode(response.body) as List<dynamic>;
|
||
}
|
||
|
||
Future<Map<String, dynamic>> updateMe({
|
||
required String username,
|
||
required String firstName,
|
||
required String lastName,
|
||
String? phone,
|
||
String? email,
|
||
String? about,
|
||
}) async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.put(
|
||
Uri.http(AppConstants.baseUrl, 'users/me'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
body: jsonEncode({
|
||
'username': username,
|
||
'first_name': firstName,
|
||
'last_name': lastName,
|
||
'phone': (phone == null || phone.trim().isEmpty) ? null : phone.trim(),
|
||
'email': (email == null || email.trim().isEmpty) ? null : email.trim(),
|
||
'about': (about == null || about.trim().isEmpty) ? null : about.trim(),
|
||
}),
|
||
);
|
||
|
||
final decoded = jsonDecode(utf8.decode(response.bodyBytes));
|
||
if (response.statusCode == 200) {
|
||
return decoded as Map<String, dynamic>;
|
||
}
|
||
throw Exception((decoded is Map && decoded['detail'] != null) ? decoded['detail'] : 'Failed to update profile');
|
||
}
|
||
|
||
Future<Map<String, dynamic>> getUserById(int userId) async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.get(
|
||
Uri.http(AppConstants.baseUrl, 'users/$userId'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
return jsonDecode(utf8.decode(response.bodyBytes)) as Map<String, dynamic>;
|
||
}
|
||
throw Exception('Не удалось получить информацию о пользователе');
|
||
}
|
||
|
||
Future<bool> updatePrivacySettings({
|
||
bool? showEmail,
|
||
bool? showPhone,
|
||
bool? showAvatar,
|
||
bool? showAbout,
|
||
bool? showUsername,
|
||
}) async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.put(
|
||
Uri.http(AppConstants.baseUrl, 'users/me/privacy'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
body: jsonEncode({
|
||
if (showEmail != null) 'show_email': showEmail,
|
||
if (showPhone != null) 'show_phone': showPhone,
|
||
if (showAvatar != null) 'show_avatar': showAvatar,
|
||
if (showAbout != null) 'show_about': showAbout,
|
||
if (showUsername != null) 'show_username': showUsername,
|
||
}),
|
||
);
|
||
|
||
return response.statusCode == 200;
|
||
}
|
||
|
||
Future<Map<String, dynamic>> getPrivacySettings() async {
|
||
final token = await getAccessToken();
|
||
final response = await _client.get(
|
||
Uri.http(AppConstants.baseUrl, 'users/me/privacy'),
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer $token',
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
return jsonDecode(utf8.decode(response.bodyBytes)) as Map<String, dynamic>;
|
||
}
|
||
throw Exception('Не удалось получить настройки конфиденциальности');
|
||
}
|
||
}
|