feat(app): 客户端展示多语言并支持筛选分页

This commit is contained in:
Zhou Weidong committed 2026-10-24 17:20:24 +08:00
1 parent 8481611372
commit 8b50b5bd06
68 files changed
+2742 -1120

No files matched your search

@@ -0,0 +1,128 @@
// Author: fruit.com.cn
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/models/content_category.dart';
import 'package:fruitshorts/core/data/models/drama.dart';
import 'package:fruitshorts/core/data/models/page_result.dart';
import 'package:fruitshorts/core/data/services/all_dramas_controller.dart';
void main() {
test('should_replace_first_page_when_refresh_succeeds', () async {
final remote = _ScriptedRemote(
pages: [
PageResult(total: 2, list: [_drama('a'), _drama('b')]),
],
);
final controller = AllDramasController(api: remote);
await controller.refresh();
expect(controller.dramas.map((item) => item.id), ['a', 'b']);
expect(controller.hasMore, isFalse);
expect(controller.error, isNull);
expect(remote.pagesRequested, [1]);
});
test('should_append_next_page_when_more_dramas_remain', () async {
final remote = _ScriptedRemote(
pages: [
PageResult(total: 3, list: [_drama('a'), _drama('b')]),
PageResult(total: 3, list: [_drama('c')]),
],
);
final controller = AllDramasController(api: remote);
await controller.refresh();
await controller.loadMore();
expect(controller.dramas.map((item) => item.id), ['a', 'b', 'c']);
expect(controller.hasMore, isFalse);
expect(remote.pagesRequested, [1, 2]);
});
test('should_keep_loaded_dramas_when_next_page_fails', () async {
final remote = _ScriptedRemote(
pages: [PageResult(total: 3, list: [_drama('a')])],
failOnPage: 2,
);
final controller = AllDramasController(api: remote);
await controller.refresh();
await controller.loadMore();
expect(controller.dramas.map((item) => item.id), ['a']);
expect(controller.error, isNotNull);
});
test('should_clear_selected_type_when_all_is_chosen', () {
final controller = AllDramasController.preview(
categories: const [ContentCategory(id: '2', name: '甜宠')],
);
controller.toggleCategory('2');
controller.toggleCategory('');
expect(controller.selectedCategories, isEmpty);
});
test('should_send_selected_ids_when_loading_a_page', () async {
final remote = _ScriptedRemote(
pages: [PageResult(total: 0, list: const [])],
);
final controller = AllDramasController(api: remote);
controller.toggleCategory('2');
controller.toggleClassification('3');
controller.toggleTag('4');
await controller.refresh();
expect(remote.lastCategoryIds, ['2']);
expect(remote.lastClassificationIds, ['3']);
expect(remote.lastTagIds, ['4']);
});
}
Drama _drama(String id) {
return Drama(id: id, title: id, synopsis: '', posterUrl: '');
}
class _ScriptedRemote implements AllDramasRemote {
_ScriptedRemote({required this.pages, this.failOnPage});
final List<PageResult<Drama>> pages;
final int? failOnPage;
final List<int> pagesRequested = [];
List<String> lastCategoryIds = const [];
List<String> lastClassificationIds = const [];
List<String> lastTagIds = const [];
@override
Future<List<ContentCategory>> classifications() async => const [
ContentCategory(id: '3', name: '精选'),
];
@override
Future<List<ContentCategory>> categories() async => const [
ContentCategory(id: '2', name: '甜宠'),
];
@override
Future<List<ContentCategory>> tags() async => const [
ContentCategory(id: '4', name: '热剧'),
];
@override
Future<PageResult<Drama>> dramas({
required List<String> categoryIds,
required List<String> classificationIds,
required List<String> tagIds,
required int pageIndex,
}) async {
lastCategoryIds = categoryIds;
lastClassificationIds = classificationIds;
lastTagIds = tagIds;
pagesRequested.add(pageIndex);
if (pageIndex == failOnPage) throw StateError('page failed');
return pages[pageIndex - 1];
}
}