백품타 랭킹에 전체랭킹/학년랭킹 필터 추가

grade 쿼리파라미터를 생략하면 전체 학년 통합 랭킹을 주도록 백엔드를
바꾸고, 랭킹 화면에 "N학년"/"전체랭킹" 필 필터를 추가해 시간대
필터(오늘/이번주/전체)와 별도로 고를 수 있게 했다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-22 07:19:05 +00:00
co-authored by Claude Sonnet 5
parent f5aa832ad9
commit 80667d20f1
2 changed files with 42 additions and 2 deletions
+10 -1
View File
@@ -11,10 +11,12 @@ class StudyRankingController extends ChangeNotifier {
bool _isLoading = true; bool _isLoading = true;
String _period = 'today'; // today / week / total String _period = 'today'; // today / week / total
String _scope = 'grade'; // grade / all
List<dynamic> _ranking = []; List<dynamic> _ranking = [];
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
String get period => _period; String get period => _period;
String get scope => _scope;
List<dynamic> get ranking => _ranking; List<dynamic> get ranking => _ranking;
Future<void> init() => fetchRanking(); Future<void> init() => fetchRanking();
@@ -25,12 +27,19 @@ class StudyRankingController extends ChangeNotifier {
await fetchRanking(); await fetchRanking();
} }
Future<void> setScope(String scope) async {
if (_scope == scope) return;
_scope = scope;
await fetchRanking();
}
Future<void> fetchRanking() async { Future<void> fetchRanking() async {
_isLoading = true; _isLoading = true;
notifyListeners(); notifyListeners();
try { try {
final gradeParam = _scope == 'grade' ? '&grade=$grade' : '';
final response = await http.get( final response = await http.get(
Uri.parse('$baseUrl/api/study/ranking?grade=$grade&period=$_period'), Uri.parse('$baseUrl/api/study/ranking?period=$_period$gradeParam'),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(utf8.decode(response.bodyBytes)); final data = jsonDecode(utf8.decode(response.bodyBytes));
+32 -1
View File
@@ -68,10 +68,24 @@ class _StudyRankingScreenState extends State<StudyRankingScreen> {
foregroundColor: AppPalette.ink, foregroundColor: AppPalette.ink,
elevation: 0, elevation: 0,
centerTitle: true, centerTitle: true,
title: TitlePill('${widget.grade}학년 공부 랭킹'), title: TitlePill(
_controller.scope == 'grade'
? '${widget.grade}학년 공부 랭킹'
: '전체 공부 랭킹',
),
), ),
body: Column( body: Column(
children: [ children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Row(
children: [
_scopeChip('grade', '${widget.grade}학년'),
const SizedBox(width: 8),
_scopeChip('all', '전체랭킹'),
],
),
),
Padding( Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 8), padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
child: Row( child: Row(
@@ -190,4 +204,21 @@ class _StudyRankingScreenState extends State<StudyRankingScreen> {
), ),
); );
} }
Widget _scopeChip(String value, String label) {
final bool selected = _controller.scope == value;
return Expanded(
child: ChoiceChip(
label: Center(child: Text(label, style: const TextStyle(fontSize: 13))),
selected: selected,
onSelected: (_) => _controller.setScope(value),
selectedColor: AppPalette.ink,
backgroundColor: AppPalette.mist,
labelStyle: TextStyle(
color: selected ? Colors.white : Colors.grey[600],
fontWeight: FontWeight.bold,
),
),
);
}
} }