elCaribe app - customization and branding
This commit is contained in:
318
news-app/lib/ui/screens/NewsDetail/Widgets/CommentView.dart
Normal file
318
news-app/lib/ui/screens/NewsDetail/Widgets/CommentView.dart
Normal file
@@ -0,0 +1,318 @@
|
||||
import 'package:news/data/repositories/NewsComment/LikeAndDislikeComment/likeAndDislikeCommRepository.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/delAndReportCom.dart';
|
||||
import 'package:news/cubits/NewsComment/likeAndDislikeCommCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/setCommentCubit.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/data/models/CommentModel.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/commentNewsCubit.dart';
|
||||
import 'package:news/utils/ErrorMessageKeys.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CommentView extends StatefulWidget {
|
||||
final String newsId;
|
||||
final Function updateComFun;
|
||||
final Function updateIsReplyFun;
|
||||
|
||||
const CommentView({super.key, required this.newsId, required this.updateComFun, required this.updateIsReplyFun});
|
||||
|
||||
@override
|
||||
CommentViewState createState() => CommentViewState();
|
||||
}
|
||||
|
||||
class CommentViewState extends State<CommentView> {
|
||||
final TextEditingController _commentC = TextEditingController();
|
||||
TextEditingController reportC = TextEditingController();
|
||||
bool comBtnEnabled = false, isReply = false, isSending = false;
|
||||
int? replyComIndex;
|
||||
|
||||
Widget commentsLengthView(int length) {
|
||||
return Row(children: [
|
||||
if (length > 0)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Row(children: [
|
||||
CustomTextLabel(
|
||||
text: 'allLbl',
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
CustomTextLabel(
|
||||
text: " $length ",
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
CustomTextLabel(
|
||||
text: 'comsLbl',
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
])),
|
||||
const Spacer(),
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: InkWell(
|
||||
child: const Icon(Icons.close_rounded),
|
||||
onTap: () {
|
||||
widget.updateComFun(false);
|
||||
},
|
||||
))
|
||||
]);
|
||||
}
|
||||
|
||||
Widget profileWithSendCom() {
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 5.0),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: BlocBuilder<AuthCubit, AuthState>(builder: (context, state) {
|
||||
if (state is Authenticated && context.read<AuthCubit>().getProfile() != "") {
|
||||
return CircleAvatar(backgroundImage: NetworkImage(context.read<AuthCubit>().getProfile()));
|
||||
} else {
|
||||
return UiUtils.setFixedSizeboxForProfilePicture(childWidget: const Icon(Icons.account_circle, size: 35));
|
||||
}
|
||||
})),
|
||||
BlocListener<SetCommentCubit, SetCommentState>(
|
||||
bloc: context.read<SetCommentCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is SetCommentFetchSuccess) {
|
||||
context.read<CommentNewsCubit>().commentUpdateList(state.setComment, state.total);
|
||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||
if (!currentFocus.hasPrimaryFocus) {
|
||||
currentFocus.unfocus();
|
||||
}
|
||||
_commentC.clear();
|
||||
isSending = false;
|
||||
setState(() {});
|
||||
}
|
||||
if (state is SetCommentFetchInProgress) {
|
||||
setState(() => isSending = true);
|
||||
}
|
||||
},
|
||||
child: Expanded(
|
||||
flex: 7,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 18.0),
|
||||
child: TextField(
|
||||
controller: _commentC,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
onChanged: (String val) {
|
||||
(_commentC.text.trim().isNotEmpty) ? setState(() => comBtnEnabled = true) : setState(() => comBtnEnabled = false);
|
||||
},
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(top: 10.0, bottom: 2.0),
|
||||
isDense: true,
|
||||
suffixIconConstraints: BoxConstraints(maxHeight: (!isSending) ? 35 : 0, maxWidth: (!isSending) ? 30 : 0),
|
||||
enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.5), width: 1.5)),
|
||||
hintText: UiUtils.getTranslatedLabel(context, 'shareThoghtLbl'),
|
||||
hintStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
suffixIcon: (_commentC.text.trim().isNotEmpty)
|
||||
? (!isSending)
|
||||
? IconButton(
|
||||
icon: Icon(Icons.send, color: comBtnEnabled ? UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8) : Colors.transparent, size: 20.0),
|
||||
onPressed: () async {
|
||||
(context.read<AuthCubit>().getUserId() != "0")
|
||||
? context.read<SetCommentCubit>().setComment(parentId: "0", newsId: widget.newsId, message: _commentC.text)
|
||||
: UiUtils.loginRequired(context);
|
||||
})
|
||||
: SizedBox(height: 12, width: 12, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: SizedBox.shrink())))))
|
||||
]));
|
||||
}
|
||||
|
||||
_buildCommContainer({required CommentModel model, required int index, required int totalCurrentComm, required bool hasMoreCommFetchError, required bool hasMore}) {
|
||||
model = model;
|
||||
if (index == totalCurrentComm - 1 && index <= 0) {
|
||||
//check if hasMore
|
||||
if (hasMore) {
|
||||
if (hasMoreCommFetchError) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return Center(child: Padding(padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.0), child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Builder(builder: (context) {
|
||||
return Row(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||
(model.profile != null && model.profile != "")
|
||||
? UiUtils.setFixedSizeboxForProfilePicture(
|
||||
childWidget: CircleAvatar(backgroundImage: (model.profile != null) ? NetworkImage(model.profile!) : NetworkImage(const Icon(Icons.account_circle, size: 35) as String), radius: 32))
|
||||
: UiUtils.setFixedSizeboxForProfilePicture(childWidget: const Icon(Icons.account_circle, size: 35)),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 15.0),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Row(children: [
|
||||
CustomTextLabel(
|
||||
text: model.name!, textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 13)),
|
||||
Padding(padding: const EdgeInsetsDirectional.only(start: 10.0), child: Icon(Icons.circle, size: 4.0, color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7))),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 10.0),
|
||||
child: CustomTextLabel(
|
||||
text: UiUtils.convertToAgo(context, DateTime.parse(model.date!), 1)!,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 10),
|
||||
))
|
||||
]),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: CustomTextLabel(
|
||||
text: model.message!, textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.normal))),
|
||||
BlocBuilder<LikeAndDislikeCommCubit, LikeAndDislikeCommState>(builder: (context, state) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: const Icon(Icons.thumb_up_off_alt_rounded),
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
context
|
||||
.read<LikeAndDislikeCommCubit>()
|
||||
.setLikeAndDislikeComm(langId: context.read<AppLocalizationCubit>().state.id, commId: model.id!, status: (model.like == "1") ? "0" : "1", fromLike: true);
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
}),
|
||||
model.totalLikes! != "0"
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 4.0),
|
||||
child: CustomTextLabel(text: model.totalLikes!, textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)))
|
||||
: const SizedBox(width: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 35),
|
||||
child: InkWell(
|
||||
child: const Icon(Icons.thumb_down_alt_rounded),
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
context
|
||||
.read<LikeAndDislikeCommCubit>()
|
||||
.setLikeAndDislikeComm(langId: context.read<AppLocalizationCubit>().state.id, commId: model.id!, status: (model.dislike == "1") ? "0" : "2", fromLike: false);
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
)),
|
||||
model.totalDislikes! != "0"
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 4.0),
|
||||
child:
|
||||
CustomTextLabel(text: model.totalDislikes!, textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)))
|
||||
: const SizedBox(width: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 35),
|
||||
child: InkWell(
|
||||
child: const Icon(Icons.quickreply_rounded),
|
||||
onTap: () {
|
||||
widget.updateIsReplyFun(true, index);
|
||||
setState(() {
|
||||
isReply = true;
|
||||
replyComIndex = index;
|
||||
});
|
||||
},
|
||||
)),
|
||||
model.replyComList!.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 5.0),
|
||||
child: CustomTextLabel(
|
||||
text: model.replyComList!.length.toString(),
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)))
|
||||
: const SizedBox.shrink(),
|
||||
const Spacer(),
|
||||
if (context.read<AuthCubit>().getUserId() != "0")
|
||||
InkWell(
|
||||
child: Icon(Icons.more_vert_outlined, color: UiUtils.getColorScheme(context).primaryContainer, size: 17),
|
||||
onTap: () => delAndReportCom(index: index, newsId: widget.newsId, context: context, model: model, reportC: reportC, setState: setState))
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Row(children: [
|
||||
CustomTextLabel(
|
||||
text: model.replyComList!.isNotEmpty ? "${model.replyComList!.length} " : "",
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).primaryColor, fontSize: 12, fontWeight: FontWeight.w600)),
|
||||
CustomTextLabel(
|
||||
text: model.replyComList!.isNotEmpty ? ((model.replyComList!.length == 1) ? 'replyLbl' : 'repliesLbl') : "",
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).primaryColor, fontSize: 12, fontWeight: FontWeight.w600))
|
||||
])),
|
||||
onTap: () {
|
||||
widget.updateIsReplyFun(true, index);
|
||||
setState(() {
|
||||
isReply = true;
|
||||
replyComIndex = index;
|
||||
});
|
||||
}))
|
||||
]))),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
Widget allComListView(CommentNewsFetchSuccess state) {
|
||||
return BlocListener<LikeAndDislikeCommCubit, LikeAndDislikeCommState>(
|
||||
listener: (context, likeDislikeState) {
|
||||
if (likeDislikeState is LikeAndDislikeCommSuccess) {
|
||||
final defaultIndex = state.commentNews.indexWhere((element) => element.id == likeDislikeState.comment.id);
|
||||
if (defaultIndex != -1) {
|
||||
state.commentNews[defaultIndex] = likeDislikeState.comment;
|
||||
context.read<CommentNewsCubit>().emitSuccessState(state.commentNews);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (BuildContext context, int index) => Divider(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.5)),
|
||||
shrinkWrap: true,
|
||||
primary: false,
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: state.commentNews.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildCommContainer(
|
||||
model: state.commentNews[index],
|
||||
hasMore: state.hasMore,
|
||||
hasMoreCommFetchError: (state).hasMoreFetchError,
|
||||
index: index,
|
||||
totalCurrentComm: (state.commentNews[index].replyComList!.length + state.commentNews.length),
|
||||
);
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
Widget commentView() {
|
||||
return BlocBuilder<CommentNewsCubit, CommentNewsState>(builder: (context, state) {
|
||||
if (state is CommentNewsFetchInProgress || state is CommentNewsInitial) {
|
||||
return Center(child: UiUtils.showCircularProgress(true, UiUtils.getColorScheme(context).primaryContainer));
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 10.0, bottom: 10.0),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
if (state is CommentNewsFetchSuccess) commentsLengthView((state).commentNews.length),
|
||||
if (state is! CommentNewsFetchSuccess)
|
||||
Row(children: [const Spacer(), Align(alignment: Alignment.topRight, child: InkWell(child: const Icon(Icons.close_rounded), onTap: () => widget.updateComFun(false)))]),
|
||||
if ((state is CommentNewsFetchFailure && !state.errorMessage.contains(ErrorMessageKeys.noInternet) || state is CommentNewsFetchSuccess)) profileWithSendCom(),
|
||||
if (state is CommentNewsFetchFailure)
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2,
|
||||
child: Center(
|
||||
child: CustomTextLabel(
|
||||
text: (state.errorMessage.contains(ErrorMessageKeys.noInternet))
|
||||
? UiUtils.getTranslatedLabel(context, 'internetmsg')
|
||||
: (state.errorMessage == "No Data Found")
|
||||
? UiUtils.getTranslatedLabel(context, 'noComments')
|
||||
: state.errorMessage,
|
||||
textAlign: TextAlign.center))),
|
||||
if (state is CommentNewsFetchSuccess) allComListView(state)
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(create: (context) => LikeAndDislikeCommCubit(LikeAndDislikeCommRepository()), child: commentView());
|
||||
}
|
||||
}
|
||||
98
news-app/lib/ui/screens/NewsDetail/Widgets/ImageView.dart
Normal file
98
news-app/lib/ui/screens/NewsDetail/Widgets/ImageView.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
import 'package:news/ui/widgets/networkImage.dart';
|
||||
import '../../../../app/routes.dart';
|
||||
import '../../../../data/models/BreakingNewsModel.dart';
|
||||
import '../../../../data/models/NewsModel.dart';
|
||||
|
||||
class ImageView extends StatefulWidget {
|
||||
final NewsModel? model;
|
||||
final BreakingNewsModel? breakModel;
|
||||
final bool isFromBreak;
|
||||
|
||||
const ImageView({super.key, this.model, this.breakModel, required this.isFromBreak});
|
||||
|
||||
@override
|
||||
ImageViewState createState() => ImageViewState();
|
||||
}
|
||||
|
||||
class ImageViewState extends State<ImageView> {
|
||||
List<String> allImage = [];
|
||||
int _curSlider = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
allImage.clear();
|
||||
if (!widget.isFromBreak) {
|
||||
allImage.add(widget.model!.image!);
|
||||
if (widget.model!.imageDataList!.isNotEmpty) {
|
||||
for (int i = 0; i < widget.model!.imageDataList!.length; i++) {
|
||||
allImage.add(widget.model!.imageDataList![i].otherImage!);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allImage.add(widget.breakModel!.image!);
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Widget imageView() {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.40,
|
||||
width: double.maxFinite,
|
||||
child: !widget.isFromBreak
|
||||
? PageView.builder(
|
||||
itemCount: allImage.length,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
_curSlider = index;
|
||||
});
|
||||
},
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InkWell(
|
||||
child: CustomNetworkImage(networkImageUrl: allImage[index], width: double.infinity, height: MediaQuery.of(context).size.height * 0.42, isVideo: false, fit: BoxFit.cover),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(Routes.imagePreview, arguments: {"index": index, "imgList": allImage});
|
||||
},
|
||||
);
|
||||
})
|
||||
: CustomNetworkImage(networkImageUrl: widget.breakModel!.image!, width: double.infinity, height: MediaQuery.of(context).size.height * 0.42, isVideo: false, fit: BoxFit.cover));
|
||||
}
|
||||
|
||||
List<T> map<T>(List list, Function handler) {
|
||||
List<T> result = [];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
result.add(handler(i, list[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Widget imageSliderDot() {
|
||||
if (!widget.isFromBreak && allImage.length > 1) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2.6 - 32),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: map<Widget>(allImage, (index, url) {
|
||||
return Container(
|
||||
width: _curSlider == index ? 10.0 : 8.0,
|
||||
height: _curSlider == index ? 10.0 : 8.0,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 1.0),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: (_curSlider == index) ? const [BoxShadow(color: Colors.grey, spreadRadius: 0.0, blurRadius: 2.0)] : [],
|
||||
color: _curSlider == index ? secondaryColor : secondaryColor.withOpacity((0.5))));
|
||||
}))));
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(children: [imageView(), imageSliderDot()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
|
||||
const AdRequest request = AdRequest(
|
||||
//static
|
||||
keywords: <String>['foo', 'bar'],
|
||||
contentUrl: 'http://foo.com/bar.html',
|
||||
nonPersonalizedAds: true,
|
||||
);
|
||||
int maxFailedLoadAttempts = 3;
|
||||
InterstitialAd? _interstitialAd;
|
||||
int _numInterstitialLoadAttempts = 0;
|
||||
|
||||
void createGoogleInterstitialAd(BuildContext context) {
|
||||
if (context.read<AppConfigurationCubit>().interstitialId() != "") {
|
||||
InterstitialAd.load(
|
||||
adUnitId: context.read<AppConfigurationCubit>().interstitialId()!,
|
||||
request: request,
|
||||
adLoadCallback: InterstitialAdLoadCallback(
|
||||
onAdLoaded: (InterstitialAd ad) {
|
||||
_interstitialAd = ad;
|
||||
_numInterstitialLoadAttempts = 0;
|
||||
_interstitialAd!.setImmersiveMode(true);
|
||||
},
|
||||
onAdFailedToLoad: (LoadAdError error) {
|
||||
_numInterstitialLoadAttempts += 1;
|
||||
_interstitialAd = null;
|
||||
if (_numInterstitialLoadAttempts <= maxFailedLoadAttempts) {
|
||||
createGoogleInterstitialAd(context);
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void showGoogleInterstitialAd(BuildContext context) {
|
||||
if (_interstitialAd == null) {
|
||||
return;
|
||||
}
|
||||
_interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
|
||||
onAdShowedFullScreenContent: (InterstitialAd ad) => debugPrint('ad onAdShowedFullScreenContent.'),
|
||||
onAdDismissedFullScreenContent: (InterstitialAd ad) {
|
||||
ad.dispose();
|
||||
createGoogleInterstitialAd(context);
|
||||
},
|
||||
onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
|
||||
ad.dispose();
|
||||
createGoogleInterstitialAd(context);
|
||||
},
|
||||
);
|
||||
_interstitialAd!.show();
|
||||
_interstitialAd = null;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
||||
|
||||
void loadUnityInterAd(String placementId) {
|
||||
UnityAds.load(placementId: placementId, onComplete: (placementId) {}, onFailed: (placementId, error, message) {});
|
||||
}
|
||||
|
||||
void showUnityInterstitialAds(String placementId) {
|
||||
UnityAds.showVideoAd(
|
||||
placementId: placementId,
|
||||
onComplete: (placementId) {
|
||||
loadUnityInterAd(placementId);
|
||||
},
|
||||
onFailed: (placementId, error, message) {
|
||||
loadUnityInterAd(placementId);
|
||||
},
|
||||
onStart: (placementId) => debugPrint('Video Ad $placementId started'),
|
||||
onClick: (placementId) => debugPrint('Video Ad $placementId click'),
|
||||
onSkipped: (placementId) {
|
||||
loadUnityInterAd(placementId);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_tts/flutter_tts.dart';
|
||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
import 'package:news/cubits/adSpacesNewsDetailsCubit.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/cubits/commentNewsCubit.dart';
|
||||
import 'package:news/cubits/relatedNewsCubit.dart';
|
||||
import 'package:news/cubits/setNewsViewsCubit.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/widgets/adSpaces.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/ImageView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/horizontalBtnList.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/relatedNewsList.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/setBannderAds.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/tagView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/titleView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/videoBtn.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/CommentView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/ReplyCommentView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/backBtn.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/dateView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/descView.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/likeBtn.dart';
|
||||
|
||||
class NewsSubDetails extends StatefulWidget {
|
||||
final NewsModel? model;
|
||||
final BreakingNewsModel? breakModel;
|
||||
final bool fromShowMore;
|
||||
final bool isFromBreak;
|
||||
final Function(bool) onLockScroll;
|
||||
|
||||
const NewsSubDetails({super.key, this.model, this.breakModel, required this.fromShowMore, required this.isFromBreak, required this.onLockScroll});
|
||||
|
||||
@override
|
||||
NewsSubDetailsState createState() => NewsSubDetailsState();
|
||||
}
|
||||
|
||||
class NewsSubDetailsState extends State<NewsSubDetails> {
|
||||
bool comEnabled = false;
|
||||
bool isReply = false;
|
||||
int? replyComIndex;
|
||||
int fontValue = 15;
|
||||
bool isPlaying = false;
|
||||
double volume = 0.5;
|
||||
double pitch = 1.0;
|
||||
double rate = 0.5;
|
||||
BannerAd? _bannerAd;
|
||||
NewsModel? newsModel;
|
||||
FlutterTts? _flutterTts;
|
||||
bool _isScrollingUp = false;
|
||||
late final ScrollController controller = ScrollController()..addListener(hasMoreCommScrollListener);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
newsModel = widget.model;
|
||||
getComments();
|
||||
getRelatedNews();
|
||||
initializeTts();
|
||||
setNewsViews(isBreakingNews: (widget.isFromBreak) ? true : false);
|
||||
if (context.read<AppConfigurationCubit>().getInAppAdsMode() == "1") bannerAdsInitialized();
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<AdSpacesNewsDetailsCubit>().getAdspaceForNewsDetails(langId: context.read<AppLocalizationCubit>().state.id);
|
||||
});
|
||||
}
|
||||
|
||||
setNewsViews({required bool isBreakingNews}) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<SetNewsViewsCubit>().setNewsViews(newsId: isBreakingNews ? widget.breakModel!.id! : (newsModel!.newsId ?? newsModel!.id)!, isBreakingNews: isBreakingNews);
|
||||
});
|
||||
}
|
||||
|
||||
getComments() {
|
||||
if (!widget.isFromBreak && context.read<AppConfigurationCubit>().getCommentsMode() == "1") {
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<CommentNewsCubit>().getCommentNews(newsId: (newsModel!.newsId != null && newsModel!.newsId!.trim().isNotEmpty) ? newsModel!.newsId! : newsModel!.id!);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getRelatedNews() {
|
||||
if (!widget.isFromBreak) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<RelatedNewsCubit>().getRelatedNews(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
catId: (newsModel!.categoryId == "0" || newsModel!.categoryId == '') ? newsModel!.categoryId : null,
|
||||
subCatId: (newsModel!.subCatId != "0" || newsModel!.subCatId != '') ? newsModel!.subCatId : null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_flutterTts!.stop();
|
||||
controller.removeListener(hasMoreCommScrollListener);
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
updateFontVal(int fontVal) {
|
||||
setState(() => fontValue = fontVal);
|
||||
}
|
||||
|
||||
initializeTts() {
|
||||
_flutterTts = FlutterTts();
|
||||
_flutterTts!.awaitSpeakCompletion(true);
|
||||
_flutterTts!.setStartHandler(() async {
|
||||
if (mounted) {
|
||||
setState(() => isPlaying = true);
|
||||
}
|
||||
});
|
||||
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
if (mounted) {
|
||||
setState(() => isPlaying = false);
|
||||
}
|
||||
});
|
||||
|
||||
_flutterTts!.setErrorHandler((err) {
|
||||
if (mounted) {
|
||||
setState(() => isPlaying = false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bannerAdsInitialized() {
|
||||
if (context.read<AppConfigurationCubit>().checkAdsType() == "unity") {
|
||||
UnityAds.init(
|
||||
gameId: context.read<AppConfigurationCubit>().unityGameId()!,
|
||||
testMode: true, //set it to false @Deployment
|
||||
onComplete: () {},
|
||||
onFailed: (error, message) {});
|
||||
}
|
||||
|
||||
if (context.read<AppConfigurationCubit>().checkAdsType() == "google") {
|
||||
_createBottomBannerAd();
|
||||
}
|
||||
}
|
||||
|
||||
void _createBottomBannerAd() {
|
||||
if (context.read<AppConfigurationCubit>().bannerId() != "") {
|
||||
_bannerAd = BannerAd(
|
||||
adUnitId: context.read<AppConfigurationCubit>().bannerId()!,
|
||||
request: const AdRequest(),
|
||||
size: AdSize.banner,
|
||||
listener: BannerAdListener(
|
||||
onAdLoaded: (_) {},
|
||||
onAdFailedToLoad: (ad, err) {
|
||||
ad.dispose();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
_bannerAd!.load();
|
||||
}
|
||||
}
|
||||
|
||||
speak(String description) async {
|
||||
if (description.isNotEmpty) {
|
||||
await _flutterTts!.setVolume(volume);
|
||||
await _flutterTts!.setSpeechRate(rate);
|
||||
await _flutterTts!.setPitch(pitch);
|
||||
await _flutterTts!.setLanguage(() {
|
||||
return context.read<AppLocalizationCubit>().state.languageCode;
|
||||
}());
|
||||
int length = description.length;
|
||||
|
||||
if (length < 4000) {
|
||||
setState(() => isPlaying = true);
|
||||
await _flutterTts!.speak(description);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
_flutterTts!.stop();
|
||||
isPlaying = false;
|
||||
});
|
||||
});
|
||||
} else if (length < 8000) {
|
||||
if (Platform.isAndroid) await _flutterTts!.setQueueMode(1);
|
||||
String temp1 = description.substring(0, length ~/ 2);
|
||||
await _flutterTts!.speak(temp1);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
isPlaying = true;
|
||||
});
|
||||
});
|
||||
String temp2 = description.substring(temp1.length, description.length);
|
||||
await _flutterTts!.speak(temp2);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
isPlaying = false;
|
||||
});
|
||||
});
|
||||
} else if (length < 12000) {
|
||||
if (Platform.isAndroid) await _flutterTts!.setQueueMode(2);
|
||||
String temp1 = description.substring(0, 3999);
|
||||
await _flutterTts!.speak(temp1);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
isPlaying = true;
|
||||
});
|
||||
});
|
||||
String temp2 = description.substring(temp1.length, 7999);
|
||||
await _flutterTts!.speak(temp2);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {});
|
||||
});
|
||||
String temp3 = description.substring(temp2.length, description.length);
|
||||
await _flutterTts!.speak(temp3);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
isPlaying = false;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
String temp = description.substring(0, description.length);
|
||||
await _flutterTts!.speak(temp);
|
||||
_flutterTts!.setCompletionHandler(() {
|
||||
setState(() {
|
||||
isPlaying = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stop() async {
|
||||
var result = await _flutterTts!.stop();
|
||||
if (result == 1) setState(() => isPlaying = false);
|
||||
}
|
||||
|
||||
onBackPress(bool isTrue) {
|
||||
(widget.fromShowMore == true) ? Navigator.of(context).popUntil((route) => route.isFirst) : Navigator.pop(context);
|
||||
}
|
||||
|
||||
Widget showViews() {
|
||||
return Row(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||
Icon(Icons.remove_red_eye_rounded, size: 17, color: UiUtils.getColorScheme(context).primaryContainer),
|
||||
const SizedBox(width: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: CustomTextLabel(
|
||||
text: ((!widget.isFromBreak) ? newsModel!.totalViews : widget.breakModel!.totalViews) ?? '0',
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.w600),
|
||||
textAlign: TextAlign.center))
|
||||
]);
|
||||
}
|
||||
|
||||
Widget showAuthor() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 5, left: 5, right: 5),
|
||||
child: Container(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(Routes.authorDetails, arguments: {"authorId": newsModel!.userAthorDetails!.id ?? "0"});
|
||||
},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircleAvatar(backgroundImage: NetworkImage(newsModel!.userAthorDetails!.profile!)),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomTextLabel(
|
||||
text: newsModel!.userAthorDetails!.name ?? '',
|
||||
textAlign: TextAlign.left,
|
||||
textStyle: TextStyle(
|
||||
color: UiUtils.getColorScheme(context).primaryContainer,
|
||||
fontWeight: FontWeight.w600, // SemiBold
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
otherMainDetails() {
|
||||
int readingTime = UiUtils.calculateReadingTime(widget.isFromBreak ? widget.breakModel!.desc! : newsModel!.desc!);
|
||||
String minutesPostfix = (readingTime == 1) ? UiUtils.getTranslatedLabel(context, 'minute') : UiUtils.getTranslatedLabel(context, 'minutes');
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2.7),
|
||||
child: Container(
|
||||
padding: const EdgeInsetsDirectional.only(top: 20.0, start: 20.0, end: 20.0),
|
||||
width: double.maxFinite,
|
||||
decoration: BoxDecoration(borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: UiUtils.getColorScheme(context).secondary),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||
allRowBtn(
|
||||
isFromBreak: widget.isFromBreak,
|
||||
context: context,
|
||||
breakModel: widget.isFromBreak ? widget.breakModel : null,
|
||||
model: !widget.isFromBreak ? newsModel! : null,
|
||||
fontVal: fontValue,
|
||||
updateFont: updateFontVal,
|
||||
isPlaying: isPlaying,
|
||||
speak: speak,
|
||||
stop: stop,
|
||||
updateComEnabled: updateCommentshow),
|
||||
if (newsModel!.authorDetails != null) showAuthor(),
|
||||
BlocBuilder<AdSpacesNewsDetailsCubit, AdSpacesNewsDetailsState>(
|
||||
builder: (context, state) {
|
||||
return (state is AdSpacesNewsDetailsFetchSuccess && state.adSpaceTopData != null) ? AdSpaces(adsModel: state.adSpaceTopData!) : const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!widget.isFromBreak) tagView(model: newsModel!, context: context, isFromDetailsScreen: true),
|
||||
if (!isReply && !comEnabled)
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 8.0),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
if (!widget.isFromBreak) dateView(context, newsModel!.publishDate ?? newsModel!.date!),
|
||||
if (!widget.isFromBreak) const SizedBox(width: 20),
|
||||
showViews(),
|
||||
const SizedBox(width: 20),
|
||||
Icon(Icons.circle, size: 10, color: UiUtils.getColorScheme(context).primaryContainer),
|
||||
const SizedBox(width: 10),
|
||||
CustomTextLabel(
|
||||
text: "$readingTime $minutesPostfix ${UiUtils.getTranslatedLabel(context, 'read')}",
|
||||
textStyle:
|
||||
Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 12.0, fontWeight: FontWeight.w400))
|
||||
])),
|
||||
if (!isReply && !comEnabled) titleView(title: widget.isFromBreak ? widget.breakModel!.title! : newsModel!.title!, context: context),
|
||||
if (!isReply && !comEnabled) descView(desc: widget.isFromBreak ? widget.breakModel!.desc! : newsModel!.desc!, context: context, fontValue: fontValue.toDouble()),
|
||||
],
|
||||
),
|
||||
if (!widget.isFromBreak && !isReply && comEnabled) CommentView(newsId: newsModel!.id!, updateComFun: updateCommentshow, updateIsReplyFun: updateComReply),
|
||||
if (!widget.isFromBreak && isReply && comEnabled) ReplyCommentView(replyComIndex: replyComIndex!, replyComFun: updateComReply, newsId: newsModel!.id!),
|
||||
BlocBuilder<AdSpacesNewsDetailsCubit, AdSpacesNewsDetailsState>(
|
||||
builder: (context, state) {
|
||||
return (state is AdSpacesNewsDetailsFetchSuccess && state.adSpaceBottomData != null)
|
||||
? Padding(padding: const EdgeInsetsDirectional.only(bottom: 5), child: AdSpaces(adsModel: state.adSpaceBottomData!))
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
if (!widget.isFromBreak && !isReply && !comEnabled && newsModel != null) RelatedNewsList(model: newsModel!),
|
||||
]),
|
||||
));
|
||||
}
|
||||
|
||||
updateCommentshow(bool comEnabledUpdate) {
|
||||
setState(() {
|
||||
comEnabled = comEnabledUpdate;
|
||||
widget.onLockScroll(comEnabledUpdate);
|
||||
});
|
||||
}
|
||||
|
||||
updateComReply(bool comReplyUpdate, int comIndex) {
|
||||
setState(() {
|
||||
isReply = comReplyUpdate;
|
||||
replyComIndex = comIndex;
|
||||
widget.onLockScroll(false);
|
||||
});
|
||||
}
|
||||
|
||||
void hasMoreCommScrollListener() {
|
||||
if (!widget.isFromBreak && comEnabled && !isReply) {
|
||||
if (controller.position.maxScrollExtent == controller.offset) {
|
||||
if (context.read<CommentNewsCubit>().hasMoreCommentNews()) {
|
||||
context.read<CommentNewsCubit>().getMoreCommentNews(newsId: (newsModel!.newsId != null && newsModel!.newsId!.trim().isNotEmpty) ? newsModel!.newsId! : newsModel!.id!);
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
//for comments area
|
||||
if (controller.position.userScrollDirection == ScrollDirection.forward) {
|
||||
// User is scrolling up
|
||||
if (!_isScrollingUp) {
|
||||
setState(() {
|
||||
_isScrollingUp = true;
|
||||
});
|
||||
}
|
||||
} else if (controller.position.userScrollDirection == ScrollDirection.reverse) {
|
||||
// User is scrolling down
|
||||
if (_isScrollingUp) {
|
||||
setState(() {
|
||||
_isScrollingUp = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopScope(
|
||||
onPopInvoked: (bool isTrue) => onBackPress,
|
||||
child: AnimatedPadding(
|
||||
duration: Duration(milliseconds: 300),
|
||||
padding: EdgeInsets.only(top: _isScrollingUp ? MediaQuery.of(context).viewPadding.top : 0),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
flex: (Platform.isAndroid) ? 12 : 9,
|
||||
child: SingleChildScrollView(
|
||||
controller: !widget.isFromBreak && comEnabled && !isReply ? controller : null,
|
||||
child: Stack(children: <Widget>[
|
||||
ImageView(isFromBreak: widget.isFromBreak, model: newsModel, breakModel: widget.breakModel),
|
||||
backBtn(context, widget.fromShowMore),
|
||||
videoBtn(context: context, isFromBreak: widget.isFromBreak, model: !widget.isFromBreak ? newsModel! : null, breakModel: widget.isFromBreak ? widget.breakModel! : null),
|
||||
otherMainDetails(),
|
||||
if (!widget.isFromBreak) likeBtn(context, newsModel!),
|
||||
])),
|
||||
),
|
||||
if ((context.read<AppConfigurationCubit>().getInAppAdsMode() == "1") || _bannerAd != null) Flexible(child: setBannerAd(context, _bannerAd))
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
324
news-app/lib/ui/screens/NewsDetail/Widgets/ReplyCommentView.dart
Normal file
324
news-app/lib/ui/screens/NewsDetail/Widgets/ReplyCommentView.dart
Normal file
@@ -0,0 +1,324 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/data/models/CommentModel.dart';
|
||||
import 'package:news/ui/screens/NewsDetail/Widgets/delAndReportReplyComm.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/likeAndDislikeCommCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/setCommentCubit.dart';
|
||||
import 'package:news/cubits/commentNewsCubit.dart';
|
||||
import 'package:news/data/repositories/NewsComment/LikeAndDislikeComment/likeAndDislikeCommRepository.dart';
|
||||
|
||||
class ReplyCommentView extends StatefulWidget {
|
||||
final int replyComIndex;
|
||||
final Function replyComFun;
|
||||
final String newsId;
|
||||
|
||||
const ReplyCommentView({super.key, required this.replyComIndex, required this.replyComFun, required this.newsId});
|
||||
|
||||
@override
|
||||
ReplyCommentViewState createState() => ReplyCommentViewState();
|
||||
}
|
||||
|
||||
class ReplyCommentViewState extends State<ReplyCommentView> {
|
||||
bool isReply = false, replyComEnabled = false, isSending = false;
|
||||
final TextEditingController _replyComC = TextEditingController();
|
||||
TextEditingController reportC = TextEditingController();
|
||||
|
||||
Widget allReplyComView(CommentModel model) {
|
||||
return Row(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Row(children: [
|
||||
CustomTextLabel(
|
||||
text: 'allLbl',
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
CustomTextLabel(
|
||||
text: " ${model.replyComList!.length} ",
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
CustomTextLabel(
|
||||
text: (model.replyComList!.length == 1) ? 'replyLbl' : 'repliesLbl',
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6), fontSize: 12.0, fontWeight: FontWeight.w600)),
|
||||
])),
|
||||
const Spacer(),
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: InkWell(
|
||||
child: const Icon(Icons.close),
|
||||
onTap: () {
|
||||
setState(() => isReply = false);
|
||||
widget.replyComFun(false, widget.replyComIndex);
|
||||
}))
|
||||
]);
|
||||
}
|
||||
|
||||
replyComProfileWithCom(CommentModel modelCom) {
|
||||
return BlocBuilder<LikeAndDislikeCommCubit, LikeAndDislikeCommState>(
|
||||
builder: (context, state) {
|
||||
DateTime replyTime = DateTime.parse(modelCom.date!);
|
||||
return Container(
|
||||
decoration: BoxDecoration(border: Border.all(width: 2, color: borderColor)),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||
modelCom.profile != null && modelCom.profile != ""
|
||||
? UiUtils.setFixedSizeboxForProfilePicture(childWidget: CircleAvatar(backgroundImage: NetworkImage(modelCom.profile!), radius: 32))
|
||||
: UiUtils.setFixedSizeboxForProfilePicture(childWidget: const Icon(Icons.account_circle, size: 35)),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 15.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomTextLabel(
|
||||
text: modelCom.name!,
|
||||
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 13)),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 10.0),
|
||||
child: Icon(Icons.circle, size: 4.0, color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7))),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 10.0),
|
||||
child: CustomTextLabel(
|
||||
text: UiUtils.convertToAgo(context, replyTime, 1)!,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 10)))
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: CustomTextLabel(
|
||||
text: modelCom.message!,
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.normal)),
|
||||
),
|
||||
],
|
||||
))),
|
||||
]));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
replyComSendReplyView(CommentModel model) {
|
||||
return context.read<AuthCubit>().getUserId() != "0"
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 10.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: context.read<AuthCubit>().getProfile() != ""
|
||||
? UiUtils.setFixedSizeboxForProfilePicture(childWidget: CircleAvatar(backgroundImage: NetworkImage(context.read<AuthCubit>().getProfile()), radius: 32))
|
||||
: UiUtils.setFixedSizeboxForProfilePicture(childWidget: const Icon(Icons.account_circle, size: 35))),
|
||||
BlocListener<SetCommentCubit, SetCommentState>(
|
||||
bloc: context.read<SetCommentCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is SetCommentFetchSuccess) {
|
||||
context.read<CommentNewsCubit>().commentUpdateList(state.setComment, state.total);
|
||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||
if (!currentFocus.hasPrimaryFocus) {
|
||||
currentFocus.unfocus();
|
||||
}
|
||||
_replyComC.clear();
|
||||
isSending = false;
|
||||
setState(() {});
|
||||
}
|
||||
if (state is SetCommentFetchInProgress) {
|
||||
setState(() => isSending = true);
|
||||
}
|
||||
},
|
||||
child: Expanded(
|
||||
flex: 7,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 18.0),
|
||||
child: TextField(
|
||||
controller: _replyComC,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
onChanged: (String val) {
|
||||
if (_replyComC.text.trim().isNotEmpty) {
|
||||
setState(() => replyComEnabled = true);
|
||||
} else {
|
||||
setState(() => replyComEnabled = false);
|
||||
}
|
||||
},
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(top: 10.0, bottom: 2.0),
|
||||
isDense: true,
|
||||
enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.5), width: 1.5)),
|
||||
hintText: UiUtils.getTranslatedLabel(context, 'publicReply'),
|
||||
hintStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
suffixIconConstraints: const BoxConstraints(maxHeight: 35, maxWidth: 30),
|
||||
suffixIcon: (_replyComC.text.trim().isNotEmpty)
|
||||
? (!isSending)
|
||||
? IconButton(
|
||||
icon: Icon(Icons.send, color: replyComEnabled ? UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8) : Colors.transparent, size: 20.0),
|
||||
onPressed: () async {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
context.read<SetCommentCubit>().setComment(parentId: model.id!, newsId: widget.newsId, message: _replyComC.text);
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
)
|
||||
: SizedBox(height: 12, width: 12, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: SizedBox.shrink()),
|
||||
))))
|
||||
],
|
||||
))
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
|
||||
replyAllComListView(CommentModel model) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: SingleChildScrollView(
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (BuildContext context, int index) => Divider(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.5)),
|
||||
shrinkWrap: true,
|
||||
reverse: true,
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: model.replyComList!.length,
|
||||
itemBuilder: (context, index) {
|
||||
DateTime time1 = DateTime.parse(model.replyComList![index].date!);
|
||||
return Builder(builder: (context) {
|
||||
return Row(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||
model.replyComList![index].profile != null && model.replyComList![index].profile != ""
|
||||
? UiUtils.setFixedSizeboxForProfilePicture(childWidget: CircleAvatar(backgroundImage: NetworkImage(model.replyComList![index].profile!), radius: 32))
|
||||
: UiUtils.setFixedSizeboxForProfilePicture(childWidget: const Icon(Icons.account_circle, size: 35)),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 15.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomTextLabel(
|
||||
text: model.replyComList![index].name!,
|
||||
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 13)),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 10.0),
|
||||
child: Icon(Icons.circle, size: 4.0, color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7))),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 10.0),
|
||||
child: CustomTextLabel(
|
||||
text: UiUtils.convertToAgo(context, time1, 1)!,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontSize: 10),
|
||||
)),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: CustomTextLabel(
|
||||
text: model.replyComList![index].message!,
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.normal),
|
||||
),
|
||||
),
|
||||
BlocBuilder<LikeAndDislikeCommCubit, LikeAndDislikeCommState>(builder: (context, state) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
child: const Icon(Icons.thumb_up_off_alt_rounded),
|
||||
onTap: () {
|
||||
(context.read<AuthCubit>().getUserId() != "0")
|
||||
? context.read<LikeAndDislikeCommCubit>().setLikeAndDislikeComm(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
commId: model.replyComList![index].id!,
|
||||
status: (model.replyComList![index].like == "1") ? "0" : "1",
|
||||
fromLike: true)
|
||||
: UiUtils.loginRequired(context);
|
||||
},
|
||||
),
|
||||
model.replyComList![index].totalLikes! != "0"
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: model.replyComList![index].totalLikes!,
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)))
|
||||
: const SizedBox(width: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 35),
|
||||
child: InkWell(
|
||||
child: const Icon(Icons.thumb_down_alt_rounded),
|
||||
onTap: () {
|
||||
(context.read<AuthCubit>().getUserId() != "0")
|
||||
? context.read<LikeAndDislikeCommCubit>().setLikeAndDislikeComm(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
commId: model.replyComList![index].id!,
|
||||
status: (model.replyComList![index].dislike == "1") ? "0" : "2",
|
||||
fromLike: false)
|
||||
: UiUtils.loginRequired(context);
|
||||
},
|
||||
)),
|
||||
model.replyComList![index].totalDislikes! != "0"
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: model.replyComList![index].totalDislikes!,
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)))
|
||||
: const SizedBox.shrink(),
|
||||
const Spacer(),
|
||||
if (context.read<AuthCubit>().getUserId() != "0")
|
||||
InkWell(
|
||||
child: Icon(Icons.more_vert_outlined, color: UiUtils.getColorScheme(context).primaryContainer, size: 17),
|
||||
onTap: () => delAndReportReplyComm(model: model, context: context, reportC: reportC, newsId: widget.newsId, setState: setState, replyIndex: index))
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
))),
|
||||
]);
|
||||
});
|
||||
})));
|
||||
}
|
||||
|
||||
Widget replyCommentView() {
|
||||
return BlocBuilder<CommentNewsCubit, CommentNewsState>(builder: (context, state) {
|
||||
if (state is CommentNewsFetchSuccess && state.commentNews.isNotEmpty) {
|
||||
return BlocListener<LikeAndDislikeCommCubit, LikeAndDislikeCommState>(
|
||||
listener: (context, likeDislikeState) {
|
||||
if (likeDislikeState is LikeAndDislikeCommSuccess) {
|
||||
final defaultIndex = state.commentNews.indexWhere((element) => element.id == likeDislikeState.comment.id);
|
||||
if (defaultIndex != -1) {
|
||||
state.commentNews[defaultIndex].replyComList = likeDislikeState.comment.replyComList;
|
||||
context.read<CommentNewsCubit>().emitSuccessState(state.commentNews);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 10.0, bottom: 10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
allReplyComView(state.commentNews[widget.replyComIndex]),
|
||||
replyComProfileWithCom(state.commentNews[widget.replyComIndex]),
|
||||
replyComSendReplyView(state.commentNews[widget.replyComIndex]),
|
||||
replyAllComListView(state.commentNews[widget.replyComIndex])
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
if (state is CommentNewsFetchFailure) {
|
||||
return Center(child: CustomTextLabel(text: state.errorMessage, textAlign: TextAlign.center));
|
||||
}
|
||||
//state is CommentNewsFetchInProgress || state is CommentNewsInitial
|
||||
return const Padding(padding: EdgeInsets.only(bottom: 10.0, left: 10.0, right: 10.0), child: SizedBox.shrink());
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(create: (context) => LikeAndDislikeCommCubit(LikeAndDislikeCommRepository()), child: replyCommentView());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
|
||||
const AdRequest request = AdRequest(
|
||||
//static
|
||||
keywords: <String>['foo', 'bar'],
|
||||
contentUrl: 'http://foo.com/bar.html',
|
||||
nonPersonalizedAds: true,
|
||||
);
|
||||
RewardedAd? rewardedAd;
|
||||
int _numRewardedLoadAttempts = 0;
|
||||
int maxFailedLoadAttempts = 3;
|
||||
|
||||
void createGoogleRewardedAd(BuildContext context) {
|
||||
if (context.read<AppConfigurationCubit>().rewardId() != "") {
|
||||
RewardedAd.load(
|
||||
adUnitId: context.read<AppConfigurationCubit>().rewardId()!,
|
||||
request: request,
|
||||
rewardedAdLoadCallback: RewardedAdLoadCallback(
|
||||
onAdLoaded: (RewardedAd ad) {
|
||||
rewardedAd = ad;
|
||||
_numRewardedLoadAttempts = 0;
|
||||
},
|
||||
onAdFailedToLoad: (LoadAdError error) {
|
||||
rewardedAd = null;
|
||||
_numRewardedLoadAttempts += 1;
|
||||
if (_numRewardedLoadAttempts <= maxFailedLoadAttempts) {
|
||||
createGoogleRewardedAd(context);
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void showGoogleRewardedAd(BuildContext context) {
|
||||
if (context.read<AppConfigurationCubit>().rewardId() != "") {
|
||||
if (rewardedAd == null) {
|
||||
return;
|
||||
}
|
||||
rewardedAd!.fullScreenContentCallback = FullScreenContentCallback(
|
||||
onAdShowedFullScreenContent: (RewardedAd ad) => debugPrint('ad onAdShowedFullScreenContent.'),
|
||||
onAdDismissedFullScreenContent: (RewardedAd ad) {
|
||||
ad.dispose();
|
||||
createGoogleRewardedAd(context);
|
||||
},
|
||||
onAdFailedToShowFullScreenContent: (RewardedAd ad, AdError error) {
|
||||
ad.dispose();
|
||||
createGoogleRewardedAd(context);
|
||||
},
|
||||
);
|
||||
|
||||
rewardedAd!.setImmersiveMode(true);
|
||||
rewardedAd!.show(onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {});
|
||||
rewardedAd = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
|
||||
|
||||
void loadUnityRewardAd(String placementId) {
|
||||
UnityAds.load(placementId: placementId, onComplete: (placementId) {}, onFailed: (placementId, error, message) {});
|
||||
}
|
||||
|
||||
void showUnityRewardAds(String placementId) {
|
||||
UnityAds.showVideoAd(
|
||||
placementId: placementId,
|
||||
onComplete: (placementId) {
|
||||
loadUnityRewardAd(placementId);
|
||||
},
|
||||
onFailed: (placementId, error, message) {
|
||||
loadUnityRewardAd(placementId);
|
||||
},
|
||||
onStart: (placementId) => debugPrint('Video Ad $placementId started'),
|
||||
onClick: (placementId) => debugPrint('Video Ad $placementId click'),
|
||||
onSkipped: (placementId) {
|
||||
loadUnityRewardAd(placementId);
|
||||
},
|
||||
);
|
||||
}
|
||||
121
news-app/lib/ui/screens/NewsDetail/Widgets/ShowMoreNewsList.dart
Normal file
121
news-app/lib/ui/screens/NewsDetail/Widgets/ShowMoreNewsList.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/relatedNewsCubit.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/data/repositories/Settings/settingsLocalDataRepository.dart';
|
||||
import 'package:news/ui/widgets/NewsItem.dart';
|
||||
import 'package:news/ui/widgets/errorContainerWidget.dart';
|
||||
import 'package:news/ui/widgets/shimmerNewsList.dart';
|
||||
|
||||
import 'package:news/ui/widgets/customAppBar.dart';
|
||||
import 'package:news/utils/ErrorMessageKeys.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
class ShowMoreNewsList extends StatefulWidget {
|
||||
final NewsModel model;
|
||||
|
||||
const ShowMoreNewsList({super.key, required this.model});
|
||||
|
||||
@override
|
||||
ShowMoreNewsListState createState() => ShowMoreNewsListState();
|
||||
|
||||
static Route route(RouteSettings routeSettings) {
|
||||
final arguments = routeSettings.arguments as Map<String, dynamic>;
|
||||
return CupertinoPageRoute(builder: (_) => ShowMoreNewsList(model: arguments['model']));
|
||||
}
|
||||
}
|
||||
|
||||
class ShowMoreNewsListState extends State<ShowMoreNewsList> {
|
||||
late final ScrollController controller = ScrollController()..addListener(hasMoreRelatedNewsScrollListener);
|
||||
Set<String> get locationValue => SettingsLocalDataRepository().getLocationCityValues();
|
||||
|
||||
void hasMoreRelatedNewsScrollListener() {
|
||||
if (controller.position.maxScrollExtent == controller.offset) {
|
||||
if (context.read<RelatedNewsCubit>().hasMoreRelatedNews()) {
|
||||
context.read<RelatedNewsCubit>().getMoreRelatedNews(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
catId: widget.model.subCatId == "0" || widget.model.subCatId == '' ? widget.model.categoryId : null,
|
||||
subCatId: widget.model.subCatId != "0" || widget.model.subCatId != '' ? widget.model.subCatId : null,
|
||||
latitude: locationValue.first,
|
||||
longitude: locationValue.last);
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
|
||||
_buildRelatedNewsContainer(
|
||||
{required NewsModel model, required int index, required int totalCurrentRelatedNews, required bool hasMoreRelatedNewsFetchError, required bool hasMore, required List<NewsModel> newsList}) {
|
||||
if (index == totalCurrentRelatedNews - 1 && index != 0) {
|
||||
if (hasMore) {
|
||||
if (hasMoreRelatedNewsFetchError) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.0),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
context.read<RelatedNewsCubit>().getMoreRelatedNews(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
catId: widget.model.subCatId == "0" || widget.model.subCatId == '' ? widget.model.categoryId : null,
|
||||
subCatId: widget.model.subCatId != "0" || widget.model.subCatId != '' ? widget.model.subCatId : null,
|
||||
latitude: locationValue.first,
|
||||
longitude: locationValue.last);
|
||||
},
|
||||
icon: Icon(Icons.error, color: Theme.of(context).primaryColor)),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Center(child: Padding(padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.0), child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NewsItem(model: model, index: index, newslist: newsList, fromShowMore: true);
|
||||
}
|
||||
|
||||
void refreshNewsList() {
|
||||
context.read<RelatedNewsCubit>().getRelatedNews(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
catId: widget.model.subCatId == "0" || widget.model.subCatId == '' ? widget.model.categoryId : null,
|
||||
subCatId: widget.model.subCatId != "0" || widget.model.subCatId != '' ? widget.model.subCatId : null);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(height: 45, isBackBtn: true, label: 'relatedNews', horizontalPad: 15, isConvertText: true),
|
||||
body: BlocBuilder<RelatedNewsCubit, RelatedNewsState>(
|
||||
builder: (context, state) {
|
||||
if (state is RelatedNewsFetchSuccess) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
refreshNewsList();
|
||||
},
|
||||
child: ListView.builder(
|
||||
controller: controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: state.relatedNews.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildRelatedNewsContainer(
|
||||
model: state.relatedNews[index],
|
||||
hasMore: state.hasMore,
|
||||
hasMoreRelatedNewsFetchError: state.hasMoreFetchError,
|
||||
index: index,
|
||||
totalCurrentRelatedNews: state.relatedNews.length,
|
||||
newsList: state.relatedNews);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is RelatedNewsFetchFailure) {
|
||||
return ErrorContainerWidget(
|
||||
errorMsg: (state.errorMessage.contains(ErrorMessageKeys.noInternet)) ? UiUtils.getTranslatedLabel(context, 'internetmsg') : state.errorMessage, onRetry: refreshNewsList);
|
||||
}
|
||||
//state is RelatedNewsInitial || state is RelatedNewsFetchInProgress
|
||||
return Padding(padding: const EdgeInsets.only(bottom: 10.0, left: 10.0, right: 10.0), child: ShimmerNewsList(isNews: true));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
24
news-app/lib/ui/screens/NewsDetail/Widgets/backBtn.dart
Normal file
24
news-app/lib/ui/screens/NewsDetail/Widgets/backBtn.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
|
||||
Widget backBtn(BuildContext context, bool fromShowMore) {
|
||||
return Positioned.directional(
|
||||
textDirection: Directionality.of(context),
|
||||
top: 40,
|
||||
start: 20.0,
|
||||
child: InkWell(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(52.0),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 39,
|
||||
width: 39,
|
||||
decoration: const BoxDecoration(color: secondaryColor, shape: BoxShape.circle),
|
||||
child: const Icon(Icons.keyboard_backspace_rounded, color: darkSecondaryColor)))),
|
||||
onTap: () {
|
||||
(fromShowMore == true) ? Navigator.of(context).popUntil((route) => route.isFirst) : Navigator.pop(context);
|
||||
}));
|
||||
}
|
||||
15
news-app/lib/ui/screens/NewsDetail/Widgets/dateView.dart
Normal file
15
news-app/lib/ui/screens/NewsDetail/Widgets/dateView.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
Widget dateView(BuildContext context, String date) {
|
||||
return Row(
|
||||
children: [
|
||||
const Icon(Icons.access_time_filled_rounded, size: 15),
|
||||
const SizedBox(width: 3),
|
||||
CustomTextLabel(
|
||||
text: UiUtils.convertToAgo(context, DateTime.parse(date), 0)!,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 12.0, fontWeight: FontWeight.w600))
|
||||
],
|
||||
);
|
||||
}
|
||||
131
news-app/lib/ui/screens/NewsDetail/Widgets/delAndReportCom.dart
Normal file
131
news-app/lib/ui/screens/NewsDetail/Widgets/delAndReportCom.dart
Normal file
@@ -0,0 +1,131 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/deleteCommentCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/flagCommentCubit.dart';
|
||||
import 'package:news/cubits/commentNewsCubit.dart';
|
||||
import 'package:news/data/models/CommentModel.dart';
|
||||
import 'package:news/ui/screens/auth/Widgets/svgPictureWidget.dart';
|
||||
import 'package:news/ui/widgets/customTextBtn.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:news/ui/widgets/SnackBarWidget.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
|
||||
delAndReportCom(
|
||||
{required int index,
|
||||
required CommentModel model,
|
||||
required BuildContext context,
|
||||
required TextEditingController reportC,
|
||||
required String newsId,
|
||||
required StateSetter setState,
|
||||
Function? isReplyUpdate}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: const EdgeInsets.all(20),
|
||||
elevation: 2.0,
|
||||
backgroundColor: UiUtils.getColorScheme(context).surface,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.0))),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
if (context.read<AuthCubit>().getUserId() == model.userId!)
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
context.read<DeleteCommCubit>().setDeleteComm(commId: model.id!);
|
||||
}
|
||||
},
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
CustomTextLabel(
|
||||
text: 'deleteTxt',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)),
|
||||
const Spacer(),
|
||||
BlocConsumer<DeleteCommCubit, DeleteCommState>(
|
||||
bloc: context.read<DeleteCommCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is DeleteCommSuccess) {
|
||||
context.read<CommentNewsCubit>().deleteComment(index);
|
||||
showSnackBar(state.message, context);
|
||||
if (isReplyUpdate != null) {
|
||||
isReplyUpdate(false, index);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return SvgPictureWidget(assetName: "delete_icon", assetColor: ColorFilter.mode(UiUtils.getColorScheme(context).primaryContainer, BlendMode.srcIn), height: 20, width: 20);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (context.read<AuthCubit>().getUserId() != model.userId!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Row(children: <Widget>[
|
||||
CustomTextLabel(
|
||||
text: 'reportTxt',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)),
|
||||
const Spacer(),
|
||||
SvgPictureWidget(assetName: "flag_icon", assetColor: ColorFilter.mode(UiUtils.getColorScheme(context).primaryContainer, BlendMode.srcIn), height: 20, width: 20)
|
||||
])),
|
||||
if (context.read<AuthCubit>().getUserId() != model.userId!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: TextField(
|
||||
controller: reportC,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6)),
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), width: 0.5)),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), width: 0.5)),
|
||||
))),
|
||||
if (context.read<AuthCubit>().getUserId() != model.userId!)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
CustomTextButton(
|
||||
onTap: () => Navigator.pop(context),
|
||||
textWidget: CustomTextLabel(
|
||||
text: 'cancelBtn',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold))),
|
||||
BlocConsumer<SetFlagCubit, SetFlagState>(
|
||||
bloc: context.read<SetFlagCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is SetFlagFetchSuccess) {
|
||||
setState(() => reportC.text = "");
|
||||
showSnackBar(state.message, context);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return CustomTextButton(
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
if (reportC.text.trim().isNotEmpty) {
|
||||
context.read<SetFlagCubit>().setFlag(commId: model.id!, newsId: newsId, message: reportC.text);
|
||||
} else {
|
||||
showSnackBar(UiUtils.getTranslatedLabel(context, 'firstFillData'), context);
|
||||
}
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
textWidget: CustomTextLabel(
|
||||
text: 'submitBtn',
|
||||
textStyle:
|
||||
Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)));
|
||||
})
|
||||
],
|
||||
),
|
||||
],
|
||||
)));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/data/models/CommentModel.dart';
|
||||
import 'package:news/ui/screens/auth/Widgets/svgPictureWidget.dart';
|
||||
import 'package:news/ui/widgets/customTextBtn.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/deleteCommentCubit.dart';
|
||||
import 'package:news/cubits/NewsComment/flagCommentCubit.dart';
|
||||
import 'package:news/cubits/commentNewsCubit.dart';
|
||||
import 'package:news/ui/widgets/SnackBarWidget.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
|
||||
delAndReportReplyComm(
|
||||
{required CommentModel model, required BuildContext context, required TextEditingController reportC, required String newsId, required StateSetter setState, required int replyIndex}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: const EdgeInsets.all(20),
|
||||
elevation: 2.0,
|
||||
backgroundColor: UiUtils.getColorScheme(context).surface,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.0))),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
if (context.read<AuthCubit>().getUserId() == model.replyComList![replyIndex].userId!)
|
||||
InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onTap: () async {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
context.read<DeleteCommCubit>().setDeleteComm(commId: model.replyComList![replyIndex].id!);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
CustomTextLabel(
|
||||
text: 'deleteTxt',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)),
|
||||
const Spacer(),
|
||||
BlocConsumer<DeleteCommCubit, DeleteCommState>(
|
||||
bloc: context.read<DeleteCommCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is DeleteCommSuccess) {
|
||||
context.read<CommentNewsCubit>().deleteCommentReply(model.id!, replyIndex);
|
||||
showSnackBar(state.message, context);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return SvgPictureWidget(assetName: "delete_icon", assetColor: ColorFilter.mode(UiUtils.getColorScheme(context).primaryContainer, BlendMode.srcIn), height: 20, width: 20);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (context.read<AuthCubit>().getUserId() != model.replyComList![replyIndex].userId!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
CustomTextLabel(
|
||||
text: 'reportTxt',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)),
|
||||
const Spacer(),
|
||||
SvgPictureWidget(assetName: "flag_icon", assetColor: ColorFilter.mode(UiUtils.getColorScheme(context).primaryContainer, BlendMode.srcIn), height: 20, width: 20)
|
||||
],
|
||||
)),
|
||||
if (context.read<AuthCubit>().getUserId() != model.replyComList![replyIndex].userId!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: TextField(
|
||||
controller: reportC,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.6)),
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), width: 0.5)),
|
||||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), width: 0.5)),
|
||||
),
|
||||
)),
|
||||
if (context.read<AuthCubit>().getUserId() != model.replyComList![replyIndex].userId!)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
CustomTextButton(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
textWidget: CustomTextLabel(
|
||||
text: 'cancelBtn',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold))),
|
||||
BlocConsumer<SetFlagCubit, SetFlagState>(
|
||||
bloc: context.read<SetFlagCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is SetFlagFetchSuccess) {
|
||||
setState(() {
|
||||
reportC.text = "";
|
||||
});
|
||||
|
||||
showSnackBar(state.message, context);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return CustomTextButton(
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
if (reportC.text.trim().isNotEmpty) {
|
||||
context.read<SetFlagCubit>().setFlag(commId: model.replyComList![replyIndex].id!, newsId: newsId, message: reportC.text);
|
||||
} else {
|
||||
showSnackBar(UiUtils.getTranslatedLabel(context, 'firstFillData'), context);
|
||||
}
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
textWidget: CustomTextLabel(
|
||||
text: 'submitBtn',
|
||||
textStyle:
|
||||
Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7), fontWeight: FontWeight.bold)));
|
||||
})
|
||||
],
|
||||
),
|
||||
],
|
||||
)));
|
||||
});
|
||||
}
|
||||
41
news-app/lib/ui/screens/NewsDetail/Widgets/descView.dart
Normal file
41
news-app/lib/ui/screens/NewsDetail/Widgets/descView.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:news/ui/screens/NewsDetailsVideo.dart';
|
||||
|
||||
Widget descView({required String desc, required double fontValue, required BuildContext context}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: HtmlWidget(
|
||||
desc,
|
||||
onTapUrl: (String? url) async {
|
||||
if (await canLaunchUrl(Uri.parse(url!))) {
|
||||
await launchUrl(Uri.parse(url));
|
||||
return true;
|
||||
} else {
|
||||
throw 'Could not launch $url';
|
||||
}
|
||||
},
|
||||
onErrorBuilder: (context, element, error) => CustomTextLabel(text: '$element error: $error'),
|
||||
onLoadingBuilder: (context, element, loadingProgress) => UiUtils.showCircularProgress(true, Theme.of(context).primaryColor),
|
||||
renderMode: RenderMode.column,
|
||||
// set the default styling for text
|
||||
textStyle: TextStyle(fontSize: fontValue.toDouble()),
|
||||
customWidgetBuilder: (element) {
|
||||
if ((element.toString() == "<html iframe>") || (element.toString() == "<html video>")) {
|
||||
return FittedBox(
|
||||
fit: BoxFit.fill,
|
||||
child: Container(
|
||||
height: 220,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
color: Colors.transparent,
|
||||
child: (element.toString() == "<html iframe>") ? NewsDetailsVideo(src: element.attributes["src"], type: "1") : NewsDetailsVideo(type: "2", src: element.outerHtml)),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:html/parser.dart' show parse;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/Bookmark/UpdateBookmarkCubit.dart';
|
||||
import 'package:news/cubits/Bookmark/bookmarkCubit.dart';
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
|
||||
import 'package:news/ui/widgets/SnackBarWidget.dart';
|
||||
import 'package:news/utils/internetConnectivity.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
Widget allRowBtn(
|
||||
{required bool isFromBreak,
|
||||
required BuildContext context,
|
||||
BreakingNewsModel? breakModel,
|
||||
NewsModel? model,
|
||||
required int fontVal,
|
||||
required Function updateFont,
|
||||
required bool isPlaying,
|
||||
required Function speak,
|
||||
required Function stop,
|
||||
required Function updateComEnabled}) {
|
||||
return !isFromBreak
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 85),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(children: [
|
||||
if (context.read<AppConfigurationCubit>().getCommentsMode() == "1")
|
||||
InkWell(
|
||||
child: Column(children: [
|
||||
const Icon(Icons.insert_comment_rounded),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'comLbl',
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0)))
|
||||
]),
|
||||
onTap: () {
|
||||
if (model!.isCommentEnabled != null && model.isCommentEnabled == 0) {
|
||||
//comments disabled by Admin
|
||||
showSnackBar(UiUtils.getTranslatedLabel(context, "disabledCommentsMsg"), context);
|
||||
} else {
|
||||
updateComEnabled(true);
|
||||
}
|
||||
}),
|
||||
InkWell(
|
||||
child: setShareBtn(context),
|
||||
onTap: () async {
|
||||
if (await InternetConnectivity.isNetworkAvailable()) {
|
||||
UiUtils.shareNews(context: context, slug: model!.slug!, title: model.title!, isNews: true, isVideo: false, videoId: "", isBreakingNews: false);
|
||||
} else {
|
||||
showSnackBar(UiUtils.getTranslatedLabel(context, 'internetmsg'), context);
|
||||
}
|
||||
},
|
||||
),
|
||||
BlocBuilder<BookmarkCubit, BookmarkState>(
|
||||
bloc: context.read<BookmarkCubit>(),
|
||||
builder: (context, bookmarkState) {
|
||||
bool isBookmark = context.read<BookmarkCubit>().isNewsBookmark(model!.newsId!);
|
||||
return BlocConsumer<UpdateBookmarkStatusCubit, UpdateBookmarkStatusState>(
|
||||
bloc: context.read<UpdateBookmarkStatusCubit>(),
|
||||
listener: ((context, state) {
|
||||
if (state is UpdateBookmarkStatusSuccess) {
|
||||
if (state.wasBookmarkNewsProcess) {
|
||||
context.read<BookmarkCubit>().addBookmarkNews(state.news);
|
||||
} else {
|
||||
context.read<BookmarkCubit>().removeBookmarkNews(state.news);
|
||||
}
|
||||
}
|
||||
isBookmark = context.read<BookmarkCubit>().isNewsBookmark(model.newsId!);
|
||||
}),
|
||||
builder: (context, state) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
if (state is UpdateBookmarkStatusInProgress) {
|
||||
return;
|
||||
}
|
||||
context.read<UpdateBookmarkStatusCubit>().setBookmarkNews(news: model, status: (isBookmark) ? "0" : "1");
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.13,
|
||||
child: Column(children: [
|
||||
state is UpdateBookmarkStatusInProgress
|
||||
? SizedBox(height: 24, width: 24, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: Icon(isBookmark ? Icons.bookmark_added_rounded : Icons.bookmark_add_outlined),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'saveLbl',
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0)))
|
||||
]),
|
||||
));
|
||||
});
|
||||
}),
|
||||
InkWell(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.13,
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.text_fields_rounded),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'txtSizeLbl',
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0)))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
changeFontSizeSheet(context, fontVal, updateFont);
|
||||
},
|
||||
),
|
||||
InkWell(
|
||||
child: setSpeakBtn(context, isPlaying),
|
||||
onTap: () {
|
||||
if (isPlaying) {
|
||||
stop();
|
||||
} else {
|
||||
final document = parse("${model!.title}\n${model.desc}"); //Speak Title along with Description
|
||||
String parsedString = parse(document.body!.text).documentElement!.text;
|
||||
speak(parsedString);
|
||||
}
|
||||
})
|
||||
]),
|
||||
))
|
||||
: Row(children: [
|
||||
InkWell(
|
||||
child: setTextSize(context),
|
||||
onTap: () {
|
||||
changeFontSizeSheet(context, fontVal, updateFont);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: InkWell(
|
||||
child: setSpeakBtn(context, isPlaying),
|
||||
onTap: () {
|
||||
if (isPlaying) {
|
||||
stop();
|
||||
} else {
|
||||
final document = parse("${breakModel!.title}\n${breakModel.desc}"); //Speak Title along with Description
|
||||
String parsedString = parse(document.body!.text).documentElement!.text;
|
||||
speak(parsedString);
|
||||
}
|
||||
})),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: InkWell(
|
||||
child: setShareBtn(context),
|
||||
onTap: () async {
|
||||
if (await InternetConnectivity.isNetworkAvailable()) {
|
||||
UiUtils.shareNews(context: context, slug: breakModel!.slug!, title: breakModel.title!, isVideo: false, videoId: "", isBreakingNews: true, isNews: false);
|
||||
} else {
|
||||
showSnackBar(UiUtils.getTranslatedLabel(context, 'internetmsg'), context);
|
||||
}
|
||||
}))
|
||||
]);
|
||||
}
|
||||
|
||||
changeFontSizeSheet(BuildContext context, int fontValue, Function updateFun) {
|
||||
showModalBottomSheet<dynamic>(
|
||||
context: context,
|
||||
elevation: 5.0,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(50), topRight: Radius.circular(50))),
|
||||
builder: (BuildContext context) {
|
||||
return StatefulBuilder(builder: (BuildContext context, setStater) {
|
||||
return Container(
|
||||
padding: const EdgeInsetsDirectional.only(bottom: 20.0, top: 5.0, start: 20.0, end: 20.0),
|
||||
decoration: const BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(50), topRight: Radius.circular(50))),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 30),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||
const Icon(Icons.text_fields_rounded),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: CustomTextLabel(
|
||||
text: 'txtSizeLbl',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer),
|
||||
)),
|
||||
CustomTextLabel(text: "( $fontValue )", textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer)),
|
||||
])),
|
||||
SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: Colors.red[700],
|
||||
inactiveTrackColor: Colors.red[100],
|
||||
trackShape: const RoundedRectSliderTrackShape(),
|
||||
trackHeight: 4.0,
|
||||
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 8.0),
|
||||
thumbColor: Colors.redAccent,
|
||||
overlayColor: Colors.red.withAlpha(32),
|
||||
overlayShape: const RoundSliderOverlayShape(overlayRadius: 28.0),
|
||||
tickMarkShape: const RoundSliderTickMarkShape(),
|
||||
activeTickMarkColor: Colors.red[700],
|
||||
inactiveTickMarkColor: Colors.red[100],
|
||||
valueIndicatorShape: const PaddleSliderValueIndicatorShape(),
|
||||
valueIndicatorColor: Colors.redAccent,
|
||||
valueIndicatorTextStyle: const TextStyle(color: Colors.white)),
|
||||
child: Slider(
|
||||
label: '$fontValue',
|
||||
value: fontValue.toDouble(),
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
min: 15,
|
||||
max: 40,
|
||||
divisions: 10,
|
||||
onChanged: (value) {
|
||||
setStater(() {
|
||||
fontValue = value.round();
|
||||
updateFun(value.round());
|
||||
});
|
||||
}))
|
||||
],
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setShareBtn(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.13,
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.share_rounded),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'shareLbl',
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
setSpeakBtn(BuildContext context, bool isPlaying) {
|
||||
return SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.13,
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.speaker_phone_rounded, color: isPlaying ? Theme.of(context).primaryColor : UiUtils.getColorScheme(context).primaryContainer),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'speakLoudLbl',
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(color: isPlaying ? Theme.of(context).primaryColor : UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0)))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
setTextSize(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const Icon(Icons.text_fields_rounded),
|
||||
Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 4.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'txtSizeLbl', maxLines: 2, textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.8), fontSize: 9.0)))
|
||||
],
|
||||
);
|
||||
}
|
||||
89
news-app/lib/ui/screens/NewsDetail/Widgets/likeBtn.dart
Normal file
89
news-app/lib/ui/screens/NewsDetail/Widgets/likeBtn.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/Auth/authCubit.dart';
|
||||
import 'package:news/cubits/LikeAndDislikeNews/LikeAndDislikeCubit.dart';
|
||||
import 'package:news/cubits/LikeAndDislikeNews/updateLikeAndDislikeCubit.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
Widget likeBtn(BuildContext context, NewsModel model) {
|
||||
bool isLike = context.read<LikeAndDisLikeCubit>().isNewsLikeAndDisLike(model.newsId!);
|
||||
return BlocConsumer<LikeAndDisLikeCubit, LikeAndDisLikeState>(
|
||||
bloc: context.read<LikeAndDisLikeCubit>(),
|
||||
listener: ((context, state) {
|
||||
if (state is LikeAndDisLikeFetchSuccess) {
|
||||
isLike = context.read<LikeAndDisLikeCubit>().isNewsLikeAndDisLike(model.newsId!);
|
||||
}
|
||||
}),
|
||||
builder: (context, likeAndDislikeState) {
|
||||
return BlocConsumer<UpdateLikeAndDisLikeStatusCubit, UpdateLikeAndDisLikeStatusState>(
|
||||
bloc: context.read<UpdateLikeAndDisLikeStatusCubit>(),
|
||||
listener: ((context, state) {
|
||||
if (state is UpdateLikeAndDisLikeStatusSuccess) {
|
||||
context.read<LikeAndDisLikeCubit>().getLike(langId: context.read<AppLocalizationCubit>().state.id);
|
||||
model.totalLikes = (!isLike)
|
||||
? (int.parse(model.totalLikes.toString()) + 1).toString()
|
||||
: (model.totalLikes!.isNotEmpty)
|
||||
? (int.parse(model.totalLikes.toString()) - 1).toString()
|
||||
: "0";
|
||||
}
|
||||
}),
|
||||
builder: (context, state) {
|
||||
isLike = context.read<LikeAndDisLikeCubit>().isNewsLikeAndDisLike(model.newsId!);
|
||||
return Positioned.directional(
|
||||
textDirection: Directionality.of(context),
|
||||
top: MediaQuery.of(context).size.height / 2.90,
|
||||
end: MediaQuery.of(context).size.width / 10.8,
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
if (state is UpdateLikeAndDisLikeStatusInProgress) {
|
||||
return;
|
||||
}
|
||||
context.read<UpdateLikeAndDisLikeStatusCubit>().setLikeAndDisLikeNews(news: model, status: (isLike) ? "0" : "1");
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(52.0),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 39,
|
||||
width: 39,
|
||||
decoration: BoxDecoration(boxShadow: [
|
||||
BoxShadow(blurRadius: 6, offset: const Offset(5.0, 5.0), color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.4), spreadRadius: 0),
|
||||
], color: secondaryColor, shape: BoxShape.circle),
|
||||
child: (state is UpdateLikeAndDisLikeStatusInProgress)
|
||||
? SizedBox(height: 20, width: 20, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: isLike
|
||||
? const Icon(Icons.thumb_up_alt, color: darkSecondaryColor)
|
||||
: const Icon(Icons.thumb_up_off_alt, color: darkSecondaryColor),
|
||||
))),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 7.5,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 5.0),
|
||||
child: CustomTextLabel(
|
||||
text: (int.tryParse(model.totalLikes!)! > 0) ? "${model.totalLikes!} ${UiUtils.getTranslatedLabel(context, 'likeLbl')}" : "",
|
||||
maxLines: 2,
|
||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
166
news-app/lib/ui/screens/NewsDetail/Widgets/relatedNewsList.dart
Normal file
166
news-app/lib/ui/screens/NewsDetail/Widgets/relatedNewsList.dart
Normal file
@@ -0,0 +1,166 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/cubits/relatedNewsCubit.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/ui/widgets/networkImage.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
|
||||
class RelatedNewsList extends StatefulWidget {
|
||||
final NewsModel model;
|
||||
|
||||
const RelatedNewsList({super.key, required this.model});
|
||||
|
||||
@override
|
||||
RelatedNewsListState createState() => RelatedNewsListState();
|
||||
}
|
||||
|
||||
class RelatedNewsListState extends State<RelatedNewsList> {
|
||||
int sliderIndex = 0;
|
||||
List<NewsModel> relatedList = [];
|
||||
|
||||
Widget getRelatedList() {
|
||||
return BlocConsumer<RelatedNewsCubit, RelatedNewsState>(
|
||||
bloc: context.read<RelatedNewsCubit>(),
|
||||
listener: (context, state) {
|
||||
if (state is RelatedNewsFetchSuccess) {
|
||||
setState(() {
|
||||
relatedList.clear();
|
||||
relatedList.addAll(state.relatedNews);
|
||||
relatedList.removeWhere((element) => (element.id == widget.model.id!) || (element.id == widget.model.newsId!));
|
||||
});
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is RelatedNewsFetchSuccess && relatedList.isNotEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 15.0, bottom: 15.0),
|
||||
child: Column(children: [
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(bottom: 15.0),
|
||||
child: CustomTextLabel(
|
||||
text: 'relatedNews',
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.w600)))),
|
||||
showRelatedNews(relatedList)
|
||||
]));
|
||||
}
|
||||
return const SizedBox.shrink(); //state is RelatedNewsFetchInProgress || state is RelatedNewsInitial || state is RelatedNewsFetchFailure
|
||||
});
|
||||
}
|
||||
|
||||
Widget relatedNewsData(NewsModel model, List<NewsModel> newsList) {
|
||||
return Stack(children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(15.0), topRight: Radius.circular(15.0)),
|
||||
child: ShaderMask(
|
||||
shaderCallback: (rect) => const LinearGradient(begin: Alignment.center, end: Alignment.bottomCenter, colors: [Colors.transparent, secondaryColor]).createShader(rect),
|
||||
blendMode: BlendMode.darken,
|
||||
child: GestureDetector(
|
||||
child: CustomNetworkImage(networkImageUrl: model.image!, width: double.maxFinite, height: MediaQuery.of(context).size.height / 2.9, isVideo: false, fit: BoxFit.cover),
|
||||
onTap: () {
|
||||
List<NewsModel> addNewsList = [];
|
||||
addNewsList.addAll(newsList);
|
||||
addNewsList.remove(model);
|
||||
UiUtils.showInterstitialAds(context: context);
|
||||
Navigator.of(context).pushNamed(Routes.newsDetails, arguments: {"model": model, "newsList": addNewsList, "isFromBreak": false, "fromShowMore": false});
|
||||
}))),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
padding: EdgeInsetsDirectional.only(bottom: MediaQuery.of(context).size.height / 18.9, start: MediaQuery.of(context).size.width / 20.0, end: 5.0),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: CustomTextLabel(
|
||||
text: model.title!,
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(color: secondaryColor, fontWeight: FontWeight.normal, fontSize: 12.5, height: 1.0),
|
||||
maxLines: 1,
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)))
|
||||
]);
|
||||
}
|
||||
|
||||
List<T> map<T>(List list, Function handler) {
|
||||
List<T> result = [];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
result.add(handler(i, list[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CustomTextLabel setCoverageText(BuildContext context) {
|
||||
return CustomTextLabel(
|
||||
text: 'viewFullCoverage',
|
||||
textAlign: TextAlign.center,
|
||||
textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.9), fontWeight: FontWeight.w600),
|
||||
);
|
||||
}
|
||||
|
||||
Icon setCoverageIcon(BuildContext context) {
|
||||
return Icon(Icons.image, color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.9));
|
||||
}
|
||||
|
||||
Widget showRelatedNews(List<NewsModel> relatedNews) {
|
||||
return Column(children: [
|
||||
Stack(children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2.9,
|
||||
width: double.infinity,
|
||||
child: PageView.builder(
|
||||
itemCount: relatedNews.length,
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
sliderIndex = index;
|
||||
});
|
||||
},
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return relatedNewsData(relatedNews[index], relatedNews);
|
||||
})),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: EdgeInsetsDirectional.only(top: MediaQuery.of(context).size.height / 3.3),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: map<Widget>(relatedNews, (index, url) {
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
width: sliderIndex == index ? MediaQuery.of(context).size.width / 15.0 : MediaQuery.of(context).size.width / 15.0,
|
||||
height: 5.0,
|
||||
margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
color: sliderIndex == index ? Theme.of(context).primaryColor : darkBackgroundColor.withOpacity(0.5),
|
||||
));
|
||||
}))))
|
||||
]),
|
||||
Container(
|
||||
height: 38.0,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(15.0), bottomRight: Radius.circular(15.0)),
|
||||
color: UiUtils.getColorScheme(context).surface,
|
||||
boxShadow: [BoxShadow(color: borderColor.withOpacity(0.4), offset: const Offset(0.0, 2.0), blurRadius: 6.0, spreadRadius: 0)]),
|
||||
child: ElevatedButton.icon(
|
||||
icon: setCoverageIcon(context),
|
||||
label: setCoverageText(context),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(Routes.showMoreRelatedNews, arguments: {"model": widget.model});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(foregroundColor: Theme.of(context).primaryColor, backgroundColor: Colors.transparent, shadowColor: Colors.transparent),
|
||||
))
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return getRelatedList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||
import 'package:unity_ads_plugin/unity_ads_plugin.dart' as unity;
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
|
||||
setBannerAd(BuildContext context, BannerAd? bannerAd) {
|
||||
if (context.read<AppConfigurationCubit>().bannerId() != "") {
|
||||
switch (context.read<AppConfigurationCubit>().checkAdsType()) {
|
||||
case "google":
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: 5.0, end: 5.0),
|
||||
child: SizedBox(width: double.maxFinite, height: bannerAd!.size.height.toDouble(), child: AdWidget(ad: bannerAd)),
|
||||
);
|
||||
|
||||
case "unity":
|
||||
return unity.UnityBannerAd(
|
||||
placementId: context.read<AppConfigurationCubit>().bannerId()!,
|
||||
onLoad: (placementId) => debugPrint('Banner loaded: $placementId'),
|
||||
onClick: (placementId) => debugPrint('Banner clicked: $placementId'),
|
||||
onFailed: (placementId, error, message) => debugPrint('Banner Ad $placementId failed: $error $message'),
|
||||
);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
}
|
||||
63
news-app/lib/ui/screens/NewsDetail/Widgets/tagView.dart
Normal file
63
news-app/lib/ui/screens/NewsDetail/Widgets/tagView.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
Widget tagView({required NewsModel model, required BuildContext context, bool? isFromDetailsScreen = false}) {
|
||||
List<String> tagList = [];
|
||||
|
||||
if (model.tagName! != "") {
|
||||
final tagName = model.tagName!;
|
||||
tagList = tagName.split(',');
|
||||
}
|
||||
|
||||
List<String> tagId = [];
|
||||
|
||||
if (model.tagId != null && model.tagId! != "") {
|
||||
tagId = model.tagId!.split(",");
|
||||
}
|
||||
|
||||
return model.tagName! != ""
|
||||
? Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 15.0),
|
||||
child: SizedBox(
|
||||
height: 20.0,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: List.generate(tagList.length, (index) {
|
||||
return Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: index == 0 ? 0 : 7),
|
||||
child: InkWell(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(3.0),
|
||||
child: (isFromDetailsScreen != null && isFromDetailsScreen)
|
||||
? tagsContainer(context: context, tagList: tagList, index: index)
|
||||
: BackdropFilter(filter: ImageFilter.blur(sigmaX: 30, sigmaY: 30), child: tagsContainer(context: context, tagList: tagList, index: index))),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(Routes.tagScreen, arguments: {"tagId": tagId[index], "tagName": tagList[index]});
|
||||
},
|
||||
));
|
||||
}),
|
||||
),
|
||||
)))
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
|
||||
Widget tagsContainer({required BuildContext context, required List<String> tagList, required int index}) {
|
||||
return Container(
|
||||
height: 20.0,
|
||||
width: 65,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsetsDirectional.only(start: 3.0, end: 3.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(10.0), bottomRight: Radius.circular(10.0)), color: UiUtils.getColorScheme(context).primaryContainer.withOpacity(0.7)),
|
||||
child: CustomTextLabel(
|
||||
text: tagList[index],
|
||||
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).secondary, fontSize: 11),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
Widget titleView({required String title, required BuildContext context}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(top: 6.0),
|
||||
child: CustomTextLabel(text: title, textStyle: Theme.of(context).textTheme.titleMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontWeight: FontWeight.w600)));
|
||||
}
|
||||
24
news-app/lib/ui/screens/NewsDetail/Widgets/videoBtn.dart
Normal file
24
news-app/lib/ui/screens/NewsDetail/Widgets/videoBtn.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
|
||||
Widget videoBtn({required BuildContext context, required bool isFromBreak, NewsModel? model, BreakingNewsModel? breakModel}) {
|
||||
if ((breakModel != null && breakModel.contentValue != "") || model != null && model.contentValue != "") {
|
||||
return Positioned.directional(
|
||||
textDirection: Directionality.of(context),
|
||||
top: 35,
|
||||
end: 20.0,
|
||||
child: InkWell(
|
||||
child:
|
||||
Container(height: 39, width: 39, decoration: const BoxDecoration(color: secondaryColor, shape: BoxShape.circle), child: const Icon(Icons.play_arrow_rounded, color: darkSecondaryColor)),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.newsVideo, arguments: (!isFromBreak) ? {"from": 1, "model": model} : {"from": 3, "breakModel": breakModel, "otherVideos": [], "otherBreakingVideos": []});
|
||||
},
|
||||
));
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user