189 lines
6.1 KiB
Dart
189 lines
6.1 KiB
Dart
import 'package:didvan/config/auth_config.dart';
|
||
import 'package:didvan/models/enums.dart';
|
||
import 'package:didvan/models/overview_data.dart';
|
||
import 'package:didvan/models/home_page_content/swot.dart';
|
||
import 'package:didvan/providers/core.dart';
|
||
import 'package:didvan/services/auth/token_storage.dart';
|
||
import 'package:didvan/services/content/content_service.dart';
|
||
import 'package:didvan/services/network/request.dart';
|
||
import 'package:didvan/services/network/request_helper.dart';
|
||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||
import 'package:didvan/services/swot_service.dart';
|
||
|
||
class BookmarksState extends CoreProvier {
|
||
final List<OverviewData> bookmarks = [];
|
||
List<SwotItem> bookmarkedSwotItems = [];
|
||
|
||
String search = '';
|
||
String lastSearch = '';
|
||
int page = 1;
|
||
int lastPage = 1;
|
||
List<int> selectedTypes = [];
|
||
DateTime? startDate;
|
||
DateTime? endDate;
|
||
bool get isFiltered =>
|
||
selectedTypes.isNotEmpty || startDate != null || endDate != null;
|
||
|
||
bool _swotItemsLoading = false;
|
||
bool get searching => search.isNotEmpty;
|
||
bool get swotItemsLoading => _swotItemsLoading;
|
||
|
||
Future<void> loadInitialData() async {
|
||
appState = AppState.busy;
|
||
_swotItemsLoading = true;
|
||
bookmarks.clear();
|
||
bookmarkedSwotItems.clear();
|
||
notifyListeners();
|
||
|
||
await Future.wait([
|
||
_fetchGeneralBookmarks(page: 1),
|
||
_fetchSwotBookmarks(),
|
||
]);
|
||
|
||
if (appState != AppState.failed && !searching) {
|
||
appState = AppState.idle;
|
||
} else if (appState != AppState.failed &&
|
||
searching &&
|
||
bookmarks.isEmpty &&
|
||
bookmarkedSwotItems.isEmpty) {
|
||
appState = AppState.idle;
|
||
}
|
||
_swotItemsLoading = false;
|
||
notifyListeners();
|
||
}
|
||
|
||
Future<void> _fetchGeneralBookmarks({required int page}) async {
|
||
if (page == 1) bookmarks.clear();
|
||
this.page = page;
|
||
if (!searching) lastSearch = search;
|
||
|
||
// مسیر جدید: content های bookmarkشده از api2.didvan.com.
|
||
final userId = TokenStorage.userId;
|
||
if (userId != null && userId.isNotEmpty) {
|
||
final result = await ContentService.instance.getBookmarkedContents(
|
||
userId: userId,
|
||
page: page,
|
||
limit: 15,
|
||
search: search.isNotEmpty ? search : null,
|
||
);
|
||
if (result.isSuccess && result.data != null) {
|
||
lastPage = result.data!.totalPages;
|
||
bookmarks.addAll(result.data!.data.map((c) {
|
||
final ov = OverviewData.fromContentItem(c);
|
||
// در صفحهی نشانشدهها فیلدِ «یادداشتِ من» از description خوانده
|
||
// میشود؛ آن را خالی میکنیم تا کاربر یادداشتِ خودش را بنویسد و
|
||
// summaryِ محتوا در آن نیاید.
|
||
ov.description = '';
|
||
return ov;
|
||
}));
|
||
return;
|
||
}
|
||
// اگر content جدید خطا داد (مثلا 403) و legacy هم در دسترس نیست،
|
||
// فقط swot bookmarks نمایش داده میشود؛ general را خالی میگذاریم.
|
||
if (!AuthConfig.useLegacyApi) {
|
||
// failure را fatal نمیکنیم تا swot bookmarks دیده شوند.
|
||
return;
|
||
}
|
||
}
|
||
|
||
// TODO(backend-migration): مسیر legacy (api.didvan.app/home/mark/v2).
|
||
// فعلا فقط در صورت useLegacyApi اجرا میشود.
|
||
if (!AuthConfig.useLegacyApi) return;
|
||
final service = RequestService(
|
||
RequestHelper.searchMarks(
|
||
page: page,
|
||
search: search.isNotEmpty ? search : null,
|
||
types: selectedTypes.isNotEmpty ? selectedTypes : null,
|
||
startDate: startDate?.toIso8601String().split('T').first,
|
||
endDate: endDate?.toIso8601String().split('T').first,
|
||
),
|
||
);
|
||
await service.httpGet();
|
||
if (service.isSuccess) {
|
||
lastPage = service.result['lastPage'];
|
||
final marks = service.result['contents'];
|
||
for (var i = 0; i < marks.length; i++) {
|
||
bookmarks.add(OverviewData.fromJson(marks[i]));
|
||
}
|
||
} else {
|
||
appState = AppState.failed;
|
||
}
|
||
}
|
||
|
||
Future<void> searchAndLoadData({required int page}) async {
|
||
appState = AppState.busy;
|
||
_swotItemsLoading = true;
|
||
bookmarks.clear();
|
||
notifyListeners();
|
||
|
||
await Future.wait([
|
||
_fetchGeneralBookmarks(page: page),
|
||
_fetchSwotBookmarks(),
|
||
]);
|
||
|
||
if (appState != AppState.failed) {
|
||
appState = AppState.idle;
|
||
}
|
||
_swotItemsLoading = false;
|
||
notifyListeners();
|
||
}
|
||
|
||
Future<void> _fetchSwotBookmarks() async {
|
||
try {
|
||
if (selectedTypes.isNotEmpty && !selectedTypes.contains(8)) {
|
||
bookmarkedSwotItems = [];
|
||
return;
|
||
}
|
||
|
||
// TODO(backend-migration): opportunity-threat.didvan.com/api/bookmarks
|
||
// توکن جدید Keycloak را نمیپذیرد (403). تا زمانی که آن سرور با
|
||
// احراز هویت جدید سازگار شود یا bookmark به api2 منتقل شود، این
|
||
// مسیر را در حالت غیر-legacy رد میکنیم.
|
||
if (!AuthConfig.useLegacyApi) {
|
||
bookmarkedSwotItems = [];
|
||
return;
|
||
}
|
||
|
||
final postIds = await BookmarkService.fetchBookmarks();
|
||
if (postIds.isNotEmpty) {
|
||
final allSwots = await SwotService.fetchSwotItems();
|
||
|
||
bookmarkedSwotItems = allSwots.where((swot) {
|
||
final isBookmarked = postIds.contains(swot.id);
|
||
if (search.isEmpty) return isBookmarked;
|
||
return isBookmarked &&
|
||
swot.title.toLowerCase().contains(search.toLowerCase());
|
||
}).toList();
|
||
} else {
|
||
bookmarkedSwotItems = [];
|
||
}
|
||
} catch (e) {
|
||
bookmarkedSwotItems = [];
|
||
}
|
||
}
|
||
|
||
void onMarkChanged(int id, bool value) {
|
||
bookmarks.removeWhere((element) => element.id == id);
|
||
notifyListeners();
|
||
}
|
||
|
||
void onSwotMarkChanged(int swotId) {
|
||
bookmarkedSwotItems.removeWhere((element) => element.id == swotId);
|
||
notifyListeners();
|
||
}
|
||
|
||
void resetFilters([bool notify = true]) {
|
||
selectedTypes.clear();
|
||
startDate = null;
|
||
endDate = null;
|
||
if (notify) {
|
||
loadInitialData();
|
||
}
|
||
}
|
||
|
||
// ignore: annotate_overrides
|
||
void update() {
|
||
notifyListeners();
|
||
}
|
||
}
|