fromis_9/app/lib/services/schedules_service.dart
caadiq fbe18b6157 feat(schedule): 추천 검색어 기능 및 검색 UX 개선
- 추천 검색어 API 연동 (getSuggestions)
- SuggestionController로 추천 검색어 상태 관리
- 유튜브 스타일 검색 UX 구현
  - X 버튼 클릭 시 추천 검색어 화면으로 전환
  - 뒤로가기 시 검색 결과 화면 복원 및 검색어 유지
- 검색 결과 화면 전체 페이드 애니메이션으로 변경
- 입력 디바운스(200ms) 적용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 22:02:48 +09:00

81 lines
2.4 KiB
Dart

/// 일정 API 서비스
library;
import 'package:intl/intl.dart';
import '../models/schedule.dart';
import 'api_client.dart';
/// 오늘 날짜 (KST) 반환
String getTodayKST() {
final now = DateTime.now();
return DateFormat('yyyy-MM-dd').format(now);
}
/// 일정 목록 조회 (월별)
Future<List<Schedule>> getSchedules(int year, int month) async {
final response = await dio.get('/schedules', queryParameters: {
'year': year.toString(),
'month': month.toString(),
});
final List<dynamic> data = response.data;
return data.map((json) => Schedule.fromJson(json)).toList();
}
/// 다가오는 일정 N개 조회 (오늘 이후) - 웹과 동일
Future<List<Schedule>> getUpcomingSchedules(int limit) async {
final todayStr = getTodayKST();
final response = await dio.get('/schedules', queryParameters: {
'startDate': todayStr,
'limit': limit.toString(),
});
final List<dynamic> data = response.data;
return data.map((json) => Schedule.fromJson(json)).toList();
}
/// 일정 검색 결과
class SearchResult {
final List<Schedule> schedules;
final int offset;
final bool hasMore;
const SearchResult({
required this.schedules,
required this.offset,
required this.hasMore,
});
}
/// 일정 검색 (Meilisearch)
Future<SearchResult> searchSchedules(String query, {int offset = 0, int limit = 20}) async {
final response = await dio.get('/schedules', queryParameters: {
'search': query,
'offset': offset.toString(),
'limit': limit.toString(),
});
// 응답: { schedules: [...], hasMore: bool, offset: int }
final Map<String, dynamic> data = response.data;
final List<dynamic> schedulesJson = data['schedules'] ?? [];
final schedules = schedulesJson.map((json) => Schedule.fromJson(json)).toList();
return SearchResult(
schedules: schedules,
offset: offset,
hasMore: data['hasMore'] ?? schedules.length >= limit,
);
}
/// 추천 검색어 조회
Future<List<String>> getSuggestions(String query, {int limit = 10}) async {
if (query.trim().isEmpty) return [];
try {
final response = await dio.get('/schedules/suggestions', queryParameters: {
'q': query,
'limit': limit.toString(),
});
final Map<String, dynamic> data = response.data;
final List<dynamic> suggestions = data['suggestions'] ?? [];
return suggestions.cast<String>();
} catch (e) {
return [];
}
}