// ๐Ÿ… ๋ฝ€๋ชจ๋„๋กœ ๋ฃจํ‹ด ๊ณต์œ (๋‹ค๋ฅธ ํ•™์ƒ๊ณผ ๊ณต๋ถ€/ํœด์‹ ์‹œ๊ฐ„ ์กฐํ•ฉ ๊ณต์œ ) ํ™”๋ฉด์˜ ๊ธฐ๋Šฅ(์„œ๋ฒ„ ํ†ต์‹ /์ƒํƒœ) ๋‹ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ. import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import '../config.dart'; class StudyPresetController extends ChangeNotifier { final String studentId; final String studentName; StudyPresetController({required this.studentId, required this.studentName}); bool _isLoading = true; bool _isBusy = false; String _sort = 'popular'; // popular / recent List _presets = []; bool _disposed = false; bool get isLoading => _isLoading; bool get isBusy => _isBusy; String get sort => _sort; List get presets => _presets; void _safeNotify() { if (!_disposed) notifyListeners(); } @override void dispose() { _disposed = true; super.dispose(); } Future init() => fetchPresets(); Future setSort(String sort) async { if (_sort == sort) return; _sort = sort; await fetchPresets(); } Future fetchPresets() async { _isLoading = true; _safeNotify(); try { final response = await http.get( Uri.parse('$baseUrl/api/study/presets?sort=$_sort'), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); _presets = data['presets'] ?? []; } } catch (_) { // ์กฐ์šฉํžˆ ๋ฌด์‹œ - ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ›์•„์˜จ ๋ชฉ๋ก์„ ์œ ์ง€ํ•œ๋‹ค. } finally { _isLoading = false; _safeNotify(); } } Future<(bool success, String message)> share({ required String title, required int studyMinutes, required int breakMinutes, }) async { _isBusy = true; _safeNotify(); try { final response = await http.post( Uri.parse('$baseUrl/api/study/presets'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ "studentId": studentId, "studentName": studentName, "title": title.trim(), "studyMinutes": studyMinutes, "breakMinutes": breakMinutes, }), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { await fetchPresets(); return (true, '${result['message'] ?? '๋ฃจํ‹ด์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.'}'); } return (false, '${result['message'] ?? '๋ฃจํ‹ด ๊ณต์œ  ์‹คํŒจ'}'); } catch (e) { return (false, '๋„คํŠธ์›Œํฌ ์—๋Ÿฌ: $e'); } finally { _isBusy = false; _safeNotify(); } } /// ๋‹ค๋ฅธ ํ•™์ƒ์˜ ๋ฃจํ‹ด์„ ๋‚ด ์„ค์ •์œผ๋กœ ์ ์šฉํ•  ๋•Œ ํ˜ธ์ถœ - ์ธ๊ธฐ๋„(์‚ฌ์šฉ ํšŸ์ˆ˜)๋งŒ ์˜ฌ๋ ค์ค€๋‹ค. Future markUsed(int presetId) async { try { await http.post(Uri.parse('$baseUrl/api/study/presets/$presetId/use')); } catch (_) { // ์ธ๊ธฐ๋„ ์ง‘๊ณ„ ์‹คํŒจ๋Š” ์กฐ์šฉํžˆ ๋ฌด์‹œ - ์ ์šฉ ์ž์ฒด๋Š” ์ด๋ฏธ ๋๋‚œ ๋’ค๋ผ ์˜ํ–ฅ ์—†๋‹ค. } } Future<(bool success, String message)> delete(int presetId) async { _isBusy = true; _safeNotify(); try { final response = await http.delete( Uri.parse('$baseUrl/api/study/presets/$presetId'), headers: {"Content-Type": "application/json"}, body: jsonEncode({"studentId": studentId}), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { await fetchPresets(); return (true, '${result['message'] ?? '์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'}'); } return (false, '${result['message'] ?? '์‚ญ์ œ ์‹คํŒจ'}'); } catch (e) { return (false, '๋„คํŠธ์›Œํฌ ์—๋Ÿฌ: $e'); } finally { _isBusy = false; _safeNotify(); } } }