didvan-app/lib/views/home/infography/infography_screen.dart

257 lines
9.0 KiB
Dart

import 'dart:async';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/infography/info_tag.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/home/infography/infography_screen_state.dart';
import 'package:didvan/views/home/main/widgets/infography_item.dart';
import 'package:didvan/views/widgets/didvan/card.dart';
import 'package:didvan/views/widgets/didvan/checkbox.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/item_title.dart';
import 'package:didvan/views/widgets/search_field.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:didvan/views/widgets/state_handlers/empty_result.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:animated_custom_dropdown/custom_dropdown.dart';
class InfographyScreen extends StatefulWidget {
const InfographyScreen({super.key});
@override
State<InfographyScreen> createState() => _InfographyScreenState();
}
class _InfographyScreenState extends State<InfographyScreen> {
final ScrollController _scrollController = ScrollController();
int pageNumber = 1;
Timer? _timer;
final _focusNode = FocusNode();
@override
void initState() {
context.read<InfographyScreenState>().init();
_scrollController.addListener(_onScroll);
super.initState();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent) {
pageNumber++;
context
.read<InfographyScreenState>()
.getInfographyContent(page: pageNumber);
}
}
void _onChanged(String value) {
final state = context.read<InfographyScreenState>();
if (value.length < 3 && value.isNotEmpty || state.lastSearch == value) {
return;
}
_timer?.cancel();
_timer = Timer(const Duration(seconds: 1), () {
state.search = value;
state.getInfographyContent(page: 1);
});
}
Future<void> _showFilterBottomSheet() async {
final state = context.read<InfographyScreenState>();
await ActionSheetUtils.showBottomSheet(
data: ActionSheetData(
title: 'فیلتر جستجو',
smallDismissButton: true,
titleIcon: DidvanIcons.filter_regular,
dismissTitle: 'حذف فیلتر',
confrimTitle: 'نمایش نتایج',
onDismissed: () => state.resetFilters(false),
onConfirmed: () => state.getInfographyContent(page: 1),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ItemTitle(
title: "جستجوی هشتگ",
icon: DidvanIcons.hashtag_regular,
style: Theme.of(context).textTheme.bodyMedium,
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: CustomDropdown<InTag>.multiSelectSearch(
closedHeaderPadding: const EdgeInsets.all(12),
items: state.tags,
hideSelectedFieldWhenExpanded: false,
searchHintText: "جستجوی هشتگ",
decoration: CustomDropdownDecoration(
listItemDecoration: ListItemDecoration(
selectedColor: Theme.of(context)
.colorScheme
.surface
.withOpacity(0.5),
),
searchFieldDecoration: SearchFieldDecoration(
fillColor: Theme.of(context).colorScheme.surface),
closedBorder: Border.all(color: Colors.grey),
closedFillColor: Colors.grey.shade100.withOpacity(0.1),
expandedFillColor: Theme.of(context).colorScheme.surface),
hintText: "انتخاب کنید",
onListChanged: (value) {
state.selectedTags.addAll(value);
},
),
),
ItemTitle(
title: 'دسته بندی',
icon: DidvanIcons.category_regular,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
Wrap(
children: [
for (var i = 0; i < state.categories.length; i++)
SizedBox(
width: (MediaQuery.of(context).size.width - 40) / 2,
child: DidvanCheckbox(
title: state.categories[i].label,
value: state.selectedCats.contains(state.categories[i]),
onChanged: (value) {
if (value) {
state.selectedCats.add(state.categories[i]);
return;
}
state.selectedCats.remove(state.categories[i]);
},
),
),
],
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.surface,
elevation: 0.0,
scrolledUnderElevation: 0.0,
title: DidvanText(
"اینفوگرافی",
style: Theme.of(context).textTheme.bodyLarge,
fontSize: 20,
),
),
body: Column(
children: [
Container(
height: 80,
color: Theme.of(context).colorScheme.surface,
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: SearchField(
title: "اینفوگرافی",
onChanged: _onChanged,
focusNode: _focusNode,
onFilterButtonPressed: _showFilterBottomSheet,
value: context.watch<InfographyScreenState>().lastSearch,
isFiltered: context.watch<InfographyScreenState>().filtering),
),
StateHandler<InfographyScreenState>(
placeholder: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
placeholder,
const SizedBox(
height: 8.0,
),
placeholder
],
),
),
emptyState: EmptyResult(
onNewSearch: () => _focusNode.requestFocus(),
),
enableEmptyState:
context.watch<InfographyScreenState>().contents.isEmpty,
topPadding: 16.0,
onRetry: context.read<InfographyScreenState>().init,
state: context.watch<InfographyScreenState>(),
builder: (context, state) => Expanded(
child: ListView.separated(
controller: _scrollController,
itemCount: state.contents.length,
padding: const EdgeInsets.all(8.0),
separatorBuilder: (BuildContext context, i) =>
const SizedBox(height: 8.0),
itemBuilder: (context, index) => InfographyItem(
id: state.contents[index].id,
onMarkChanged: (id, value, _) => state.changeMark(id, value),
image: state.contents[index].image,
category: state.contents[index].category,
createdAt: state.contents[index].createdAt,
title: state.contents[index].title,
tag: state.contents[index].tags,
marked: state.contents[index].marked,
),
),
),
),
],
),
);
}
static Widget get placeholder => const DidvanCard(
padding: EdgeInsets.all(8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ShimmerPlaceholder(
height: 16,
width: 240,
),
],
),
SizedBox(height: 12),
ShimmerPlaceholder(height: 200, width: 400),
SizedBox(height: 12),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ShimmerPlaceholder(
height: 32,
width: 100,
),
],
),
DidvanDivider(
verticalPadding: 12,
),
ShimmerPlaceholder(
height: 16,
width: double.infinity,
),
],
),
);
}