// ๐Ÿ‘ฅ ๋ฐฑํ’ˆํƒ€ ๊ทธ๋ฃน ์Šคํ„ฐ๋””(๋ชฉ๋ก/์ƒ์„ฑ/์ดˆ๋Œ€) ํ™”๋ฉด์˜ ๊ธฐ๋Šฅ(์„œ๋ฒ„ ํ†ต์‹ /์ƒํƒœ) ๋‹ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ. import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import '../config.dart'; class GroupController extends ChangeNotifier { final String studentId; final String studentName; GroupController({required this.studentId, required this.studentName}); bool _isLoading = true; bool _isBusy = false; List _groups = []; List _invites = []; List _publicGroups = []; bool _disposed = false; bool get isLoading => _isLoading; bool get isBusy => _isBusy; List get groups => _groups; List get invites => _invites; List get publicGroups => _publicGroups; void _safeNotify() { if (!_disposed) notifyListeners(); } @override void dispose() { _disposed = true; super.dispose(); } Future init() => refresh(); Future refresh() async { _isLoading = true; _safeNotify(); await Future.wait([_fetchGroups(), _fetchInvites(), _fetchPublicGroups()]); _isLoading = false; _safeNotify(); } Future _fetchGroups() async { try { final response = await http.get( Uri.parse('$baseUrl/api/groups/mine?studentId=$studentId'), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); _groups = data['groups'] ?? []; } } catch (_) { // ์กฐ์šฉํžˆ ๋ฌด์‹œ } } Future _fetchInvites() async { try { final response = await http.get( Uri.parse('$baseUrl/api/groups/invites?studentId=$studentId'), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); _invites = data['invites'] ?? []; } } catch (_) { // ์กฐ์šฉํžˆ ๋ฌด์‹œ } } Future _fetchPublicGroups() async { try { final response = await http.get( Uri.parse('$baseUrl/api/groups/public?studentId=$studentId'), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); _publicGroups = data['groups'] ?? []; } } catch (_) { // ์กฐ์šฉํžˆ ๋ฌด์‹œ } } Future<(bool success, String message)> createGroup( String name, { bool isPublic = false, }) async { _isBusy = true; _safeNotify(); try { final response = await http.post( Uri.parse('$baseUrl/api/groups'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ "ownerId": studentId, "ownerName": studentName, "name": name.trim(), "isPublic": isPublic, }), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { await _fetchGroups(); return (true, '${result['message'] ?? '๊ทธ๋ฃน์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.'}'); } return (false, '${result['message'] ?? '๊ทธ๋ฃน ์ƒ์„ฑ ์‹คํŒจ'}'); } catch (e) { return (false, '๋„คํŠธ์›Œํฌ ์—๋Ÿฌ: $e'); } finally { _isBusy = false; _safeNotify(); } } Future<(bool success, String message)> respondInvite( int inviteId, bool accept, ) async { _isBusy = true; _safeNotify(); try { final response = await http.post( Uri.parse('$baseUrl/api/groups/invites/$inviteId/respond'), headers: {"Content-Type": "application/json"}, body: jsonEncode({"responderId": studentId, "accept": accept}), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { await refresh(); return (true, '${result['message'] ?? '์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.'}'); } return (false, '${result['message'] ?? '์ฒ˜๋ฆฌ ์‹คํŒจ'}'); } catch (e) { return (false, '๋„คํŠธ์›Œํฌ ์—๋Ÿฌ: $e'); } finally { _isBusy = false; _safeNotify(); } } Future<(bool success, String message)> requestJoin(int groupId) async { _isBusy = true; _safeNotify(); try { final response = await http.post( Uri.parse('$baseUrl/api/groups/$groupId/join-request'), headers: {"Content-Type": "application/json"}, body: jsonEncode({"studentId": studentId, "studentName": studentName}), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { await _fetchPublicGroups(); return (true, '${result['message'] ?? '์ฐธ์—ฌ ์‹ ์ฒญ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค.'}'); } return (false, '${result['message'] ?? '์ฐธ์—ฌ ์‹ ์ฒญ ์‹คํŒจ'}'); } catch (e) { return (false, '๋„คํŠธ์›Œํฌ ์—๋Ÿฌ: $e'); } finally { _isBusy = false; _safeNotify(); } } }