240 lines
6.9 KiB
Dart
240 lines
6.9 KiB
Dart
import 'dart:convert';
|
|
import 'package:didvan/constants/assets.dart';
|
|
import 'package:didvan/models/category.dart';
|
|
import 'package:didvan/models/enums.dart';
|
|
import 'package:didvan/models/monthly/monthly_model.dart';
|
|
import 'package:didvan/providers/core.dart';
|
|
import 'package:didvan/services/network/request.dart';
|
|
import 'package:didvan/services/network/request_helper.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
class MonthlyListState extends CoreProvier {
|
|
List<MonthlyItem> monthlyItems = [];
|
|
List<MonthlyItem> _allMonthlyItems = [];
|
|
String searchQuery = '';
|
|
String? startDate;
|
|
String? endDate;
|
|
final List<CategoryData> selectedCats = [];
|
|
List<CategoryData> categories = [];
|
|
bool filtering = false;
|
|
|
|
void initCategories() {
|
|
categories = [
|
|
CategoryData(
|
|
id: 1,
|
|
label: 'اقتصادی',
|
|
asset: Assets.economicCategoryIcon,
|
|
),
|
|
CategoryData(
|
|
id: 2,
|
|
label: 'سیاسی',
|
|
asset: Assets.politicalCategoryIcon,
|
|
),
|
|
CategoryData(
|
|
id: 3,
|
|
label: 'فناوری',
|
|
asset: Assets.techCategoryIcon,
|
|
),
|
|
CategoryData(
|
|
id: 4,
|
|
label: 'کسب و کار',
|
|
asset: Assets.businessCategoryIcon,
|
|
),
|
|
CategoryData(
|
|
id: 5,
|
|
label: 'زیستمحیطی',
|
|
asset: Assets.enviromentalCategoryIcon,
|
|
),
|
|
CategoryData(
|
|
id: 6,
|
|
label: 'اجتماعی',
|
|
asset: Assets.socialCategoryIcon,
|
|
),
|
|
];
|
|
}
|
|
|
|
bool get searching => searchQuery.isNotEmpty;
|
|
|
|
Future<void> fetchMonthlyList() async {
|
|
appState = AppState.busy;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final url = '${RequestHelper.baseUrl}/monthly';
|
|
debugPrint('Fetching monthly list from: $url');
|
|
|
|
final response = await http.get(
|
|
Uri.parse(url),
|
|
headers: {
|
|
'Authorization': 'Bearer ${RequestService.token}',
|
|
'accept': '*/*',
|
|
'Content-Type': 'application/json; charset=UTF-8',
|
|
},
|
|
).timeout(const Duration(seconds: 30));
|
|
|
|
debugPrint('Response status code: ${response.statusCode}');
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonData = json.decode(response.body);
|
|
debugPrint('Decoded JSON: $jsonData');
|
|
|
|
final List<dynamic> resultList = jsonData['result'] as List;
|
|
debugPrint('Found ${resultList.length} items');
|
|
|
|
_allMonthlyItems =
|
|
resultList.map((item) => MonthlyItem.fromJson(item)).toList();
|
|
|
|
monthlyItems = _applyFilters(_allMonthlyItems);
|
|
|
|
debugPrint(
|
|
'Successfully parsed ${monthlyItems.length} monthly items after filters');
|
|
appState = AppState.idle;
|
|
} else {
|
|
debugPrint('Request failed with status code: ${response.statusCode}');
|
|
appState = AppState.failed;
|
|
}
|
|
} catch (e, stackTrace) {
|
|
debugPrint('Error fetching monthly list: $e');
|
|
debugPrint('Stack trace: $stackTrace');
|
|
appState = AppState.failed;
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
void search(String query) {
|
|
searchQuery = query;
|
|
var filtered = _allMonthlyItems;
|
|
|
|
if (query.isNotEmpty) {
|
|
filtered = filtered
|
|
.where((item) =>
|
|
item.title.toLowerCase().contains(query.toLowerCase()) ||
|
|
item.description.toLowerCase().contains(query.toLowerCase()))
|
|
.toList();
|
|
}
|
|
|
|
monthlyItems = _applyFilters(filtered);
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> toggleLike(int id) async {
|
|
try {
|
|
final url = '${RequestHelper.baseUrl}/monthly/$id/like';
|
|
debugPrint('Toggling like for monthly item: $url');
|
|
|
|
final index = monthlyItems.indexWhere((item) => item.id == id);
|
|
if (index != -1) {
|
|
monthlyItems[index].isLiked = !monthlyItems[index].isLiked;
|
|
notifyListeners();
|
|
}
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {
|
|
'Authorization': 'Bearer ${RequestService.token}',
|
|
'accept': '*/*',
|
|
'Content-Type': 'application/json; charset=UTF-8',
|
|
},
|
|
).timeout(const Duration(seconds: 30));
|
|
|
|
if (response.statusCode == 200) {
|
|
debugPrint('Like toggled successfully');
|
|
} else {
|
|
debugPrint('Failed to toggle like: ${response.statusCode}');
|
|
if (index != -1) {
|
|
monthlyItems[index].isLiked = !monthlyItems[index].isLiked;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Error toggling like: $e');
|
|
final index = monthlyItems.indexWhere((item) => item.id == id);
|
|
if (index != -1) {
|
|
monthlyItems[index].isLiked = !monthlyItems[index].isLiked;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> toggleBookmark(int id) async {
|
|
try {
|
|
final url = '${RequestHelper.baseUrl}/monthly/$id/mark';
|
|
debugPrint('Toggling bookmark for monthly item: $url');
|
|
|
|
final index = monthlyItems.indexWhere((item) => item.id == id);
|
|
if (index != -1) {
|
|
monthlyItems[index].isBookmarked = !monthlyItems[index].isBookmarked;
|
|
notifyListeners();
|
|
}
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {
|
|
'Authorization': 'Bearer ${RequestService.token}',
|
|
'accept': '*/*',
|
|
'Content-Type': 'application/json; charset=UTF-8',
|
|
},
|
|
).timeout(const Duration(seconds: 30));
|
|
|
|
if (response.statusCode == 200) {
|
|
debugPrint('Bookmark toggled successfully');
|
|
} else {
|
|
debugPrint('Failed to toggle bookmark: ${response.statusCode}');
|
|
if (index != -1) {
|
|
monthlyItems[index].isBookmarked = !monthlyItems[index].isBookmarked;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Error toggling bookmark: $e');
|
|
final index = monthlyItems.indexWhere((item) => item.id == id);
|
|
if (index != -1) {
|
|
monthlyItems[index].isBookmarked = !monthlyItems[index].isBookmarked;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
}
|
|
|
|
void resetFilters([bool notify = true]) {
|
|
startDate = null;
|
|
endDate = null;
|
|
selectedCats.clear();
|
|
filtering = false;
|
|
if (notify) {
|
|
fetchMonthlyList();
|
|
}
|
|
}
|
|
|
|
List<MonthlyItem> _applyFilters(List<MonthlyItem> items) {
|
|
var filtered = items;
|
|
|
|
if (startDate != null || endDate != null) {
|
|
filtered = filtered.where((item) {
|
|
final itemDate = DateTime.parse(item.publishedAt);
|
|
|
|
if (startDate != null) {
|
|
final start = DateTime.parse(startDate!);
|
|
if (itemDate.isBefore(start)) return false;
|
|
}
|
|
|
|
if (endDate != null) {
|
|
final end = DateTime.parse(endDate!).add(const Duration(days: 1));
|
|
if (itemDate.isAfter(end)) return false;
|
|
}
|
|
|
|
return true;
|
|
}).toList();
|
|
}
|
|
|
|
if (selectedCats.isNotEmpty) {
|
|
filtered = filtered.where((item) {
|
|
return item.tags
|
|
.any((tag) => selectedCats.any((cat) => cat.id == tag.id));
|
|
}).toList();
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
}
|