elCaribe app - customization and branding

This commit is contained in:
2025-12-12 19:09:42 -04:00
parent 9e5d0d8ebf
commit ba7deac9f3
402 changed files with 31833 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:news/utils/constant.dart';
import 'package:news/utils/uiUtils.dart';
import 'package:news/utils/internetConnectivity.dart';
import 'package:unity_ads_plugin/unity_ads_plugin.dart';
import 'package:news/data/models/NewsModel.dart';
import 'package:news/ui/screens/NewsDetail/Widgets/InterstitialAds/googleInterstitialAds.dart';
import 'package:news/ui/screens/NewsDetail/Widgets/InterstitialAds/unityInterstitialAds.dart';
import 'package:news/ui/screens/NewsDetail/Widgets/RerwardAds/googleRewardAds.dart';
import 'package:news/ui/screens/NewsDetail/Widgets/RerwardAds/unityRewardAds.dart';
import 'package:news/ui/screens/NewsDetail/Widgets/NewsSubDetailsScreen.dart';
import 'package:news/cubits/appSystemSettingCubit.dart';
import 'package:news/data/models/BreakingNewsModel.dart';
class NewsDetailScreen extends StatefulWidget {
final NewsModel? model;
final List<NewsModel>? newsList;
final BreakingNewsModel? breakModel;
final List<BreakingNewsModel>? breakNewsList;
final bool isFromBreak;
final bool fromShowMore;
final String? slug;
const NewsDetailScreen({super.key, this.model, this.breakModel, this.breakNewsList, this.newsList, this.slug, required this.isFromBreak, required this.fromShowMore});
@override
NewsDetailsState createState() => NewsDetailsState();
static Route route(RouteSettings routeSettings) {
final arguments = routeSettings.arguments as Map<String, dynamic>;
return CupertinoPageRoute(
builder: (_) => NewsDetailScreen(
model: arguments['model'],
breakModel: arguments['breakModel'],
breakNewsList: arguments['breakNewsList'],
newsList: arguments['newsList'],
isFromBreak: arguments['isFromBreak'],
fromShowMore: arguments['fromShowMore'],
slug: arguments['slug']));
}
}
class NewsDetailsState extends State<NewsDetailScreen> {
final PageController pageController = PageController();
bool isScrollLocked = false;
void _setScrollLock(bool lock) {
setState(() {
isScrollLocked = lock;
});
}
@override
void initState() {
if (context.read<AppConfigurationCubit>().getInAppAdsMode() == "1") {
if (context.read<AppConfigurationCubit>().checkAdsType() == "google") {
createGoogleInterstitialAd(context);
createGoogleRewardedAd(context);
} else {
if (context.read<AppConfigurationCubit>().unityGameId() != null) {
UnityAds.init(
gameId: context.read<AppConfigurationCubit>().unityGameId()!,
testMode: true, //set it to False @Deployement
onComplete: () {
loadUnityInterAd(context.read<AppConfigurationCubit>().interstitialId()!);
loadUnityRewardAd(context.read<AppConfigurationCubit>().rewardId()!);
},
onFailed: (error, message) => debugPrint('Initialization Failed: $error $message'),
);
}
}
}
super.initState();
}
Widget showBreakingNews() {
return PageView.builder(
controller: pageController,
onPageChanged: (index) async {
if (await InternetConnectivity.isNetworkAvailable()) {
if (index % rewardAdsIndex == 0) showRewardAds();
if (index % interstitialAdsIndex == 0) UiUtils.showInterstitialAds(context: context);
}
},
itemCount: (widget.breakNewsList == null || widget.breakNewsList!.isEmpty) ? 1 : widget.breakNewsList!.length + 1,
itemBuilder: (context, index) {
return NewsSubDetails(
onLockScroll: (p0) {}, //no change for breaking news , No comments widget
breakModel: (index == 0) ? widget.breakModel : widget.breakNewsList![index - 1],
fromShowMore: widget.fromShowMore,
isFromBreak: widget.isFromBreak,
model: widget.model);
});
}
void showRewardAds() {
if (context.read<AppConfigurationCubit>().getInAppAdsMode() == "1") {
if (context.read<AppConfigurationCubit>().checkAdsType() == "google") {
showGoogleRewardedAd(context);
} else {
showUnityRewardAds(context.read<AppConfigurationCubit>().rewardId()!);
}
}
}
Widget showNews() {
return PageView.builder(
controller: pageController,
physics: isScrollLocked ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(),
onPageChanged: (index) async {
if (await InternetConnectivity.isNetworkAvailable()) {
if (index % rewardAdsIndex == 0) showRewardAds();
if (index % interstitialAdsIndex == 0) UiUtils.showInterstitialAds(context: context);
}
},
itemCount: (widget.newsList == null || widget.newsList!.isEmpty) ? 1 : widget.newsList!.length + 1,
itemBuilder: (context, index) {
return NewsSubDetails(
onLockScroll: _setScrollLock,
model: (index == 0) ? widget.model : widget.newsList![index - 1],
fromShowMore: widget.fromShowMore,
isFromBreak: widget.isFromBreak,
breakModel: widget.breakModel);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: UiUtils.getColorScheme(context).secondary, body: widget.isFromBreak ? showBreakingNews() : showNews());
}
}

View 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());
}
}

View 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()]);
}
}

View File

@@ -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;
}

View File

@@ -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);
},
);
}

View File

@@ -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))
]),
),
);
}
}

View 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());
}
}

View File

@@ -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;
}
}

View File

@@ -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);
},
);
}

View 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));
},
),
);
}
}

View 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);
}));
}

View 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))
],
);
}

View 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)));
})
],
),
],
)));
});
}

View File

@@ -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)));
})
],
),
],
)));
});
}

View 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;
},
));
}

View File

@@ -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)))
],
);
}

View 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)),
),
),
)
],
));
});
});
}

View 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();
}
}

View File

@@ -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();
}
}
}

View 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));
}

View File

@@ -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)));
}

View 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();
}
}