elCaribe app - customization and branding
This commit is contained in:
229
news-app/lib/ui/screens/Videos/VideoScreen.dart
Normal file
229
news-app/lib/ui/screens/Videos/VideoScreen.dart
Normal file
@@ -0,0 +1,229 @@
|
||||
import 'package:news/data/repositories/Settings/settingsLocalDataRepository.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/cubits/appSystemSettingCubit.dart';
|
||||
import 'package:news/cubits/videosCubit.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
import 'package:news/ui/widgets/customAppBar.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/ui/widgets/errorContainerWidget.dart';
|
||||
import 'package:news/ui/widgets/networkImage.dart';
|
||||
import 'package:news/ui/widgets/videoItem.dart';
|
||||
import 'package:news/utils/ErrorMessageKeys.dart';
|
||||
import 'package:news/utils/constant.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
class VideoScreen extends StatefulWidget {
|
||||
const VideoScreen({super.key});
|
||||
|
||||
@override
|
||||
VideoScreenState createState() => VideoScreenState();
|
||||
|
||||
static Route<dynamic> route(RouteSettings routeSettings) {
|
||||
return CupertinoPageRoute(builder: (_) => const VideoScreen());
|
||||
}
|
||||
}
|
||||
|
||||
class VideoScreenState extends State<VideoScreen> {
|
||||
late final PageController _videoScrollController = PageController()..addListener(hasMoreVideoScrollListener);
|
||||
|
||||
int currentIndex = 0;
|
||||
int totalItems = 0;
|
||||
String? initializedVideoId;
|
||||
late String latitude, longitude;
|
||||
VideoViewType? videoViewType;
|
||||
void getVideos() {
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<VideoCubit>().getVideo(langId: context.read<AppLocalizationCubit>().state.id, latitude: latitude, longitude: longitude);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
videoViewType = context.read<AppConfigurationCubit>().getVideoTypePreference();
|
||||
|
||||
setLatitudeLongitude();
|
||||
getVideos();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_videoScrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void setLatitudeLongitude() {
|
||||
latitude = SettingsLocalDataRepository().getLocationCityValues().first;
|
||||
longitude = SettingsLocalDataRepository().getLocationCityValues().last;
|
||||
}
|
||||
|
||||
void hasMoreVideoScrollListener() {
|
||||
if (_videoScrollController.offset >= _videoScrollController.position.maxScrollExtent && !_videoScrollController.position.outOfRange) {
|
||||
if (context.read<VideoCubit>().hasMoreVideo()) {
|
||||
context.read<VideoCubit>().getMoreVideo(langId: context.read<AppLocalizationCubit>().state.id, latitude: latitude, longitude: longitude);
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(appBar: CustomAppBar(height: 44, isBackBtn: false, label: 'videosLbl', isConvertText: true), body: _buildVideos(videoViewType ?? VideoViewType.normal));
|
||||
}
|
||||
|
||||
Widget _buildVideos(VideoViewType type) {
|
||||
return BlocBuilder<VideoCubit, VideoState>(builder: (context, state) {
|
||||
if (state is VideoFetchSuccess) {
|
||||
totalItems = state.video.length;
|
||||
if (type == VideoViewType.page) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
getVideos();
|
||||
},
|
||||
child: PageView.builder(
|
||||
controller: _videoScrollController,
|
||||
scrollDirection: Axis.vertical,
|
||||
physics: PageScrollPhysics(),
|
||||
itemCount: totalItems,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildVideoContainer(
|
||||
video: state.video[index], hasMore: state.hasMore, hasMoreVideoFetchError: state.hasMoreFetchError, index: index, totalCurrentVideo: state.video.length);
|
||||
}));
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 15.0),
|
||||
child: ListView.separated(
|
||||
controller: _videoScrollController,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildHorizontalViewContainer(videosList: state.video, video: state.video[index], index: index, totalCurrentVideo: state.video.length);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return SizedBox(height: 16);
|
||||
},
|
||||
itemCount: state.video.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (state is VideoFetchFailure) {
|
||||
return ErrorContainerWidget(errorMsg: (state.errorMessage.contains(ErrorMessageKeys.noInternet)) ? UiUtils.getTranslatedLabel(context, 'internetmsg') : state.errorMessage, onRetry: getVideos);
|
||||
}
|
||||
return SizedBox.shrink();
|
||||
});
|
||||
}
|
||||
|
||||
_buildVideoContainer({required NewsModel video, required int index, required int totalCurrentVideo, required bool hasMoreVideoFetchError, required bool hasMore}) {
|
||||
if (index == totalCurrentVideo - 1 && index != 0) {
|
||||
if (hasMore) {
|
||||
if (hasMoreVideoFetchError) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.0),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
context.read<VideoCubit>().getMoreVideo(
|
||||
langId: context.read<AppLocalizationCubit>().state.id,
|
||||
latitude: SettingsLocalDataRepository().getLocationCityValues().first,
|
||||
longitude: SettingsLocalDataRepository().getLocationCityValues().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 VideoItem(model: video);
|
||||
}
|
||||
|
||||
Widget _buildHorizontalViewContainer({required List<NewsModel> videosList, required NewsModel video, required int index, required int totalCurrentVideo}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: VideoNewsCard(
|
||||
video: video,
|
||||
videosList: videosList,
|
||||
onInitializeVideo: () {
|
||||
initializedVideoId = video.id;
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoNewsCard extends StatefulWidget {
|
||||
final NewsModel video;
|
||||
final List<NewsModel> videosList;
|
||||
const VideoNewsCard({super.key, required this.videosList, required this.video, required this.onInitializeVideo});
|
||||
final void Function() onInitializeVideo;
|
||||
|
||||
@override
|
||||
VideoNewsCardState createState() => VideoNewsCardState();
|
||||
}
|
||||
|
||||
class VideoNewsCardState extends State<VideoNewsCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(color: UiUtils.getColorScheme(context).surface, borderRadius: BorderRadius.circular(8)),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
List<NewsModel> videosList = List.from(widget.videosList)..removeWhere((x) => x.id == widget.video.id);
|
||||
Navigator.of(context).pushNamed(Routes.newsVideo, arguments: {"from": 1, "model": widget.video, "otherVideos": videosList});
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 8,
|
||||
children: [
|
||||
Container(height: 192, color: borderColor, child: _buildThumbnail()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 8,
|
||||
children: [
|
||||
CustomTextLabel(text: widget.video.title!, textStyle: TextStyle(fontWeight: FontWeight.bold)),
|
||||
if (widget.video.date != null && widget.video.date!.isNotEmpty)
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [Icon(Icons.calendar_month_rounded), CustomTextLabel(text: UiUtils.formatDate(widget.video.date ?? ''))],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildThumbnail() {
|
||||
return Container(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
ShaderMask(
|
||||
shaderCallback: (rect) =>
|
||||
LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [darkSecondaryColor.withOpacity(0.6), darkSecondaryColor.withOpacity(0.6)]).createShader(rect),
|
||||
blendMode: BlendMode.darken,
|
||||
child: Container(
|
||||
color: primaryColor.withAlpha(5),
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height / 3.3,
|
||||
child: CustomNetworkImage(width: double.maxFinite, networkImageUrl: widget.video.image ?? ''),
|
||||
)),
|
||||
Center(
|
||||
child: Icon(Icons.play_circle_outline_rounded, size: 50, color: backgroundColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
93
news-app/lib/ui/screens/Videos/Widgets/otherVideosCard.dart
Normal file
93
news-app/lib/ui/screens/Videos/Widgets/otherVideosCard.dart
Normal file
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:news/app/routes.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/data/models/LiveStreamingModel.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/ui/widgets/networkImage.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
class OtherVideosCard extends StatelessWidget {
|
||||
final NewsModel? model;
|
||||
final BreakingNewsModel? brModel;
|
||||
final LiveStreamingModel? liveModel;
|
||||
OtherVideosCard({super.key, this.model, this.brModel, this.liveModel});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isLive = liveModel != null;
|
||||
return InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
bool isNews = (model != null) ? true : false;
|
||||
bool isBreakingNews = (brModel != null) ? true : false;
|
||||
int fromVal = (isNews) ? 1 : (isBreakingNews ? 2 : 3); // VAL 1 = news, 2 = liveNews , 3 = breakingNews
|
||||
// and pass current model accordingly.Do not pass other videos - set it from newsVideo screen only
|
||||
Map<String, dynamic> videoArguments = {"from": fromVal};
|
||||
if (fromVal == 1) {
|
||||
videoArguments.addAll({"model": model});
|
||||
} else if (fromVal == 2) {
|
||||
videoArguments.addAll({"brModel": brModel});
|
||||
} else {
|
||||
videoArguments.addAll({"liveModel": liveModel});
|
||||
}
|
||||
Navigator.pushReplacementNamed(context, Routes.newsVideo, arguments: videoArguments);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: BoxDecoration(color: UiUtils.getColorScheme(context).surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: dividerColor.withAlpha(70))),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: CustomNetworkImage(
|
||||
networkImageUrl: (isLive)
|
||||
? liveModel!.image!
|
||||
: (model != null)
|
||||
? model!.image!
|
||||
: brModel!.image!,
|
||||
height: 60,
|
||||
width: 90,
|
||||
fit: BoxFit.cover)),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(!isLive && (model != null && model!.categoryName != null && model!.categoryName!.isNotEmpty))
|
||||
? Container(
|
||||
height: 25.0,
|
||||
width: 65,
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsetsDirectional.only(start: 2.0, end: 2.0, top: 1.0, bottom: 1.0),
|
||||
decoration: BoxDecoration(
|
||||
color: UiUtils.getColorScheme(context).onPrimary.withAlpha(40),
|
||||
border: Border.all(color: UiUtils.getColorScheme(context).secondary.withOpacity(0.85)),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
child: CustomTextLabel(
|
||||
text: model!.categoryName ?? "",
|
||||
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).onPrimary, fontWeight: FontWeight.bold, fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true))
|
||||
: SizedBox.shrink(),
|
||||
SizedBox(height: 4),
|
||||
CustomTextLabel(
|
||||
text: (isLive)
|
||||
? liveModel!.title!
|
||||
: (model != null)
|
||||
? model!.title ?? ""
|
||||
: brModel!.title ?? "",
|
||||
textStyle: TextStyle(color: UiUtils.getColorScheme(context).onPrimary),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
271
news-app/lib/ui/screens/Videos/Widgets/videoCard.dart
Normal file
271
news-app/lib/ui/screens/Videos/Widgets/videoCard.dart
Normal file
@@ -0,0 +1,271 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:news/ui/styles/colors.dart';
|
||||
import 'package:news/app/routes.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/LikeAndDislikeNews/LikeAndDislikeCubit.dart';
|
||||
import 'package:news/cubits/LikeAndDislikeNews/updateLikeAndDislikeCubit.dart';
|
||||
import 'package:news/cubits/appLocalizationCubit.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/data/models/LiveStreamingModel.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/data/repositories/Bookmark/bookmarkRepository.dart';
|
||||
import 'package:news/data/repositories/LikeAndDisLikeNews/LikeAndDisLikeNewsRepository.dart';
|
||||
import 'package:news/ui/widgets/SnackBarWidget.dart';
|
||||
import 'package:news/ui/widgets/customTextLabel.dart';
|
||||
import 'package:news/ui/widgets/videoPlayContainer.dart';
|
||||
import 'package:news/utils/internetConnectivity.dart';
|
||||
import 'package:news/utils/strings.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
class VideoCard extends StatefulWidget {
|
||||
final NewsModel? model;
|
||||
final BreakingNewsModel? brModel;
|
||||
final LiveStreamingModel? liveModel;
|
||||
VideoCard({super.key, this.model, this.liveModel, this.brModel});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => VideoCardState();
|
||||
}
|
||||
|
||||
class VideoCardState extends State<VideoCard> {
|
||||
late NewsModel? model;
|
||||
late BreakingNewsModel? brModel;
|
||||
late LiveStreamingModel? liveModel;
|
||||
bool isLiveVideo = false, isBreakingVideo = false;
|
||||
List<String>? tagList = [];
|
||||
List<String>? tagId = [];
|
||||
String formattedDate = "", contentType = "", contentValue = "", titleTxt = "";
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
model = widget.model;
|
||||
brModel = widget.brModel;
|
||||
liveModel = widget.liveModel;
|
||||
isLiveVideo = (liveModel != null);
|
||||
isBreakingVideo = (brModel != null);
|
||||
setFormattedDate();
|
||||
setTitle();
|
||||
setContentValueAndContentType();
|
||||
setTags();
|
||||
}
|
||||
|
||||
void setTitle() {
|
||||
titleTxt = (isLiveVideo)
|
||||
? liveModel?.title ?? ""
|
||||
: (isBreakingVideo)
|
||||
? brModel?.title ?? ""
|
||||
: model?.title ?? "";
|
||||
}
|
||||
|
||||
void setTags() {
|
||||
if (model != null && model?.tagName != null && (model!.sourceType != null && model!.sourceType != BREAKING_NEWS)) {
|
||||
if (model?.tagId != null && model!.tagId!.isNotEmpty) {
|
||||
tagId = model?.tagId?.split(",");
|
||||
}
|
||||
|
||||
if (model!.tagName!.isNotEmpty) {
|
||||
final tagName = model?.tagName!;
|
||||
tagList = tagName?.split(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setFormattedDate() {
|
||||
String dateVal = (isLiveVideo) ? liveModel!.updatedDate ?? "" : (model?.publishDate ?? model?.date ?? "");
|
||||
if (dateVal.isNotEmpty) {
|
||||
DateTime parsedDate = DateFormat("yyyy-MM-dd").parse(dateVal);
|
||||
formattedDate = DateFormat("MMM dd, yyyy").format(parsedDate);
|
||||
}
|
||||
}
|
||||
|
||||
void setContentValueAndContentType() {
|
||||
contentType = (isLiveVideo) ? liveModel?.type ?? "" : ((model != null) ? model?.contentType ?? "" : brModel!.contentType ?? "");
|
||||
contentValue = (isLiveVideo)
|
||||
? liveModel?.url ?? ""
|
||||
: (model != null)
|
||||
? model?.contentValue ?? ""
|
||||
: brModel!.contentValue ?? "";
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget likeButton() {
|
||||
bool isLike = context.read<LikeAndDisLikeCubit>().isNewsLikeAndDisLike(widget.model?.newsId ?? "0");
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => UpdateLikeAndDisLikeStatusCubit(LikeAndDisLikeRepository()),
|
||||
child: BlocConsumer<LikeAndDisLikeCubit, LikeAndDisLikeState>(
|
||||
bloc: context.read<LikeAndDisLikeCubit>(),
|
||||
listener: ((context, state) {
|
||||
if (state is LikeAndDisLikeFetchSuccess) {
|
||||
isLike = context.read<LikeAndDisLikeCubit>().isNewsLikeAndDisLike(model?.newsId ?? "0");
|
||||
} else {
|
||||
isLike = false; //in case of failue - no other likes found
|
||||
}
|
||||
}),
|
||||
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);
|
||||
}
|
||||
}),
|
||||
builder: (context, state) {
|
||||
return InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
if (context.read<AuthCubit>().getUserId() != "0") {
|
||||
if (state is UpdateLikeAndDisLikeStatusInProgress) {
|
||||
return;
|
||||
}
|
||||
context.read<UpdateLikeAndDisLikeStatusCubit>().setLikeAndDisLikeNews(news: model ?? NewsModel(), status: (isLike) ? "0" : "1");
|
||||
} else {
|
||||
UiUtils.loginRequired(context);
|
||||
}
|
||||
},
|
||||
child: designButtons(
|
||||
childWidget: (state is UpdateLikeAndDisLikeStatusInProgress)
|
||||
? SizedBox(height: 15, width: 15, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: ((isLike)
|
||||
? Icon(Icons.thumb_up_alt, size: 25, color: UiUtils.getColorScheme(context).onPrimary)
|
||||
: Icon(Icons.thumb_up_off_alt, size: 25, color: UiUtils.getColorScheme(context).onPrimary))));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: UiUtils.getColorScheme(context).surface, borderRadius: BorderRadius.circular(12)),
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: AspectRatio(aspectRatio: 16 / 9, child: VideoPlayContainer(contentType: contentType, contentValue: contentValue)),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
(model != null && model!.sourceType != BREAKING_NEWS)
|
||||
? Wrap(
|
||||
spacing: 8,
|
||||
children: tagList!
|
||||
.map((tag) => tag.trim())
|
||||
.where((tag) => tag.isNotEmpty)
|
||||
.map(
|
||||
(tag) => InkWell(
|
||||
onTap: () async {
|
||||
Navigator.of(context).pushNamed(Routes.tagScreen, arguments: {"tagId": tagId, "tagName": tagList});
|
||||
},
|
||||
child: Container(
|
||||
height: 25.0,
|
||||
width: 65,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsetsDirectional.only(start: 3.0, end: 3.0, top: 1.0, bottom: 1.0),
|
||||
decoration: BoxDecoration(borderRadius: const BorderRadius.all(Radius.circular(15)), color: UiUtils.getColorScheme(context).secondary.withOpacity(0.85)),
|
||||
child: CustomTextLabel(
|
||||
text: tag,
|
||||
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: UiUtils.getColorScheme(context).primaryContainer, fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true)),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
const SizedBox(height: 10),
|
||||
CustomTextLabel(text: titleTxt, textStyle: TextStyle(color: UiUtils.getColorScheme(context).onPrimary)),
|
||||
const SizedBox(height: 10),
|
||||
Divider(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
(formattedDate.isNotEmpty)
|
||||
? Row(
|
||||
children: [
|
||||
Icon(Icons.calendar_month_rounded, size: 20),
|
||||
SizedBox(width: 4),
|
||||
CustomTextLabel(text: formattedDate, textStyle: TextStyle(fontSize: 12, color: UiUtils.getColorScheme(context).onPrimary)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
Row(
|
||||
children: [
|
||||
if ((model?.sourceType != null && model?.newsId != null || model?.id != null) || (model?.sourceType == NEWS || model?.sourceType == VIDEOS))
|
||||
Row(children: [
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
(await InternetConnectivity.isNetworkAvailable())
|
||||
? UiUtils.shareNews(
|
||||
context: context, slug: model?.slug ?? "", title: model?.title ?? "", isVideo: true, videoId: model?.id ?? "0", isBreakingNews: false, isNews: false)
|
||||
: showSnackBar(UiUtils.getTranslatedLabel(context, 'internetmsg'), context);
|
||||
},
|
||||
splashColor: Colors.transparent,
|
||||
child: designButtons(childWidget: Icon(Icons.share_rounded, color: UiUtils.getColorScheme(context).onPrimary))),
|
||||
const SizedBox(height: 15),
|
||||
BlocProvider(
|
||||
create: (context) => UpdateBookmarkStatusCubit(BookmarkRepository()),
|
||||
child: BlocBuilder<BookmarkCubit, BookmarkState>(
|
||||
bloc: context.read<BookmarkCubit>(),
|
||||
builder: (context, bookmarkState) {
|
||||
bool isBookmark = context.read<BookmarkCubit>().isNewsBookmark(model?.id ?? "0");
|
||||
return BlocConsumer<UpdateBookmarkStatusCubit, UpdateBookmarkStatusState>(
|
||||
bloc: context.read<UpdateBookmarkStatusCubit>(),
|
||||
listener: ((context, state) {
|
||||
if (state is UpdateBookmarkStatusSuccess) {
|
||||
(state.wasBookmarkNewsProcess) ? context.read<BookmarkCubit>().addBookmarkNews(state.news) : context.read<BookmarkCubit>().removeBookmarkNews(state.news);
|
||||
setState(() {});
|
||||
}
|
||||
}),
|
||||
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: state is UpdateBookmarkStatusInProgress
|
||||
? SizedBox(height: 15, width: 15, child: UiUtils.showCircularProgress(true, Theme.of(context).primaryColor))
|
||||
: designButtons(
|
||||
childWidget: Icon(isBookmark ? Icons.bookmark_added_rounded : Icons.bookmark_add_outlined, color: UiUtils.getColorScheme(context).onPrimary)));
|
||||
});
|
||||
}),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
likeButton()
|
||||
]),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget designButtons({required Widget childWidget}) {
|
||||
return Container(
|
||||
height: 30,
|
||||
width: 30,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5),
|
||||
padding: EdgeInsets.all(3),
|
||||
decoration: BoxDecoration(shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(7), color: borderColor.withOpacity(0.2)),
|
||||
child: childWidget);
|
||||
}
|
||||
}
|
||||
104
news-app/lib/ui/screens/Videos/videoDetailsScreen.dart
Normal file
104
news-app/lib/ui/screens/Videos/videoDetailsScreen.dart
Normal file
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:news/data/models/BreakingNewsModel.dart';
|
||||
import 'package:news/data/models/LiveStreamingModel.dart';
|
||||
import 'package:news/data/models/NewsModel.dart';
|
||||
import 'package:news/ui/screens/Videos/Widgets/otherVideosCard.dart';
|
||||
import 'package:news/ui/screens/Videos/Widgets/videoCard.dart';
|
||||
import 'package:news/ui/widgets/customAppBar.dart';
|
||||
import 'package:news/utils/uiUtils.dart';
|
||||
|
||||
class VideoDetailsScreen extends StatefulWidget {
|
||||
int from;
|
||||
LiveStreamingModel? liveModel;
|
||||
NewsModel? model;
|
||||
BreakingNewsModel? breakModel;
|
||||
List<NewsModel>? otherVideos;
|
||||
List<BreakingNewsModel>? otherBreakingVideos;
|
||||
List<LiveStreamingModel>? otherLiveVideos;
|
||||
|
||||
VideoDetailsScreen({super.key, this.model, required this.from, this.liveModel, this.breakModel, required this.otherVideos, this.otherLiveVideos, this.otherBreakingVideos});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => VideoDetailsState();
|
||||
|
||||
static Route route(RouteSettings routeSettings) {
|
||||
final arguments = routeSettings.arguments as Map<String, dynamic>;
|
||||
return CupertinoPageRoute(
|
||||
builder: (_) => VideoDetailsScreen(
|
||||
from: arguments['from'],
|
||||
liveModel: arguments['liveModel'],
|
||||
model: arguments['model'],
|
||||
breakModel: arguments['breakModel'],
|
||||
otherVideos: arguments['otherVideos'],
|
||||
otherLiveVideos: arguments['otherLiveVideos'],
|
||||
otherBreakingVideos: arguments['otherBreakingVideos']));
|
||||
}
|
||||
}
|
||||
|
||||
class VideoDetailsState extends State<VideoDetailsScreen> {
|
||||
bool isLiveVideo = false, isBreakingNewsVideo = false, isNewsVideo = true;
|
||||
//FROM VAL 1 = news, 2 = liveNews , 3 = breakingNews
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
isLiveVideo = (widget.from == 2);
|
||||
isBreakingNewsVideo = (widget.from == 3);
|
||||
isNewsVideo = !(isLiveVideo || isBreakingNewsVideo);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// set screen back to portrait mode
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: UiUtils.getColorScheme(context).surface,
|
||||
appBar: CustomAppBar(height: 45, isBackBtn: true, label: 'videosLbl', isConvertText: true),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
VideoCard(
|
||||
model: (widget.model != null) ? widget.model : null, brModel: (widget.breakModel != null) ? widget.breakModel : null, liveModel: (widget.liveModel != null) ? widget.liveModel : null),
|
||||
const SizedBox(height: 16),
|
||||
((isLiveVideo && widget.otherLiveVideos != null && widget.otherLiveVideos!.isNotEmpty) ||
|
||||
((widget.otherVideos != null && widget.otherVideos!.isNotEmpty) || (widget.otherBreakingVideos != null && widget.otherBreakingVideos!.isNotEmpty)))
|
||||
? Text(
|
||||
UiUtils.getTranslatedLabel(context, 'recentVidLbl'),
|
||||
style: TextStyle(color: UiUtils.getColorScheme(context).onPrimary, fontWeight: FontWeight.bold, fontSize: 18),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
const SizedBox(height: 8),
|
||||
((isLiveVideo && widget.otherLiveVideos != null && widget.otherLiveVideos!.isNotEmpty) ||
|
||||
((widget.otherVideos != null && widget.otherVideos!.isNotEmpty) || (widget.otherBreakingVideos != null && widget.otherBreakingVideos!.isNotEmpty)))
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: (isLiveVideo)
|
||||
? widget.otherLiveVideos!.length
|
||||
: (widget.otherVideos != null && widget.otherVideos!.isNotEmpty)
|
||||
? widget.otherVideos!.length
|
||||
: widget.otherBreakingVideos!.length,
|
||||
itemBuilder: (context, index) => OtherVideosCard(
|
||||
brModel: (widget.otherBreakingVideos != null && widget.otherBreakingVideos!.isNotEmpty) ? widget.otherBreakingVideos![index] : null,
|
||||
model: (widget.otherVideos != null && widget.otherVideos!.isNotEmpty) ? widget.otherVideos![index] : null,
|
||||
liveModel: (widget.otherLiveVideos != null && widget.otherLiveVideos!.isNotEmpty) ? widget.otherLiveVideos![index] : null),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user