news and news details

This commit is contained in:
MohammadTaha Basiri 2022-01-26 00:18:30 +03:30
parent 74b0926612
commit 99141f2050
4 changed files with 174 additions and 82 deletions

View File

@ -1,76 +1,70 @@
import 'package:didvan/pages/home/news/news_details/news_details_state.dart';
import 'package:didvan/widgets/didvan/page_view.dart'; import 'package:didvan/widgets/didvan/page_view.dart';
import 'package:didvan/widgets/didvan/text.dart';
import 'package:didvan/widgets/floating_navigation_bar.dart'; import 'package:didvan/widgets/floating_navigation_bar.dart';
import 'package:didvan/widgets/skeletun_image.dart'; import 'package:didvan/widgets/state_handlers/state_handler.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class NewsDetails extends StatelessWidget { class NewsDetails extends StatefulWidget {
const NewsDetails({Key? key}) : super(key: key); final Map<String, dynamic> pageData;
const NewsDetails({Key? key, required this.pageData}) : super(key: key);
@override
State<NewsDetails> createState() => _NewsDetailsState();
}
class _NewsDetailsState extends State<NewsDetails> {
final ScrollController _scrollController = ScrollController();
@override
void initState() {
final state = context.read<NewsDetailsState>();
state.args = widget.pageData['args'];
Future.delayed(Duration.zero, () {
state.getNewsDetails(widget.pageData['id']);
});
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: Stack( body: Consumer<NewsDetailsState>(
builder: (context, state, child) => StateHandler<NewsDetailsState>(
onRetry: () => state.getNewsDetails(state.currentNews.id),
state: state,
builder: (context, state) => Stack(
children: [ children: [
if (state.news.isNotEmpty)
DidvanPageView( DidvanPageView(
pages: [ isRadar: false,
Column( initialIndex: state.initialIndex,
crossAxisAlignment: CrossAxisAlignment.start, onPageChanged: _onPageChnaged,
children: [ scrollController: _scrollController,
const SkeletonImage( items: state.news,
imageUrl: 'https://wallpapercave.com/wp/wp9373116.jpg',
width: double.infinity,
height: 200,
), ),
const SizedBox(height: 20), if (state.news.isNotEmpty)
for (var i = 0; i < 10; i++) Positioned(
Padding( bottom: 0,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Builder(
builder: (context) {
switch (i) {
case 0:
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DidvanText(
'تحلیل شکاف فناوری صنعت فولاد ایران',
style:
Theme.of(context).textTheme.bodyText1,
),
const SizedBox(height: 8),
const DidvanText(
'پایگاه خبری معدن نیوز - 2 ساعت پیش',
),
const SizedBox(height: 8),
],
);
default:
return const Padding(
padding: EdgeInsets.only(bottom: 8),
child: DidvanText(
'این سایت امروز (شنبه) تیم منتخب قاره آسیا در سال ۲۰۲۱ میلادی را معرفی کرد که از ایران، سردار آزمون و محمد حسین کنعانی‌زادگان در ترکیب اصلی و مهدی طارمی و سیدمجید حسینی در جمع بازیکنان ذخیره دیده می‌شوند.',
),
);
}
},
),
),
const SizedBox(height: 20),
],
),
],
),
const Positioned(
left: 0, left: 0,
right: 0, right: 0,
bottom: 0,
child: FloatingNavigationBar( child: FloatingNavigationBar(
isRadar: false, news: state.currentNews,
scrollController: _scrollController,
), ),
), ),
], ],
), ),
),
),
);
}
void _onPageChnaged(int index) {
final state = context.read<NewsDetailsState>();
state.getNewsDetails(
state.news[index]!.id,
isForward: state.currentIndex < index,
); );
} }
} }

View File

@ -1,3 +1,73 @@
import 'package:didvan/providers/core_provider.dart'; import 'dart:math';
class NewsDetailsState extends CoreProvier {} import 'package:didvan/models/enums.dart';
import 'package:didvan/models/news_details_data.dart';
import 'package:didvan/models/requests/news.dart';
import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';
class NewsDetailsState extends CoreProvier {
final List<NewsDetailsData?> news = [];
late final int initialIndex;
late final NewsRequestArgs args;
int _currentIndex = 0;
int get currentIndex => _currentIndex;
NewsDetailsData get currentNews => news[_currentIndex]!;
Future<void> getNewsDetails(int id, {bool? isForward}) async {
if (isForward == null) {
appState = AppState.busy;
}
final service = RequestService(RequestHelper.newsDetails(id, args));
await service.httpGet();
if (service.isSuccess) {
final result = service.result;
NewsDetailsData? prevNews;
if (result['prevNews'].isNotEmpty) {
prevNews = NewsDetailsData.fromJson(result['prevNews']);
}
final newsItem = NewsDetailsData.fromJson(result['news']);
NewsDetailsData? nextNews;
if (result['nextNews'].isNotEmpty) {
nextNews = NewsDetailsData.fromJson(result['nextNews']);
}
if (isForward == null) {
news.addAll(List.generate(max(newsItem.order - 2, 0), (index) => null));
if (prevNews != null) {
news.add(prevNews);
}
news.add(newsItem);
if (nextNews != null) {
news.add(nextNews);
}
_currentIndex = initialIndex = newsItem.order - 1;
} else if (isForward) {
if (!exists(nextNews) && nextNews != null) {
news.add(nextNews);
}
_currentIndex++;
} else if (!isForward) {
if (!exists(prevNews) && prevNews != null) {
news[_currentIndex - 2] = prevNews;
}
_currentIndex--;
}
appState = AppState.idle;
return;
}
if (isForward == null) {
appState = AppState.failed;
}
}
bool exists(NewsDetailsData? newsItem) =>
news.any((n) => newsItem != null && n != null && n.id == newsItem.id);
void onCommentAdded(int id) {
news.firstWhere((item) => item!.id == id)!.comments++;
notifyListeners();
}
}

View File

@ -1,20 +1,31 @@
import 'package:collection/collection.dart'; 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/providers/core_provider.dart'; import 'package:didvan/providers/core_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';
class NewsState extends CoreProvier { class NewsState extends CoreProvier {
bool isFiltering = false;
String search = ''; String search = '';
String lastSearch = ''; String lastSearch = '';
String? startDate; String? startDate;
String? endDate; String? endDate;
int page = 1;
final List<MapEntry> _markQueue = []; final List<MapEntry> _markQueue = [];
final List<NewsOverview> news = []; final List<NewsOverview> news = [];
void init() {
search = '';
lastSearch = '';
startDate = null;
endDate = null;
Future.delayed(Duration.zero, () {
getNews(page: 1);
});
}
void resetFilters() { void resetFilters() {
startDate = null; startDate = null;
endDate = null; endDate = null;
@ -24,22 +35,24 @@ class NewsState extends CoreProvier {
Future<void> getNews({ Future<void> getNews({
required int page, required int page,
}) async { }) async {
if (search != '' || filterApplied) { if (this.page == page) {
news.clear();
}
this.page = page;
if (search != '') {
lastSearch = search; lastSearch = search;
isFiltering = true;
} else {
isFiltering = false;
} }
lastSearch = search; lastSearch = search;
appState = AppState.busy; appState = AppState.busy;
news.clear();
final service = RequestService( final service = RequestService(
RequestHelper.newsOverviews( RequestHelper.newsOverviews(
args: NewsRequestArgs(
page: 1, page: 1,
startDate: startDate?.split(' ').first, startDate: startDate?.split(' ').first,
endDate: endDate?.split(' ').first, endDate: endDate?.split(' ').first,
search: search == '' ? null : search, search: search == '' ? null : search,
), ),
),
); );
await service.httpGet(); await service.httpGet();
if (service.isSuccess) { if (service.isSuccess) {
@ -53,7 +66,7 @@ class NewsState extends CoreProvier {
appState = AppState.failed; appState = AppState.failed;
} }
Future<void> markNews(int id) async { Future<void> mark(int id) async {
news.firstWhere((element) => element.id == id).marked = true; news.firstWhere((element) => element.id == id).marked = true;
notifyListeners(); notifyListeners();
_markQueue.add(MapEntry(id, true)); _markQueue.add(MapEntry(id, true));
@ -69,7 +82,7 @@ class NewsState extends CoreProvier {
}); });
} }
Future<void> unMarkNews(int id) async { Future<void> unMark(int id) async {
news.firstWhere((element) => element.id == id).marked = false; news.firstWhere((element) => element.id == id).marked = false;
notifyListeners(); notifyListeners();
_markQueue.add(MapEntry(id, false)); _markQueue.add(MapEntry(id, false));
@ -85,5 +98,5 @@ class NewsState extends CoreProvier {
}); });
} }
bool get filterApplied => startDate != null || endDate != null; bool get isFiltering => startDate != null || endDate != null;
} }

View File

@ -1,13 +1,14 @@
import 'package:didvan/models/news_overview.dart'; import 'package:didvan/models/news_overview.dart';
import 'package:didvan/models/requests/news.dart';
import 'package:didvan/pages/home/news/news_state.dart'; import 'package:didvan/pages/home/news/news_state.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/date_time.dart';
import 'package:didvan/widgets/bookmark_button.dart'; import 'package:didvan/widgets/bookmark_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/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:persian_number_utility/persian_number_utility.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class NewsItem extends StatelessWidget { class NewsItem extends StatelessWidget {
@ -23,6 +24,12 @@ class NewsItem extends StatelessWidget {
arguments: { arguments: {
'state': state, 'state': state,
'id': news.id, 'id': news.id,
'args': NewsRequestArgs(
page: state.page,
endDate: state.endDate,
search: state.search,
startDate: state.startDate,
)
}, },
), ),
child: Column( child: Column(
@ -55,15 +62,23 @@ class NewsItem extends StatelessWidget {
const DidvanDivider(verticalPadding: 8), const DidvanDivider(verticalPadding: 8),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [ children: [
DidvanText( DidvanText(
'${news.reference} | ${DateTime.parse(news.createdAt).toPersianDateStr()}', news.reference,
style: Theme.of(context).textTheme.overline, style: Theme.of(context).textTheme.caption,
),
DidvanText(
' - ' + DateTimeUtils.momentGenerator(news.createdAt),
style: Theme.of(context).textTheme.caption,
),
],
), ),
BookmarkButton( BookmarkButton(
value: news.marked, value: news.marked,
onMark: () => state.markNews(news.id), onMark: () => state.mark(news.id),
onUnmark: () => state.unMarkNews(news.id), onUnmark: () => state.unMark(news.id),
), ),
], ],
), ),