some changes
This commit is contained in:
parent
b5ee5887c6
commit
058ffbef0d
|
|
@ -15,6 +15,7 @@ class OverviewData {
|
|||
final bool forManagers;
|
||||
final String createdAt;
|
||||
final String type;
|
||||
int typeInteger;
|
||||
int comments;
|
||||
bool marked;
|
||||
final List<CategoryData>? categories;
|
||||
|
|
@ -35,17 +36,41 @@ class OverviewData {
|
|||
this.timeToRead,
|
||||
this.reference,
|
||||
this.categories,
|
||||
});
|
||||
this.typeInteger = 0,
|
||||
}) {
|
||||
switch (type) {
|
||||
case 'radar':
|
||||
typeInteger = 1;
|
||||
break;
|
||||
case 'news':
|
||||
typeInteger = 2;
|
||||
break;
|
||||
case 'video':
|
||||
typeInteger = 3;
|
||||
break;
|
||||
case 'podcast':
|
||||
typeInteger = 4;
|
||||
break;
|
||||
case 'saha':
|
||||
typeInteger = 6;
|
||||
break;
|
||||
default:
|
||||
typeInteger = 5;
|
||||
}
|
||||
typeInteger = 2;
|
||||
}
|
||||
|
||||
factory OverviewData.fromJson(Map<String, dynamic> json) {
|
||||
String? description;
|
||||
if (json['description'] != null) {
|
||||
final document = parse(json['description']);
|
||||
final String parsedString =
|
||||
parse(document.body!.text).documentElement!.text;
|
||||
description = parse(document.body!.text).documentElement!.text;
|
||||
}
|
||||
return OverviewData(
|
||||
id: json['id'],
|
||||
title: json['title'],
|
||||
image: json['image'],
|
||||
description: parsedString,
|
||||
image: json['image'] ?? 'https://wallpapercave.com/fwp/wp12977378.jpg',
|
||||
description: description ?? '',
|
||||
timeToRead: json['timeToRead'],
|
||||
reference: json['reference'],
|
||||
forManagers: json['forManagers'] ?? false,
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ class UserProvider extends CoreProvier {
|
|||
|
||||
int get unreadMessageCount => _unreadMessageCount;
|
||||
|
||||
static final List<MapEntry> _radarMarkQueue = [];
|
||||
static final List<MapEntry> _newsMarkQueue = [];
|
||||
static final List<MapEntry> _studioMarkQueue = [];
|
||||
// static final List<MapEntry> _radarMarkQueue = [];
|
||||
// static final List<MapEntry> _newsMarkQueue = [];
|
||||
// static final List<MapEntry> _studioMarkQueue = [];
|
||||
static final List<MapEntry> _statisticMarkQueue = [];
|
||||
static final List<Map> _itemMarkQueue = [];
|
||||
|
||||
|
|
@ -188,53 +188,53 @@ class UserProvider extends CoreProvier {
|
|||
});
|
||||
}
|
||||
|
||||
static Future<void> changeRadarMark(int id, bool value) async {
|
||||
_radarMarkQueue.add(MapEntry(id, value));
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
final MapEntry? lastChange =
|
||||
_radarMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
if (lastChange == null) return;
|
||||
final service = RequestService(RequestHelper.mark(id, 'radar'));
|
||||
if (lastChange.value) {
|
||||
await service.post();
|
||||
} else {
|
||||
await service.delete();
|
||||
}
|
||||
_radarMarkQueue.removeWhere((element) => element.key == id);
|
||||
});
|
||||
}
|
||||
// static Future<void> changeRadarMark(int id, bool value) async {
|
||||
// _radarMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _radarMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'radar'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// }
|
||||
// _radarMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
static Future<void> changeStudioMark(int id, bool value) async {
|
||||
_studioMarkQueue.add(MapEntry(id, value));
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
final MapEntry? lastChange =
|
||||
_studioMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
if (lastChange == null) return;
|
||||
final service = RequestService(RequestHelper.mark(id, 'studio'));
|
||||
if (lastChange.value) {
|
||||
await service.post();
|
||||
} else {
|
||||
await service.delete();
|
||||
}
|
||||
_studioMarkQueue.removeWhere((element) => element.key == id);
|
||||
});
|
||||
}
|
||||
// static Future<void> changeStudioMark(int id, bool value) async {
|
||||
// _studioMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _studioMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'studio'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// }
|
||||
// _studioMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
static Future<void> changeNewsMark(int id, bool value) async {
|
||||
_newsMarkQueue.add(MapEntry(id, value));
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
final MapEntry? lastChange =
|
||||
_newsMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
if (lastChange == null) return;
|
||||
final service = RequestService(RequestHelper.mark(id, 'news'));
|
||||
if (lastChange.value) {
|
||||
await service.post();
|
||||
} else {
|
||||
await service.delete();
|
||||
}
|
||||
_newsMarkQueue.removeWhere((element) => element.key == id);
|
||||
});
|
||||
}
|
||||
// static Future<void> changeNewsMark(int id, bool value) async {
|
||||
// _newsMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _newsMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'news'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// }
|
||||
// _newsMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
static Future<void> changeStatisticMark(int id, bool value) async {
|
||||
_statisticMarkQueue.add(MapEntry(id, value));
|
||||
|
|
@ -252,11 +252,11 @@ class UserProvider extends CoreProvier {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> getUnreadMessageCount() async {
|
||||
final RequestService service = RequestService(RequestHelper.directs);
|
||||
await service.httpGet();
|
||||
if (service.isSuccess) {
|
||||
_unreadMessageCount = service.result['unread'] ?? 0;
|
||||
}
|
||||
}
|
||||
// Future<void> getUnreadMessageCount() async {
|
||||
// final RequestService service = RequestService(RequestHelper.directs);
|
||||
// await service.httpGet();
|
||||
// if (service.isSuccess) {
|
||||
// _unreadMessageCount = service.result['unread'] ?? 0;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,17 +51,6 @@ class RequestHelper {
|
|||
static const String otp = '$_baseUserUrl/otp';
|
||||
static String editItemBookmark(String type, int id) =>
|
||||
'$_baseHomeUrl/$type/$id/mark';
|
||||
static String bookmarks({
|
||||
required int page,
|
||||
String? search,
|
||||
String? type,
|
||||
String? studioType,
|
||||
}) =>
|
||||
'$_baseUserUrl/marked/${type ?? ''}${_urlConcatGenerator([
|
||||
MapEntry('page', page),
|
||||
MapEntry('type', studioType),
|
||||
MapEntry('search', search),
|
||||
])}';
|
||||
|
||||
static const String directTypes = '$baseUrl/direct/types';
|
||||
static String direct(int id) => '$_baseDirectUrl/$id';
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ class BookmarksState extends CoreProvier {
|
|||
}
|
||||
this.page = page;
|
||||
appState = AppState.busy;
|
||||
final service =
|
||||
RequestService(RequestHelper.bookmarks(page: page, search: search));
|
||||
final service = RequestService(
|
||||
RequestHelper.searchMarks(page: page, search: search),
|
||||
);
|
||||
await service.httpGet();
|
||||
|
||||
if (service.isSuccess) {
|
||||
lastPage = service.result['lastPage'];
|
||||
final marks = service.result['contents'];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import 'package:didvan/views/widgets/overview/multitype.dart';
|
|||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||
import 'package:didvan/views/widgets/item_title.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/empty_list.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/empty_result.dart';
|
||||
|
|
@ -40,14 +39,80 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = context.watch<BookmarksState>();
|
||||
return DidvanScaffold(
|
||||
appBarData: null,
|
||||
// appBarData: AppBarData(
|
||||
// title: 'نشان شدهها',
|
||||
// hasBack: true,
|
||||
// ),
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverStateHandler<BookmarksState>(
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
AnimatedVisibility(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
isVisible: !state.searching,
|
||||
child: DidvanCard(
|
||||
child: Column(
|
||||
children: [
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(5),
|
||||
title: 'تحلیلهای رادار',
|
||||
icon: DidvanIcons.radar_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(2),
|
||||
title: 'دنیای فولاد',
|
||||
icon: DidvanIcons.news_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(1),
|
||||
title: 'پویش افق',
|
||||
icon: DidvanIcons.radar_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(3),
|
||||
title: 'ویدئوکست',
|
||||
icon: DidvanIcons.video_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(4),
|
||||
title: 'پادکستها',
|
||||
icon: DidvanIcons.podcast_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(6),
|
||||
title: 'سها',
|
||||
icon: DidvanIcons.podcast_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: AnimatedVisibility(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
isVisible: !state.searching,
|
||||
child: const ItemTitle(title: 'آخرین نشان شدهها'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverStateHandler<BookmarksState>(
|
||||
state: state,
|
||||
centerEmptyState: state.searching,
|
||||
builder: (context, state, index) {
|
||||
|
|
@ -73,78 +138,19 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
state.bookmarks.length + (state.page != state.lastPage ? 1 : 0),
|
||||
onRetry: () => state.getBookmarks(page: state.page),
|
||||
),
|
||||
],
|
||||
children: [
|
||||
// SearchField(
|
||||
// title: 'نشان شدهها',
|
||||
// onChanged: _onChanged,
|
||||
// focusNode: _focuseNode,
|
||||
// ),
|
||||
const SizedBox(height: 16),
|
||||
AnimatedVisibility(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
isVisible: !state.searching,
|
||||
child: DidvanCard(
|
||||
child: Column(
|
||||
children: [
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected('radar'),
|
||||
title: 'تحلیلهای رادار',
|
||||
icon: DidvanIcons.radar_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected('news'),
|
||||
title: 'دنیای فولاد',
|
||||
icon: DidvanIcons.news_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected('radar'),
|
||||
title: 'پویش افق',
|
||||
icon: DidvanIcons.radar_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected('video'),
|
||||
title: 'ویدئوکست',
|
||||
icon: DidvanIcons.video_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected('podcast'),
|
||||
title: 'پادکستها',
|
||||
icon: DidvanIcons.podcast_solid,
|
||||
iconSize: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: AnimatedVisibility(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
isVisible: !state.searching,
|
||||
child: const ItemTitle(title: 'آخرین نشان شدهها'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onCategorySelected(String type) {
|
||||
void _onCategorySelected(int type) {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.of(context).pushNamed(Routes.filteredBookmarks, arguments: {
|
||||
'type': type,
|
||||
'onDeleted': (int id) {
|
||||
final state = context.read<BookmarksState>();
|
||||
state.bookmarks
|
||||
.removeWhere((element) => element.id == id && element.type == type);
|
||||
state.bookmarks.removeWhere(
|
||||
(element) => element.id == id && element.typeInteger == type);
|
||||
state.update();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,18 +28,20 @@ class _FilteredBookmarksState extends State<FilteredBookmarks> {
|
|||
|
||||
String get _appBarTitle {
|
||||
switch (context.read<FilteredBookmarksState>().type) {
|
||||
case 'radar':
|
||||
case 1:
|
||||
return 'پویش افق';
|
||||
case 'news':
|
||||
case 2:
|
||||
return 'دنیای فولاد';
|
||||
case 'video':
|
||||
case 3:
|
||||
return 'ویدئوکستها';
|
||||
case 'podcast':
|
||||
case 4:
|
||||
return 'پادکستها';
|
||||
case 'new-radar':
|
||||
case 5:
|
||||
return 'تحلیلهای رادار';
|
||||
case 6:
|
||||
return 'سها';
|
||||
default:
|
||||
return 'پادکستها';
|
||||
return 'پویش';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:didvan/services/network/request_helper.dart';
|
|||
|
||||
class FilteredBookmarksState extends CoreProvier {
|
||||
final List<OverviewData> bookmarks = [];
|
||||
final String type;
|
||||
final int type;
|
||||
int page = 1;
|
||||
int lastPage = 1;
|
||||
|
||||
|
|
@ -14,26 +14,17 @@ class FilteredBookmarksState extends CoreProvier {
|
|||
|
||||
Future<void> getBookmarks({required int page}) async {
|
||||
this.page = page;
|
||||
String typeString = '';
|
||||
if (type == 'video' || type == 'podcast') {
|
||||
typeString = 'studios';
|
||||
} else if (type == 'news') {
|
||||
typeString = type;
|
||||
} else {
|
||||
typeString = '${type}s';
|
||||
}
|
||||
final service = RequestService(
|
||||
RequestHelper.bookmarks(
|
||||
type: typeString,
|
||||
RequestHelper.searchMarks(
|
||||
types: [type],
|
||||
page: page,
|
||||
studioType: type == 'podcast' || type == 'video' ? type : null,
|
||||
),
|
||||
);
|
||||
await service.httpGet();
|
||||
|
||||
if (service.isSuccess) {
|
||||
lastPage = service.result['lastPage'];
|
||||
final marks = service.result[typeString];
|
||||
final marks = service.result['contents'];
|
||||
for (var i = 0; i < marks.length; i++) {
|
||||
bookmarks.add(OverviewData.fromJson(marks[i]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class HomeState extends CoreProvier {
|
|||
final List<CategoryData> selectedCats = [];
|
||||
final List<OverviewData> results = [];
|
||||
late TabController tabController;
|
||||
int unreadCount = 0;
|
||||
|
||||
void resetFilters(bool isInit) {
|
||||
startDate = null;
|
||||
|
|
@ -122,6 +123,7 @@ class HomeState extends CoreProvier {
|
|||
await service.httpGet();
|
||||
if (service.isSuccess) {
|
||||
lastPage = service.result['lastPage'];
|
||||
unreadCount = service.result['unread'];
|
||||
results.addAll(
|
||||
List<OverviewData>.from(
|
||||
service.result['contents'].map(
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@ class _SplashState extends State<Splash> {
|
|||
}
|
||||
RequestService.token = token;
|
||||
final result = await userProvider.getUserInfo();
|
||||
await userProvider.getUnreadMessageCount();
|
||||
if (!result && mounted) {
|
||||
StorageService.delete(key: 'token');
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
|
|
|
|||
|
|
@ -74,21 +74,7 @@ class _BookmarkButtonState extends State<BookmarkButton> {
|
|||
_value = !_value;
|
||||
});
|
||||
widget.onMarkChanged(_value);
|
||||
switch (widget.type) {
|
||||
case 'radar':
|
||||
UserProvider.changeRadarMark(widget.itemId, _value);
|
||||
break;
|
||||
case 'news':
|
||||
UserProvider.changeNewsMark(widget.itemId, _value);
|
||||
break;
|
||||
case 'podcast':
|
||||
UserProvider.changeStudioMark(widget.itemId, _value);
|
||||
break;
|
||||
case 'video':
|
||||
UserProvider.changeStudioMark(widget.itemId, _value);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
UserProvider.changeItemMark(widget.type, widget.itemId, _value);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ class _NavBarItem extends StatelessWidget {
|
|||
final String title;
|
||||
final IconData selectedIcon;
|
||||
final IconData unselectedIcon;
|
||||
final bool hasBadge;
|
||||
const _NavBarItem({
|
||||
Key? key,
|
||||
required this.isSelected,
|
||||
|
|
@ -376,7 +375,6 @@ class _NavBarItem extends StatelessWidget {
|
|||
required this.selectedIcon,
|
||||
required this.unselectedIcon,
|
||||
required this.onTap,
|
||||
this.hasBadge = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
|
@ -407,26 +405,13 @@ class _NavBarItem extends StatelessWidget {
|
|||
? Theme.of(context).colorScheme.focused
|
||||
: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Icon(
|
||||
child: Icon(
|
||||
isSelected ? selectedIcon : unselectedIcon,
|
||||
size: 32,
|
||||
color: DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.text
|
||||
: Theme.of(context).colorScheme.title,
|
||||
),
|
||||
if (hasBadge)
|
||||
Container(
|
||||
height: 12,
|
||||
width: 12,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
DidvanText(
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class LogoAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = context.read<HomeState>();
|
||||
final MediaQueryData d = MediaQuery.of(context);
|
||||
return Container(
|
||||
height: 144,
|
||||
|
|
@ -63,10 +64,30 @@ class LogoAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||
width: 1,
|
||||
color: Theme.of(context).colorScheme.border,
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
DidvanIconButton(
|
||||
icon: DidvanIcons.notification_light,
|
||||
icon: state.unreadCount == 0
|
||||
? DidvanIcons.message_light
|
||||
: DidvanIcons.message_solid,
|
||||
size: 32,
|
||||
onPressed: () => {},
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pushNamed(Routes.direct),
|
||||
),
|
||||
if (state.unreadCount != 0)
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 4,
|
||||
child: Container(
|
||||
height: 12,
|
||||
width: 12,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue