Files
velocity-pay-flutter/lib/screens/groups/controllers/group_controller.dart
2026-06-05 20:25:20 +02:00

255 lines
7.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/models/pageable_model.dart';
import 'package:qpay/screens/groups/models/recipient_group_model.dart';
class GroupScreenModel {
List<RecipientGroup> groups = [];
List<RecipientGroupMember> members = [];
bool isLoading = false;
bool isLoadingMore = false;
String? errorMessage;
int currentPage = 0;
int totalPages = 0;
int totalElements = 0;
String searchQuery = '';
bool selectMode = false;
Set<String> selectedGroupIds = {};
}
class GroupController extends ChangeNotifier {
final GroupScreenModel model = GroupScreenModel();
final Http http = Http();
BuildContext context;
bool _disposed = false;
GroupController(this.context);
@override
void dispose() {
_disposed = true;
super.dispose();
}
dynamic _unwrap(dynamic response) {
if (response is Map && response.containsKey('body')) {
return response['body'];
}
return response;
}
String buildQueryParameters(Map<String, String> params) {
if (params.isEmpty) {
return '';
}
String query = '';
params.forEach((key, value) {
query += '$key=$value&';
});
return query.substring(0, query.length - 1);
}
Future<ApiResponse<PageableModel>> listGroups({
required String userId,
int page = 0,
int size = 20,
String? name,
}) async {
if (page == 0) {
model.isLoading = true;
model.groups = [];
model.currentPage = 0;
} else {
model.isLoadingMore = true;
}
if (!_disposed) notifyListeners();
try {
final params = <String, String>{
'userId': userId,
'page': page.toString(),
'size': size.toString(),
};
if (name != null && name.isNotEmpty) {
params['name'] = name;
}
final raw = await http.get(
'/public/recipient-groups?${buildQueryParameters(params)}',
);
final response = _unwrap(raw);
final pageableModel =
PageableModel.fromJson(response as Map<String, dynamic>);
final newGroups = pageableModel.content
.map((e) => RecipientGroup.fromJson(e as Map<String, dynamic>))
.toList();
if (page == 0) {
model.groups = newGroups;
} else {
model.groups.addAll(newGroups);
}
model.currentPage = pageableModel.number;
model.totalPages = pageableModel.totalPages;
model.totalElements = pageableModel.totalElements;
model.isLoading = false;
model.isLoadingMore = false;
if (!_disposed) notifyListeners();
return ApiResponse.success(pageableModel);
} catch (e) {
logger.e(e);
model.errorMessage = e.toString();
if (page == 0) {
model.groups = [];
}
model.isLoading = false;
model.isLoadingMore = false;
if (!_disposed) notifyListeners();
return ApiResponse.failure('Failed to load groups');
}
}
Future<void> searchGroups({
required String userId,
String? name,
}) async {
model.searchQuery = name ?? '';
await listGroups(userId: userId, page: 0, name: name);
}
Future<void> loadNextPage({required String userId}) async {
if (model.isLoadingMore || model.currentPage + 1 >= model.totalPages) {
return;
}
await listGroups(
userId: userId,
page: model.currentPage + 1,
name: model.searchQuery.isNotEmpty ? model.searchQuery : null,
);
}
Future<ApiResponse<List<RecipientGroupMember>>> listMembers(
String groupId,
) async {
model.isLoading = true;
if (!_disposed) notifyListeners();
try {
final raw = await http.get(
'/public/recipient-groups/members?recipientGroupId=$groupId',
);
final response = _unwrap(raw);
final List<dynamic> content;
if (response is List) {
content = response;
} else if (response is Map && response.containsKey('content')) {
content = response['content'] as List<dynamic>;
} else {
content = [];
}
model.members = content
.map((e) => RecipientGroupMember.fromJson(e as Map<String, dynamic>))
.toList();
model.isLoading = false;
if (!_disposed) notifyListeners();
return ApiResponse.success(model.members);
} catch (e, s) {
logger.e(e);
logger.e(s);
model.errorMessage = e.toString();
model.members = [];
model.isLoading = false;
if (!_disposed) notifyListeners();
return ApiResponse.failure('Failed to load members');
}
}
Future<ApiResponse<RecipientGroup>> createGroup(
CreateGroupRequest req,
) async {
model.isLoading = true;
if (!_disposed) notifyListeners();
try {
final raw = await http.post('/public/recipient-groups', req.toJson());
final response = _unwrap(raw);
final group = RecipientGroup.fromJson(response as Map<String, dynamic>);
model.groups = [group, ...model.groups];
model.isLoading = false;
if (!_disposed) notifyListeners();
return ApiResponse.success(group);
} catch (e) {
logger.e(e);
model.errorMessage = e.toString();
model.isLoading = false;
if (!_disposed) notifyListeners();
return ApiResponse.failure('Failed to create group');
}
}
Future<void> deleteGroup({
required String groupId,
required String userId,
}) async {
try {
await http.delete(
'/public/recipient-groups/delete/$groupId?userId=$userId',
);
model.groups.removeWhere((g) => g.id == groupId);
model.selectedGroupIds.remove(groupId);
if (!_disposed) notifyListeners();
} catch (e) {
logger.e(e);
model.errorMessage = e.toString();
if (!_disposed) notifyListeners();
}
}
void toggleSelectMode() {
model.selectMode = !model.selectMode;
if (!model.selectMode) {
model.selectedGroupIds.clear();
}
if (!_disposed) notifyListeners();
}
void toggleGroupSelection(String groupId) {
if (model.selectedGroupIds.contains(groupId)) {
model.selectedGroupIds.remove(groupId);
} else {
model.selectedGroupIds.add(groupId);
}
if (!_disposed) notifyListeners();
}
Future<void> removeMember({
required String groupId,
required String recipientId,
required String userId,
}) async {
try {
await http.delete(
'/public/recipient-groups/$groupId/members/$recipientId?userId=$userId',
);
model.members.removeWhere((m) => m.id == recipientId);
if (!_disposed) notifyListeners();
} catch (e) {
logger.e(e);
model.errorMessage = e.toString();
if (!_disposed) notifyListeners();
}
}
Future<void> deleteSelectedGroups({required String userId}) async {
final idsToDelete = List<String>.from(model.selectedGroupIds);
model.selectMode = false;
model.selectedGroupIds.clear();
if (!_disposed) notifyListeners();
for (final id in idsToDelete) {
await deleteGroup(groupId: id, userId: userId);
}
}
}