didvan-app/lib/views/home/statistics/statistics.dart

197 lines
6.8 KiB
Dart

import 'dart:math';
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/category.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/views/home/statistics/statistics_state.dart';
import 'package:didvan/views/home/widgets/categories_gird.dart';
import 'package:didvan/views/home/widgets/categories_list.dart';
import 'package:didvan/views/home/widgets/logo_app_bar.dart';
import 'package:didvan/views/home/widgets/overview/radar.dart';
import 'package:didvan/views/widgets/animated_visibility.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Statistics extends StatefulWidget {
const Statistics({Key? key}) : super(key: key);
@override
State<Statistics> createState() => _RadarState();
}
class _RadarState extends State<Statistics> {
final ScrollController _scrollController = ScrollController();
bool _isAnimating = false;
@override
void initState() {
_scrollController.addListener(() {
_handleAnimations();
});
final state = context.read<StatisticsState>();
state.addListener(() {
if (state.shouldColapse && mounted) {
_handleAnimations(true);
state.shouldColapse = false;
}
});
state.init();
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<StatisticsState>(
builder: (context, state, child) => Stack(
children: [
CustomScrollView(
physics: _isAnimating
? const NeverScrollableScrollPhysics()
: const ClampingScrollPhysics(),
controller: _scrollController,
slivers: [
const SliverToBoxAdapter(child: LogoAppBar()),
if (state.appState != AppState.failed)
const SliverToBoxAdapter(
child: SizedBox(height: 156),
),
if (state.appState != AppState.failed)
SliverPadding(
padding: const EdgeInsets.only(right: 16, bottom: 20),
sliver: SliverToBoxAdapter(
child: Align(
alignment: Alignment.centerRight,
child: AnimatedVisibility(
isVisible: !state.isColapsed,
duration: DesignConfig.lowAnimationDuration,
child: DidvanText(
'شاخص‌های منتخب',
style: Theme.of(context).textTheme.subtitle1,
color: Theme.of(context).colorScheme.title,
),
),
),
),
),
SliverStateHandler<StatisticsState>(
onRetry: () => state.getStatistics(page: state.page),
state: state,
itemPadding: const EdgeInsets.only(
bottom: 20,
left: 16,
right: 16,
),
enableEmptyState: state.statistics.isEmpty,
emptyState: Padding(
padding: const EdgeInsets.only(bottom: 120),
child: EmptyState(
asset: Assets.emptyResult,
title: 'موردی برای نمایش وجود ندارد.',
),
),
placeholder: RadarOverview.placeholder,
builder: (context, state, index) {
index += 2;
if (index % 15 == 0 && state.lastPage != state.page) {
state.getStatistics(page: state.page + 1);
}
index -= 2;
if (index >= state.statistics.length) {
return RadarOverview.placeholder;
}
final radar = state.statistics[index];
return RadarOverview(
radar: radar,
onMarkChanged: state.changeMark,
onCommentsChanged: (id, count) => {},
radarRequestArgs: RadarRequestArgs(
page: state.page,
categories:
List.from(state.selectedCats.map((cat) => cat.id)),
isSingleItem: false,
),
);
},
childCount: state.statistics.length +
(state.lastPage == state.page ? 0 : 3),
),
if (state.statistics.length == 1)
const SliverToBoxAdapter(
child: SizedBox(height: 320),
),
],
),
if (state.appState != AppState.failed)
CategoriesRow1(
onSelected: _onCategorySelected,
categories: state.categories,
isColapsed: state.isColapsed,
topPadding: 120,
),
if (state.appState != AppState.failed)
CategoriesList(
isRadar: false,
categories: state.categories,
isColapsed: state.isColapsed,
onSelected: () => state.getStatistics(page: 1),
selectedCats: state.selectedCats,
),
],
),
);
}
void _onCategorySelected(CategoryData category) {
final state = context.read<StatisticsState>();
state.selectedCats.clear();
if (category.id != 0) {
state.selectedCats.add(category);
}
state.getStatistics(page: 1);
}
void _handleAnimations([bool forceAnimate = false]) async {
final state = context.read<StatisticsState>();
if (_isAnimating) return;
final double position = _scrollController.offset;
if (position > 5 && !state.isColapsed || forceAnimate) {
state.isScrolled = true;
_isAnimating = true;
setState(() {});
await _scrollController.animateTo(
200,
duration: DesignConfig.mediumAnimationDuration,
curve: Curves.easeIn,
);
_isAnimating = false;
setState(() {});
} else if (position <
min(_scrollController.position.maxScrollExtent, 200) &&
state.isColapsed) {
state.isScrolled = false;
_isAnimating = true;
setState(() {});
await _scrollController.animateTo(
0,
duration: DesignConfig.mediumAnimationDuration,
curve: Curves.easeIn,
);
_isAnimating = false;
setState(() {});
}
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}