restucturing | reusablity

This commit is contained in:
MohammadTaha Basiri 2022-01-29 14:03:32 +03:30
parent 0553cc75ae
commit 711a4ad1d0
17 changed files with 166 additions and 349 deletions

View File

@ -1,4 +1,4 @@
class NewsOverview { class NewsOverviewData {
final int id; final int id;
final String title; final String title;
final String reference; final String reference;
@ -7,7 +7,7 @@ class NewsOverview {
final String createdAt; final String createdAt;
bool marked; bool marked;
NewsOverview({ NewsOverviewData({
required this.id, required this.id,
required this.title, required this.title,
required this.reference, required this.reference,
@ -17,7 +17,8 @@ class NewsOverview {
required this.marked, required this.marked,
}); });
factory NewsOverview.fromJson(Map<String, dynamic> json) => NewsOverview( factory NewsOverviewData.fromJson(Map<String, dynamic> json) =>
NewsOverviewData(
id: json['id'], id: json['id'],
title: json['title'], title: json['title'],
reference: json['reference'], reference: json['reference'],

View File

@ -1,6 +1,6 @@
import 'category.dart'; import 'category.dart';
class RadarOverview { class RadarOverviewData {
final int id; final int id;
final String image; final String image;
final String title; final String title;
@ -12,7 +12,7 @@ class RadarOverview {
final List<Category> categories; final List<Category> categories;
int comments; int comments;
RadarOverview({ RadarOverviewData({
required this.id, required this.id,
required this.image, required this.image,
required this.title, required this.title,
@ -25,7 +25,8 @@ class RadarOverview {
required this.comments, required this.comments,
}); });
factory RadarOverview.fromJson(Map<String, dynamic> json) => RadarOverview( factory RadarOverviewData.fromJson(Map<String, dynamic> json) =>
RadarOverviewData(
id: json['id'], id: json['id'],
image: json['image'], image: json['image'],
title: json['title'], title: json['title'],

View File

@ -4,7 +4,7 @@ import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/pages/home/news/news_state.dart'; import 'package:didvan/pages/home/news/news_state.dart';
import 'package:didvan/pages/home/news/widgets/news_item.dart'; import 'package:didvan/pages/home/widgets/news_overview.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/widgets/date_picker_button.dart'; import 'package:didvan/widgets/date_picker_button.dart';
import 'package:didvan/widgets/item_title.dart'; import 'package:didvan/widgets/item_title.dart';
@ -56,16 +56,20 @@ class _NewsState extends State<News> {
SliverStateHandler<NewsState>( SliverStateHandler<NewsState>(
onRetry: () => state.getNews(page: state.page), onRetry: () => state.getNews(page: state.page),
state: state, state: state,
builder: (context, state, index) => NewsItem( builder: (context, state, index) {
news: state.news[index], final news = state.news[index];
), return NewsOverview(
news: news,
onMarkChanged: (value) => state.onMarkChanged(news.id, value),
);
},
enableEmptyState: state.news.isEmpty, enableEmptyState: state.news.isEmpty,
emptyState: EmptyResult( emptyState: EmptyResult(
onNewSearch: () => _focusNode.requestFocus(), onNewSearch: () => _focusNode.requestFocus(),
), ),
childCount: state.news.length, childCount: state.news.length,
itemPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), itemPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
placeholder: const _NewsItemPlaceholder(), placeholder: const _NewsOverviewPlaceholder(),
), ),
], ],
); );
@ -131,8 +135,8 @@ class _NewsState extends State<News> {
} }
} }
class _NewsItemPlaceholder extends StatelessWidget { class _NewsOverviewPlaceholder extends StatelessWidget {
const _NewsItemPlaceholder({Key? key}) : super(key: key); const _NewsOverviewPlaceholder({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -49,8 +49,17 @@ class _NewsDetailsState extends State<NewsDetails> {
left: 0, left: 0,
right: 0, right: 0,
child: FloatingNavigationBar( child: FloatingNavigationBar(
news: state.currentNews,
scrollController: _scrollController, scrollController: _scrollController,
comments: state.currentNews.comments,
id: state.currentNews.id,
marked: state.currentNews.marked,
title: state.currentNews.title,
onCommentsChanged: state.onCommentsChanged,
onMarkChanged: (value) => widget.pageData['onMarkChanged'](
state.currentNews.id,
value,
),
isRadar: false,
), ),
), ),
], ],

View File

@ -66,8 +66,8 @@ class NewsDetailsState extends CoreProvier {
bool exists(NewsDetailsData? newsItem) => bool exists(NewsDetailsData? newsItem) =>
news.any((n) => newsItem != null && n != null && n.id == newsItem.id); news.any((n) => newsItem != null && n != null && n.id == newsItem.id);
void onCommentAdded(int id) { void onCommentsChanged(int count) {
news.firstWhere((item) => item!.id == id)!.comments++; news.firstWhere((item) => item!.id == currentNews.id)!.comments = count;
notifyListeners(); notifyListeners();
} }
} }

View File

@ -1,8 +1,8 @@
import 'package:collection/collection.dart';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/news_overview.dart'; import 'package:didvan/models/news_overview.dart';
import 'package:didvan/models/requests/news.dart'; import 'package:didvan/models/requests/news.dart';
import 'package:didvan/providers/core_provider.dart'; import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/providers/user_provider.dart';
import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/network/request_helper.dart';
@ -13,8 +13,7 @@ class NewsState extends CoreProvier {
String? endDate; String? endDate;
int page = 1; int page = 1;
final List<MapEntry> _markQueue = []; final List<NewsOverviewData> news = [];
final List<NewsOverview> news = [];
void init() { void init() {
search = ''; search = '';
@ -58,7 +57,7 @@ class NewsState extends CoreProvier {
if (service.isSuccess) { if (service.isSuccess) {
final newsList = service.result['news']; final newsList = service.result['news'];
for (var i = 0; i < newsList.length; i++) { for (var i = 0; i < newsList.length; i++) {
news.add(NewsOverview.fromJson(newsList[i])); news.add(NewsOverviewData.fromJson(newsList[i]));
} }
appState = AppState.idle; appState = AppState.idle;
return; return;
@ -66,36 +65,10 @@ class NewsState extends CoreProvier {
appState = AppState.failed; appState = AppState.failed;
} }
Future<void> mark(int id) async { Future<void> onMarkChanged(int id, bool value) async {
news.firstWhere((element) => element.id == id).marked = true; news.firstWhere((element) => element.id == id).marked = value;
notifyListeners(); notifyListeners();
_markQueue.add(MapEntry(id, true)); UserProvider.changeNewsMark(id, value);
Future.delayed(const Duration(milliseconds: 500), () async {
final MapEntry? lastChange =
_markQueue.lastWhereOrNull((item) => item.key == id);
if (lastChange == null) return;
if (lastChange.value) {
final service = RequestService(RequestHelper.markNews(id));
await service.post();
_markQueue.removeWhere((element) => element.key == id);
}
});
}
Future<void> unMark(int id) async {
news.firstWhere((element) => element.id == id).marked = false;
notifyListeners();
_markQueue.add(MapEntry(id, false));
Future.delayed(const Duration(milliseconds: 500), () async {
final MapEntry? lastChange =
_markQueue.lastWhereOrNull((item) => item.key == id);
if (lastChange == null) return;
if (!lastChange.value) {
final service = RequestService(RequestHelper.markNews(id));
await service.delete();
_markQueue.removeWhere((element) => element.key == id);
}
});
} }
bool get isFiltering => startDate != null || endDate != null; bool get isFiltering => startDate != null || endDate != null;

View File

@ -9,7 +9,7 @@ import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/pages/home/radar/radar_state.dart'; import 'package:didvan/pages/home/radar/radar_state.dart';
import 'package:didvan/pages/home/radar/widgets/categories_gird.dart'; import 'package:didvan/pages/home/radar/widgets/categories_gird.dart';
import 'package:didvan/pages/home/radar/widgets/categories_list.dart'; import 'package:didvan/pages/home/radar/widgets/categories_list.dart';
import 'package:didvan/pages/home/radar/widgets/radar_item.dart'; import 'package:didvan/pages/home/widgets/radar_overview.dart';
import 'package:didvan/widgets/animated_visibility.dart'; import 'package:didvan/widgets/animated_visibility.dart';
import 'package:didvan/widgets/search_field.dart'; import 'package:didvan/widgets/search_field.dart';
import 'package:didvan/pages/home/widgets/logo_app_bar.dart'; import 'package:didvan/pages/home/widgets/logo_app_bar.dart';
@ -114,7 +114,7 @@ class _RadarState extends State<Radar> {
), ),
), ),
SliverStateHandler<RadarState>( SliverStateHandler<RadarState>(
onRetry: () => state.getRadarOverviews(page: state.page), onRetry: () => state.getRadarOverviewDatas(page: state.page),
state: state, state: state,
itemPadding: const EdgeInsets.only( itemPadding: const EdgeInsets.only(
bottom: 20, bottom: 20,
@ -122,12 +122,21 @@ class _RadarState extends State<Radar> {
right: 16, right: 16,
), ),
enableEmptyState: state.radars.isEmpty, enableEmptyState: state.radars.isEmpty,
emptyState: emptyState: Padding(
EmptyResult(onNewSearch: () => _focusNode.requestFocus()), padding: const EdgeInsets.only(bottom: 120),
placeholder: const _RadarItemPlaceholder(), child:
builder: (context, state, index) => RadarItem( EmptyResult(onNewSearch: () => _focusNode.requestFocus()),
radar: state.radars[index],
), ),
placeholder: const _RadarOverviewPlaceholder(),
builder: (context, state, index) {
final radar = state.radars[index];
return RadarOverview(
radar: radar,
onMarkChanged: (value) => state.changeMark(radar.id, value),
onCommentsChanged: (count) =>
state.onCommentsChanged(radar.id, count),
);
},
childCount: state.radars.length, childCount: state.radars.length,
), ),
if (state.radars.length == 1) if (state.radars.length == 1)
@ -136,20 +145,9 @@ class _RadarState extends State<Radar> {
), ),
], ],
), ),
if (state.appState != AppState.failed) if (state.appState != AppState.failed) const CategoriesRow1(),
CategoriesRow1( if (state.appState != AppState.failed) const CategoriesRow2(),
isColapsed: if (state.appState != AppState.failed) const CategoriesList(),
state.isColapsed || state.searching || state.filtering,
),
if (state.appState != AppState.failed)
CategoriesRow2(
isColapsed:
state.isColapsed || state.searching || state.filtering,
),
if (state.appState != AppState.failed)
CategoriesList(
isColapsed: state.isColapsed && !state.searching,
),
], ],
), ),
); );
@ -163,7 +161,7 @@ class _RadarState extends State<Radar> {
_timer?.cancel(); _timer?.cancel();
_timer = Timer(const Duration(seconds: 1), () { _timer = Timer(const Duration(seconds: 1), () {
state.search = value; state.search = value;
state.getRadarOverviews(page: 1); state.getRadarOverviewDatas(page: 1);
}); });
} }
@ -208,7 +206,7 @@ class _RadarState extends State<Radar> {
dismissTitle: 'حذف فیلتر', dismissTitle: 'حذف فیلتر',
confrimTitle: 'نمایش نتایج', confrimTitle: 'نمایش نتایج',
onDismissed: () => state.resetFilters(false), onDismissed: () => state.resetFilters(false),
onConfirmed: () => state.getRadarOverviews(page: 1), onConfirmed: () => state.getRadarOverviewDatas(page: 1),
content: Column( content: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -276,8 +274,8 @@ class _RadarState extends State<Radar> {
} }
} }
class _RadarItemPlaceholder extends StatelessWidget { class _RadarOverviewPlaceholder extends StatelessWidget {
const _RadarItemPlaceholder({ const _RadarOverviewPlaceholder({
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);

View File

@ -50,7 +50,17 @@ class _RadarDetailsState extends State<RadarDetails> {
left: 0, left: 0,
right: 0, right: 0,
child: FloatingNavigationBar( child: FloatingNavigationBar(
radar: state.currentRadar, comments: state.currentRadar.comments,
id: state.currentRadar.id,
isRadar: true,
marked: state.currentRadar.marked,
title: state.currentRadar.title,
onMarkChanged: (value) => widget.pageData['onMarkChanged'](
state.currentRadar.id,
value,
),
onCommentsChanged: state.onCommentsChanged,
categories: state.currentRadar.categories,
scrollController: _scrollController, scrollController: _scrollController,
), ),
), ),

View File

@ -15,7 +15,13 @@ class RadarDetailsState extends CoreProvier {
int _currentIndex = 0; int _currentIndex = 0;
int get currentIndex => _currentIndex; int get currentIndex => _currentIndex;
RadarDetailsData get currentRadar => radars[_currentIndex]!; RadarDetailsData get currentRadar {
try {
return radars[_currentIndex]!;
} catch (e) {
return radars[_currentIndex + 1]!;
}
}
Future<void> getRadarDetails(int id, {bool? isForward}) async { Future<void> getRadarDetails(int id, {bool? isForward}) async {
if (isForward == null) { if (isForward == null) {
@ -74,8 +80,9 @@ class RadarDetailsState extends CoreProvier {
bool exists(RadarDetailsData? radar) => bool exists(RadarDetailsData? radar) =>
radars.any((r) => radar != null && r != null && r.id == radar.id); radars.any((r) => radar != null && r != null && r.id == radar.id);
void onCommentAdded(int id) { void onCommentsChanged(int count) {
radars.firstWhere((radar) => radar!.id == id)!.comments++; radars.firstWhere((radar) => radar!.id == currentRadar.id)!.comments =
count;
notifyListeners(); notifyListeners();
} }
} }

View File

@ -1,10 +1,10 @@
import 'package:collection/collection.dart';
import 'package:didvan/constants/assets.dart'; import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/requests/radar.dart'; import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/models/view/radar_category.dart'; import 'package:didvan/models/view/radar_category.dart';
import 'package:didvan/models/radar_overview.dart'; import 'package:didvan/models/radar_overview.dart';
import 'package:didvan/providers/core_provider.dart'; import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/providers/user_provider.dart';
import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/network/request_helper.dart';
@ -16,10 +16,9 @@ class RadarState extends CoreProvier {
int page = 1; int page = 1;
bool isScrolled = false; bool isScrolled = false;
bool shouldColapse = false; bool shouldColapse = false;
final List<MapEntry> _markQueue = [];
final List<RadarCategory> selectedCats = []; final List<RadarCategory> selectedCats = [];
List<RadarCategory> categories = []; List<RadarCategory> categories = [];
final List<RadarOverview> radars = []; final List<RadarOverviewData> radars = [];
bool get filtering => bool get filtering =>
selectedCats.length > 1 || startDate != null || endDate != null; selectedCats.length > 1 || startDate != null || endDate != null;
@ -43,7 +42,7 @@ class RadarState extends CoreProvier {
} }
} }
Future<void> getRadarOverviews({ Future<void> getRadarOverviewDatas({
required int page, required int page,
}) async { }) async {
if (this.page == page) { if (this.page == page) {
@ -66,7 +65,7 @@ class RadarState extends CoreProvier {
await service.httpGet(); await service.httpGet();
if (service.isSuccess) { if (service.isSuccess) {
for (var i = 0; i < service.result['radars'].length; i++) { for (var i = 0; i < service.result['radars'].length; i++) {
radars.add(RadarOverview.fromJson(service.result['radars'][i])); radars.add(RadarOverviewData.fromJson(service.result['radars'][i]));
} }
if (searching || filtering || isColapsed || isCategorySelected) { if (searching || filtering || isColapsed || isCategorySelected) {
shouldColapse = true; shouldColapse = true;
@ -78,47 +77,21 @@ class RadarState extends CoreProvier {
appState = AppState.failed; appState = AppState.failed;
} }
Future<void> mark(int id) async { Future<void> changeMark(int id, bool value) async {
radars.firstWhere((element) => element.id == id).marked = true; radars.firstWhere((element) => element.id == id).marked = value;
notifyListeners(); notifyListeners();
_markQueue.add(MapEntry(id, true)); UserProvider.changeRadarMark(id, value);
Future.delayed(const Duration(milliseconds: 500), () async {
final MapEntry? lastChange =
_markQueue.lastWhereOrNull((item) => item.key == id);
if (lastChange == null) return;
if (lastChange.value) {
final service = RequestService(RequestHelper.markRadar(id));
await service.post();
_markQueue.removeWhere((element) => element.key == id);
}
});
} }
Future<void> unMark(int id) async { void onCommentsChanged(int id, int count) {
radars.firstWhere((element) => element.id == id).marked = false; radars.firstWhere((radar) => radar.id == id).comments = count;
notifyListeners();
_markQueue.add(MapEntry(id, false));
Future.delayed(const Duration(milliseconds: 500), () async {
final MapEntry? lastChange =
_markQueue.lastWhereOrNull((item) => item.key == id);
if (lastChange == null) return;
if (!lastChange.value) {
final service = RequestService(RequestHelper.markRadar(id));
await service.delete();
_markQueue.removeWhere((element) => element.key == id);
}
});
}
void onCommentAdded(int id) {
radars.firstWhere((radar) => radar.id == id).comments++;
notifyListeners(); notifyListeners();
} }
void init() { void init() {
resetFilters(true); resetFilters(true);
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
getRadarOverviews(page: 1); getRadarOverviewDatas(page: 1);
}); });
categories = [ categories = [
RadarCategory( RadarCategory(

View File

@ -7,7 +7,7 @@ import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/pages/home/settings/general_settings/settings_state.dart'; import 'package:didvan/pages/home/settings/general_settings/settings_state.dart';
import 'package:didvan/pages/home/settings/widgets/menu_item.dart'; import 'package:didvan/pages/home/widgets/menu_item.dart';
import 'package:didvan/providers/theme_provider.dart'; import 'package:didvan/providers/theme_provider.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/widgets/didvan/card.dart'; import 'package:didvan/widgets/didvan/card.dart';

View File

@ -1,14 +1,17 @@
import 'dart:async'; import 'dart:async';
import 'package:didvan/config/design_config.dart';
import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/pages/home/settings/profile/widgets/profile_photo.dart'; import 'package:didvan/pages/home/settings/profile/widgets/profile_photo.dart';
import 'package:didvan/pages/home/settings/widgets/menu_item.dart'; import 'package:didvan/pages/home/widgets/menu_item.dart';
import 'package:didvan/providers/user_provider.dart'; import 'package:didvan/providers/user_provider.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/widgets/animated_visibility.dart';
import 'package:didvan/widgets/didvan/button.dart'; import 'package:didvan/widgets/didvan/button.dart';
import 'package:didvan/widgets/didvan/card.dart'; import 'package:didvan/widgets/didvan/card.dart';
import 'package:didvan/widgets/didvan/divider.dart'; import 'package:didvan/widgets/didvan/divider.dart';
import 'package:didvan/widgets/didvan/scaffold.dart'; import 'package:didvan/widgets/didvan/scaffold.dart';
import 'package:didvan/widgets/didvan/text.dart';
import 'package:didvan/widgets/didvan/text_field.dart'; import 'package:didvan/widgets/didvan/text_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -26,6 +29,7 @@ class _ProfileState extends State<Profile> {
late String fullName; late String fullName;
String? username; String? username;
String? email; String? email;
bool _usernameIsAvailible = true;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
@ -54,6 +58,7 @@ class _ProfileState extends State<Profile> {
const SizedBox(height: 16), const SizedBox(height: 16),
DidvanCard( DidvanCard(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
DidvanTextField( DidvanTextField(
title: 'نام و نام‌ خانوادگی', title: 'نام و نام‌ خانوادگی',
@ -76,12 +81,15 @@ class _ProfileState extends State<Profile> {
hintText: 'انتخاب نام کاربری (اختیاری)', hintText: 'انتخاب نام کاربری (اختیاری)',
onChanged: _onUsernameChanged, onChanged: _onUsernameChanged,
initialValue: state.user.username, initialValue: state.user.username,
validator: (value) async { ),
final result = await state.checkUsername(value); AnimatedVisibility(
if (result == false) { duration: DesignConfig.lowAnimationDuration,
return 'نام کاربری در دسترس نمی‌باشد'; isVisible: !_usernameIsAvailible,
} child: DidvanText(
}, 'نام کاربری در دسترس نمی‌باشد',
style: Theme.of(context).textTheme.caption,
color: Theme.of(context).colorScheme.error,
),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
DidvanTextField( DidvanTextField(
@ -156,6 +164,7 @@ class _ProfileState extends State<Profile> {
} }
void _onUsernameChanged(String value) { void _onUsernameChanged(String value) {
_usernameIsAvailible = true;
_setButtonState(); _setButtonState();
username = value; username = value;
_timer?.cancel(); _timer?.cancel();
@ -163,7 +172,13 @@ class _ProfileState extends State<Profile> {
return; return;
} }
_timer = Timer(const Duration(seconds: 1), () { _timer = Timer(const Duration(seconds: 1), () {
_formKey.currentState!.validate(); context.read<UserProvider>().checkUsername(value).then((value) {
if (value == false) {
setState(() {
_usernameIsAvailible = false;
});
}
});
}); });
} }
} }

View File

@ -1,5 +1,5 @@
import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/pages/home/settings/widgets/menu_item.dart'; import 'package:didvan/pages/home/widgets/menu_item.dart';
import 'package:didvan/pages/home/widgets/logo_app_bar.dart'; import 'package:didvan/pages/home/widgets/logo_app_bar.dart';
import 'package:didvan/providers/theme_provider.dart'; import 'package:didvan/providers/theme_provider.dart';
import 'package:didvan/providers/user_provider.dart'; import 'package:didvan/providers/user_provider.dart';
@ -11,6 +11,7 @@ import 'package:didvan/widgets/didvan/text.dart';
import 'package:didvan/widgets/item_title.dart'; import 'package:didvan/widgets/item_title.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
class Settings extends StatelessWidget { class Settings extends StatelessWidget {
const Settings({Key? key}) : super(key: key); const Settings({Key? key}) : super(key: key);
@ -86,13 +87,15 @@ class Settings extends StatelessWidget {
MenuItem( MenuItem(
icon: DidvanIcons.didvan_solid, icon: DidvanIcons.didvan_solid,
title: 'معرفی دیدوان', title: 'معرفی دیدوان',
onTap: () => {}, onTap: () => Navigator.of(context).pushNamed(Routes.aboutUs),
), ),
const DidvanDivider(), const DidvanDivider(),
MenuItem( MenuItem(
icon: DidvanIcons.support_regular, icon: DidvanIcons.support_regular,
title: 'پیام به پشتیبانی', title: 'پیام به پشتیبانی',
onTap: () => {}, onTap: () {
launch('mailto:info@didvan.app');
},
), ),
const DidvanDivider(), const DidvanDivider(),
MenuItem( MenuItem(

View File

@ -1,190 +0,0 @@
import 'package:day_night_time_picker/lib/constants.dart';
import 'package:day_night_time_picker/lib/daynight_timepicker.dart';
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/pages/home/settings/general_settings/settings_state.dart';
import 'package:didvan/pages/home/settings/widgets/menu_item.dart';
import 'package:didvan/providers/theme_provider.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/widgets/didvan/card.dart';
import 'package:didvan/widgets/didvan/divider.dart';
import 'package:didvan/widgets/didvan/scaffold.dart';
import 'package:didvan/widgets/didvan/text.dart';
import 'package:didvan/widgets/item_title.dart';
import 'package:didvan/widgets/state_handler.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
class GeneralSettings extends StatelessWidget {
const GeneralSettings({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<GeneralSettingsState>(
builder: (context, state, child) => StateHandler<GeneralSettingsState>(
state: context.read<GeneralSettingsState>(),
builder: (context, state) => DidvanScaffold(
appBarData: AppBarData(hasBack: true, title: 'تنظیمات'),
children: [
DidvanCard(
child: MenuItem(
title: 'زمان دریافت اعلان',
onTap: () => _pickTimeRange(context),
icon: DidvanIcons.notification_regular,
suffix: state.notificationTimeRange[0],
),
),
const ItemTitle(
title: 'انتخاب قلم',
icon: DidvanIcons.font_solid,
),
DidvanCard(
child: Column(
children: [
MenuItem(
suffix: 'نیاز به پیاده‌سازی',
title: 'فونت برنامه',
onTap: () {},
),
const DidvanDivider(),
MenuItem(
suffix: 'نیاز به پیاده‌سازی',
title: 'اندازه متن',
onTap: () {},
),
],
),
),
const ItemTitle(
title: 'ظاهر برنامه',
icon: DidvanIcons.theme_solid,
),
DidvanCard(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_themeItem(context, state, 'light'),
_themeItem(context, state, 'dark'),
],
),
),
],
),
),
);
}
Future<void> _pickTimeRange(BuildContext context) async {
ActionSheetUtils.showBottomSheet(
data: ActionSheetData(
content: Row(
children: [
const SizedBox(width: 8),
Expanded(child: _timeFieldBuilder(context, 0)),
const SizedBox(width: 8),
const DidvanText('-'),
const SizedBox(width: 8),
Expanded(child: _timeFieldBuilder(context, 1)),
const SizedBox(width: 8),
],
),
title: 'زمان دریافت اعلان',
titleIcon: DidvanIcons.notification_regular,
),
);
}
Widget _timeFieldBuilder(BuildContext context, int index) {
final GeneralSettingsState state = context.read<GeneralSettingsState>();
return ChangeNotifierProvider.value(
value: state,
child: StatefulBuilder(
builder: (context, setState) => GestureDetector(
onTap: () async {
await _openTimePicker(context, index);
setState(() {});
},
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.splash,
borderRadius: DesignConfig.mediumBorderRadius,
border: Border.all(
color: Theme.of(context).colorScheme.border,
),
),
child: DidvanText(state.notificationTimeRange[index]),
),
),
),
);
}
Future<void> _openTimePicker(BuildContext context, int index) async {
final GeneralSettingsState state = context.read<GeneralSettingsState>();
await Navigator.of(context).push(
showPicker(
okText: 'تایید',
cancelText: 'بازگشت',
accentColor: Theme.of(context).colorScheme.primary,
okStyle: Theme.of(context).textTheme.bodyText2!,
cancelStyle: Theme.of(context).textTheme.bodyText2!,
unselectedColor: Theme.of(context).colorScheme.text,
blurredBackground: true,
hourLabel: 'ساعت',
minuteLabel: 'دقیقه',
is24HrFormat: true,
iosStylePicker: true,
minuteInterval: MinuteInterval.FIFTEEN,
context: context,
value: const TimeOfDay(hour: 0, minute: 0),
themeData: Theme.of(context),
onChange: (time) {
state.notificationTimeRange = state.notificationTimeRange
..replaceRange(
index,
index + 1,
['${time.hour}:${time.minute}'],
);
},
),
);
}
Widget _themeItem(
BuildContext context, GeneralSettingsState state, String brightness) {
final bool isDarkTheme = brightness == 'dark';
return GestureDetector(
onTap: () {
state.brightness = brightness;
if (isDarkTheme && DesignConfig.isDark) {
return;
} else if (!isDarkTheme && !DesignConfig.isDark) {
return;
} else {
if (isDarkTheme) {
context.read<ThemeProvider>().themeMode = ThemeMode.dark;
} else {
context.read<ThemeProvider>().themeMode = ThemeMode.light;
}
DesignConfig.updateSystemUiOverlayStyle();
}
},
child: Column(
children: [
SvgPicture.asset(isDarkTheme ? Assets.darkTheme : Assets.lightTheme),
const SizedBox(height: 8),
DidvanText(
isDarkTheme ? 'تیره' : 'روشن',
),
],
),
);
}
}

View File

@ -4,21 +4,29 @@ import 'package:didvan/widgets/didvan/text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MenuItem extends StatelessWidget { class MenuItem extends StatelessWidget {
final String title; final String? title;
final Widget? titleWidget;
final IconData? icon; final IconData? icon;
final double iconSize;
final String? suffix; final String? suffix;
final VoidCallback onTap; final VoidCallback onTap;
final Widget? trailing; final Widget? trailing;
final Color? color; final Color? color;
const MenuItem({ MenuItem({
Key? key, Key? key,
required this.title, required this.onTap,
this.title,
this.icon, this.icon,
this.suffix, this.suffix,
required this.onTap,
this.color, this.color,
this.trailing, this.trailing,
}) : super(key: key); this.titleWidget,
this.iconSize = 18,
}) : super(key: key) {
if (title == null && titleWidget == null) {
throw Exception;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -31,14 +39,16 @@ class MenuItem extends StatelessWidget {
if (icon != null) if (icon != null)
Icon( Icon(
icon, icon,
size: 18, size: iconSize,
color: color ?? Theme.of(context).colorScheme.title, color: color ?? Theme.of(context).colorScheme.title,
), ),
if (icon != null) const SizedBox(width: 4), if (icon != null) const SizedBox(width: 4),
DidvanText( if (titleWidget != null) titleWidget!,
title, if (titleWidget == null)
color: color ?? Theme.of(context).colorScheme.title, DidvanText(
), title!,
color: color ?? Theme.of(context).colorScheme.title,
),
const Spacer(), const Spacer(),
if (suffix != null) if (suffix != null)
DidvanText( DidvanText(

View File

@ -11,9 +11,12 @@ import 'package:didvan/widgets/skeleton_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class NewsItem extends StatelessWidget { class NewsOverview extends StatelessWidget {
final NewsOverview news; final NewsOverviewData news;
const NewsItem({Key? key, required this.news}) : super(key: key); final void Function(bool value) onMarkChanged;
const NewsOverview(
{Key? key, required this.news, required this.onMarkChanged})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -77,8 +80,8 @@ class NewsItem extends StatelessWidget {
), ),
BookmarkButton( BookmarkButton(
value: news.marked, value: news.marked,
onMark: () => state.mark(news.id), onMarkChanged: onMarkChanged,
onUnmark: () => state.unMark(news.id), bigGestureSize: true,
), ),
], ],
), ),

View File

@ -2,7 +2,6 @@ import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/radar_overview.dart'; import 'package:didvan/models/radar_overview.dart';
import 'package:didvan/models/requests/radar.dart'; import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/pages/home/radar/radar_state.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/date_time.dart'; import 'package:didvan/utils/date_time.dart';
import 'package:didvan/widgets/bookmark_button.dart'; import 'package:didvan/widgets/bookmark_button.dart';
@ -12,28 +11,30 @@ import 'package:didvan/widgets/didvan/icon_button.dart';
import 'package:didvan/widgets/didvan/text.dart'; import 'package:didvan/widgets/didvan/text.dart';
import 'package:didvan/widgets/skeleton_image.dart'; import 'package:didvan/widgets/skeleton_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class RadarItem extends StatelessWidget { class RadarOverview extends StatelessWidget {
final RadarOverview radar; final RadarOverviewData radar;
const RadarItem({Key? key, required this.radar}) : super(key: key); final void Function(int count) onCommentsChanged;
final void Function(bool value) onMarkChanged;
final RadarRequestArgs? radarRequestArgs;
const RadarOverview({
Key? key,
required this.radar,
required this.onCommentsChanged,
required this.onMarkChanged,
this.radarRequestArgs,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final state = context.read<RadarState>();
return DidvanCard( return DidvanCard(
onTap: () => Navigator.of(context).pushNamed( onTap: () => Navigator.of(context).pushNamed(
Routes.radarDetails, Routes.radarDetails,
arguments: { arguments: {
'state': state, 'onMarkChanged': onMarkChanged,
'onCommentsChanged': onCommentsChanged,
'id': radar.id, 'id': radar.id,
'args': RadarRequestArgs( 'args': radarRequestArgs,
page: state.page,
categories: state.selectedCats.map((e) => e.id).toList(),
endDate: state.endDate,
search: state.search,
startDate: state.startDate,
)
}, },
), ),
child: Column( child: Column(
@ -99,8 +100,7 @@ class RadarItem extends StatelessWidget {
children: [ children: [
BookmarkButton( BookmarkButton(
value: radar.marked, value: radar.marked,
onMark: () => state.mark(radar.id), onMarkChanged: onMarkChanged,
onUnmark: () => state.unMark(radar.id),
), ),
const Spacer(), const Spacer(),
if (radar.comments != 0) DidvanText(radar.comments.toString()), if (radar.comments != 0) DidvanText(radar.comments.toString()),
@ -114,7 +114,7 @@ class RadarItem extends StatelessWidget {
'isRadar': true, 'isRadar': true,
'title': radar.title, 'title': radar.title,
'id': radar.id, 'id': radar.id,
'onCommentAdded': () => state.onCommentAdded(radar.id) 'onCommentsChanged': onCommentsChanged
}, },
), ),
), ),