Created
February 17, 2023 05:29
-
-
Save readmycodetanos/064a45703b672718d9ce1deaaa718fcc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:cached_network_image/cached_network_image.dart'; | |
import 'package:easy_localization/easy_localization.dart'; | |
import 'package:fleamarket/generated/assets.dart'; | |
import 'package:fleamarket/src/features/photo/photo_view.dart'; | |
import 'package:fleamarket/src/features/profile/my_profile_detail/user_profile_detail_view.dart'; | |
import 'package:fleamarket/src/models/data_artical_entity.dart'; | |
import 'package:fleamarket/src/resources/repository/UserRepository.dart'; | |
import 'package:fleamarket/src/util/googleutil/GoogleMapUtil.dart'; | |
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_spinkit/flutter_spinkit.dart'; | |
import 'package:photo_view/photo_view.dart'; | |
import 'package:photo_view/photo_view_gallery.dart'; | |
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |
import 'package:smooth_page_indicator/smooth_page_indicator.dart'; | |
import 'artical_detail_bloc.dart'; | |
import 'artical_detail_event.dart'; | |
import 'artical_detail_state.dart'; | |
class ArticalDetailPage extends StatefulWidget { | |
final DataArticalEntity item; | |
const ArticalDetailPage(this.item, {Key? key}) : super(key: key); | |
@override | |
State<ArticalDetailPage> createState() => _ArticalDetailPageState(this.item); | |
} | |
class _ArticalDetailPageState extends State<ArticalDetailPage> | |
with AutomaticKeepAliveClientMixin { | |
final DataArticalEntity item; | |
_ArticalDetailPageState(this.item); | |
@override | |
Widget build(BuildContext context) { | |
return BlocProvider( | |
create: (BuildContext context) => | |
ArticalDetailBloc()..add(InitEvent(item.aid, context)), | |
child: Builder(builder: (context) => _buildPage(context)), | |
); | |
} | |
// final RefreshController _refreshController = | |
// RefreshController(initialRefresh: false); | |
@override | |
void initState() { | |
super.initState(); | |
pageController = PageController(initialPage: 0); | |
} | |
@override | |
void dispose() { | |
pageController.dispose(); | |
super.dispose(); | |
} | |
late PageController pageController; | |
Widget _buildPage(BuildContext context) { | |
final bloc = BlocProvider.of<ArticalDetailBloc>(context); | |
return BlocBuilder<ArticalDetailBloc, ArticalDetailState>( | |
builder: (context, state) { | |
return Scaffold( | |
body: SafeArea( | |
child: Stack( | |
children: [ | |
Positioned(top:0,child: _buildDetail(context, state)), | |
Positioned(top: 12, child: _buildToolbar(context)), | |
Positioned(bottom: 0, child: _buildUserInfo(context,state)), | |
// Positioned(bottom: 54, child: _buildUserInfo(context, state)) | |
], | |
), | |
), | |
); | |
}, | |
); | |
} | |
Widget _buildUserInfo(BuildContext context, ArticalDetailState state) { | |
if(state.detailData==null){ | |
return const SizedBox(height: 54); | |
} | |
return SizedBox( | |
height: 54, | |
width: MediaQuery.of(context).size.width, | |
child: Container( | |
color: Colors.white, | |
child: Stack( | |
alignment: AlignmentDirectional.centerStart, | |
children: [ | |
Positioned( | |
left: 16, | |
child: | |
state.detailData!.user.photoUrl.isEmpty ? Image.asset(Assets.imagesUserPh,height: 38,width: 38,fit: BoxFit.fill,) : SizedBox( | |
width: 38, | |
height: 38, | |
child: Container( | |
width: 38, | |
height: 38, | |
decoration: BoxDecoration( | |
shape: BoxShape.circle, | |
image: DecorationImage(image:CachedNetworkImageProvider( | |
state.detailData!.user.photoUrl), | |
fit: BoxFit.fill) | |
), ), | |
), | |
), | |
Positioned(left: 62, top: 6,child:Text(state.detailData!.user.nick,style: const TextStyle(fontWeight: FontWeight.bold,fontSize: 16,color: Color.fromRGBO(34, 34, 34, 1))) ,), | |
Positioned(left: 62,top: 29,child: Row( | |
mainAxisSize: MainAxisSize.min, | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: [ | |
Image.asset(Assets.imagesStar,height: 14,fit: BoxFit.fitHeight,), | |
const SizedBox(width: 7,), | |
Text("${state.detailData!.user.reviewAvg} (${state.detailData!.user.reviewCount})",style: const TextStyle(fontWeight: FontWeight.bold,fontSize: 14,color: Color.fromRGBO(51, 72, 86, 1)),) | |
], | |
)), | |
if( !UserRepository.instance.isMe(state.detailData!.user.mid) && !state.detailData!.row.isDelete) | |
Positioned(right: 16 ,child: InkWell( | |
onTap: (){ | |
context.read<ArticalDetailBloc>().add(OpenChatEvent(context,aid:state.detailData!.row!.aid,roomKey: state.detailData!.chat.roomKey,userNick: state.detailData!.user.nick,userImg: state.detailData!.user.photoUrl)); | |
}, | |
child: Container( | |
height: 36, | |
alignment: AlignmentDirectional.center, | |
decoration: | |
state.detailData!.chat.roomKey.isNotEmpty ? BoxDecoration(border: Border.all(color: const Color.fromRGBO(39, 147, 255, 1) ,width: 1),borderRadius: BorderRadius.circular(4)) : | |
BoxDecoration(color: const Color.fromRGBO(39, 147, 255, 1),borderRadius: BorderRadius.circular(4)), | |
child: Padding( | |
padding: const EdgeInsets.only(left: 24,right: 24), | |
child: Text(state.detailData!.chat.roomKey.isNotEmpty ? "chating".tr() : "chat".tr(),style: const TextStyle(color: Colors.white,fontSize: 15,fontWeight: FontWeight.w500),), | |
), | |
), | |
)), | |
Positioned(top:0,child: SizedBox( | |
height: 1, | |
width: MediaQuery.of(context).size.width, | |
child: const Divider(color: Color.fromRGBO(0, 0, 0, 0.2),height: 1,))), | |
Positioned(left: 0, child : InkWell(onTap: (){ | |
Navigator.push(context, MaterialPageRoute(builder: (context) => UserProfileDetailPage(state.detailData!.user.mid))); | |
}, child: SizedBox(height: 54,width: 200,),)) | |
], | |
), | |
), | |
); | |
} | |
Widget _buildDetail(BuildContext context, ArticalDetailState state) { | |
return SizedBox( | |
width: MediaQuery.of(context).size.width, | |
height: MediaQuery.of(context).size.height , | |
child: ListView( | |
children: [ | |
(item.photoUrl?.isNotEmpty ==true || | |
(state.detailData != null && state.detailData!.row!.photoList!=null && state.detailData!.row!.photoList!.isNotEmpty)) | |
? _buildPhotos(context, state) | |
: const SizedBox( | |
height: 86, | |
), | |
_buildTopLikeArea(context, state), | |
_buildTitleArea(context, state), | |
_buildPriceArea(context, state), | |
_buildHashArea(context, state), | |
const Padding( | |
padding: EdgeInsets.only(top: 15, left: 16, right: 16), | |
child: Divider( | |
height: 1, | |
color: Color.fromRGBO(237, 237, 237, 1), | |
), | |
), | |
_buildBodyArea(context, state), | |
const Padding( | |
padding: EdgeInsets.only(top: 24, left: 16, right: 16), | |
child: Divider( | |
height: 1, | |
color: Color.fromRGBO(237, 237, 237, 1), | |
), | |
), | |
_buildPlaceArea(context, state), | |
const SizedBox( | |
height: 200, | |
) | |
], | |
), | |
); | |
//SmartRefresher( | |
// enablePullDown: true, | |
// enablePullUp: false, | |
// controller: _refreshController, | |
// onRefresh: () async {}, | |
// onLoading: () async {}, | |
// child: , | |
// ) | |
} | |
Widget _buildPlaceArea(BuildContext context, ArticalDetailState state) { | |
return Padding( | |
padding: const EdgeInsets.only(top: 16, left: 16, right: 16), | |
child: SizedBox( | |
height: 170, | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Text( | |
"artical_detail_place_title".tr(), | |
style: const TextStyle( | |
color: Color.fromRGBO(34, 34, 34, 1), | |
fontSize: 15, | |
fontWeight: FontWeight.bold), | |
), | |
const SizedBox( | |
height: 6, | |
), | |
InkWell( | |
onTap: () {}, | |
child: ClipRRect( | |
borderRadius: BorderRadius.circular(6), | |
child: Container( | |
height: 140, | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(6), | |
border: Border.all( | |
color: const Color.fromRGBO(230, 230, 230, 1), | |
width: 1)), | |
child: Image( | |
image: CachedNetworkImageProvider(state.detailData != null | |
? state.detailData!.row!.getCraeteArticalLocateImg( | |
MediaQuery.of(context).size.width - 32, 140) | |
: item.getCraeteArticalLocateImg( | |
MediaQuery.of(context).size.width - 32, 140)), | |
fit: BoxFit.cover, | |
height: 140), | |
), | |
), | |
), | |
], | |
), | |
), | |
); | |
} | |
Widget _buildBodyArea(BuildContext context, ArticalDetailState state) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16, right: 16, top: 15), | |
child: state.detailData != null | |
? Text( | |
state.detailData!.row!.body ?? "", | |
style: TextStyle( | |
color: Color.fromRGBO(34, 34, 34, 1), fontSize: 15), | |
) | |
: Container( | |
height: 40, | |
alignment: Alignment.center, | |
child: const SpinKitCircle( | |
size: 24, | |
color: Colors.black, | |
), | |
)); | |
} | |
Widget _buildTopLikeArea(BuildContext context, ArticalDetailState state) { | |
return Padding( | |
padding: const EdgeInsets.only(top: 16, left: 16, right: 16), | |
child: SizedBox( | |
height: 28, | |
child: Stack( | |
alignment: AlignmentDirectional.centerStart, | |
children: [ | |
Positioned( | |
child: Text( state.detailData?.row!.cate.str ?? "", | |
style: const TextStyle( | |
color: Color.fromRGBO(138, 146, 154, 1), | |
fontSize: 15, | |
), | |
)), | |
Positioned( | |
right: 0, | |
child: state.detailData != null && !state.likeLoading | |
? InkWell( | |
onTap: (){ | |
context.read<ArticalDetailBloc>().add(LikeToogleEvent(context)); | |
}, | |
child: Container( | |
height: 28, | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(6), | |
border: Border.all( | |
color: const Color.fromRGBO(190, 197, 203, 1), | |
width: 1)), | |
alignment: Alignment.center, | |
child: Padding( | |
padding: const EdgeInsets.only(left: 8, right: 8), | |
child: Row( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Image.asset( | |
state.detailData!.row!.isLike | |
? Assets.imagesHeartP | |
: Assets.imagesHeart, | |
height: 13, | |
), | |
const SizedBox( | |
width: 9, | |
), | |
Text(state.detailData!.row!.likeCount, | |
style: TextStyle( | |
color: state.detailData!.row!.isLike | |
? const Color.fromRGBO(255, 101, 101, 1) | |
: const Color.fromRGBO( | |
190, 197, 203, 1), | |
fontSize: 15, | |
)) | |
], | |
), | |
), | |
), | |
) | |
: const SpinKitCircle( | |
size: 24, | |
color: Colors.black, | |
)) | |
], | |
), | |
), | |
); | |
} | |
int curPage = 0; | |
List<Widget> _buildSingleImage( | |
BuildContext context, ArticalDetailState state) { | |
if (state.detailData != null) { | |
return (state.detailData!.row!.photoList ?? []) | |
.map((e) => InkWell( | |
onTap: () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => PhotoPage( | |
images: state.detailData!.row!.photoList?.map((e) => e.url).toList() ?? [], | |
index: curPage))); | |
}, | |
child: Image( | |
image: CachedNetworkImageProvider(e.url), | |
fit: BoxFit.cover, | |
height: 350, | |
width: MediaQuery.of(context).size.width), | |
)) | |
.toList(); | |
} | |
return [ | |
InkWell( | |
onTap: () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => | |
PhotoPage(images: [item.photoUrl ?? ""], index: 0))); | |
}, | |
child: Image( | |
image: CachedNetworkImageProvider(item.photoUrl ?? ""), | |
fit: BoxFit.cover, | |
height: 350, | |
width: MediaQuery.of(context).size.width), | |
) | |
]; | |
} | |
Widget _buildPhotos(BuildContext context, ArticalDetailState state) { | |
return SizedBox( | |
width: MediaQuery.of(context).size.width, | |
height: 350, | |
child: Stack( | |
alignment: AlignmentDirectional.topCenter, | |
children: [ | |
Positioned( | |
top: 0, | |
child: SizedBox( | |
width: MediaQuery.of(context).size.width, | |
height: 350, | |
child: PageView( | |
onPageChanged: (int index) { | |
curPage = index; | |
}, | |
controller: pageController, | |
children: _buildSingleImage(context, state), | |
) | |
// PhotoViewGallery.builder( | |
// wantKeepAlive: true, | |
// scrollPhysics: const BouncingScrollPhysics(), | |
// builder: (BuildContext context, int index) { | |
// return PhotoViewGalleryPageOptions( | |
// imageProvider: CachedNetworkImageProvider( | |
// state.detailData == null | |
// ? item.photoUrl | |
// : state.detailData!.row.photoList[index]), | |
// initialScale: PhotoViewComputedScale.contained * 0.8, | |
// heroAttributes: PhotoViewHeroAttributes(tag: index), | |
// ); | |
// }, | |
// itemCount: state.detailData == null | |
// ? 1 | |
// : state.detailData!.row.photoList.length, | |
// loadingBuilder: (context, event) => Center( | |
// child: Container( | |
// width: 20.0, | |
// height: 20.0, | |
// child: CircularProgressIndicator( | |
// value: event == null | |
// ? 0 | |
// : event.cumulativeBytesLoaded / | |
// (event!.expectedTotalBytes ?? 1), | |
// ), | |
// ), | |
// ), | |
// backgroundDecoration: | |
// const BoxDecoration(color: Color.fromRGBO(0, 0, 0, 0.05)), | |
// pageController: pageController, | |
// // onPageChanged: onPageChanged, | |
// ), | |
), | |
), | |
if (state.detailData != null && | |
(state.detailData!.row!.photoList?.length ?? 0) > 1) | |
Positioned( | |
bottom: 10, | |
child: SmoothPageIndicator( | |
controller: pageController, // PageController | |
count: state.detailData!.row!.photoList?.length ?? 0, | |
effect: ExpandingDotsEffect( | |
activeDotColor: Colors.white, | |
dotColor: Colors.white.withOpacity(0.4), | |
dotHeight: 6, | |
dotWidth: 6, | |
spacing: 6, | |
), // your preferred effect | |
onDotClicked: (index) {})) | |
], | |
), | |
); | |
} | |
Widget _buildToolbar(BuildContext context) { | |
return SizedBox( | |
height: 54, | |
width: MediaQuery.of(context).size.width, | |
child: Stack( | |
alignment: AlignmentDirectional.centerStart, | |
children: [ | |
Positioned( | |
left: 16, | |
child: InkWell( | |
onTap: () { | |
Navigator.pop(context); | |
}, | |
child: Container( | |
width: 44, | |
height: 44, | |
alignment: Alignment.center, | |
decoration: BoxDecoration( | |
color: Color.fromRGBO(0, 0, 0, 0.1), | |
borderRadius: BorderRadius.circular(22)), | |
child: Image.asset( | |
Assets.imagesBackW, | |
height: 30, | |
fit: BoxFit.fitHeight, | |
), | |
), | |
)), | |
Positioned( | |
right: 16, | |
child: PopupMenuButton<int>( | |
onSelected: (value){ | |
}, | |
child: Container( | |
width: 44, | |
height: 44, | |
alignment: Alignment.center, | |
decoration: BoxDecoration( | |
color: Color.fromRGBO(0, 0, 0, 0.1), | |
borderRadius: BorderRadius.circular(22)), | |
child: Image.asset( | |
Assets.imagesDddW, | |
height: 20, | |
fit: BoxFit.fitHeight, | |
), | |
), | |
itemBuilder: (context) { | |
return [ | |
PopupMenuItem<int>( | |
value: 1, | |
child: Text("report".tr(), | |
style: const TextStyle( | |
color: | |
Color.fromRGBO(34, 34, 34, 1), | |
fontSize: 14, | |
fontWeight: FontWeight.w500))), | |
PopupMenuItem<int>( | |
value: 1, | |
child: Text("block".tr(), | |
style: const TextStyle( | |
color: | |
Color.fromRGBO(34, 34, 34, 1), | |
fontSize: 14, | |
fontWeight: FontWeight.w500))), | |
]; | |
}, | |
)), | |
], | |
), | |
); | |
} | |
@override | |
bool get wantKeepAlive => true; | |
Widget _buildPriceArea(BuildContext context, ArticalDetailState state) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16, right: 16, top: 15), | |
child: Row( | |
children: [ | |
if(item.statBtnVisible()) | |
Padding( | |
padding: const EdgeInsets.only(right: 4), | |
child: Container( | |
decoration: BoxDecoration( | |
color: item.statBtnBgColor(), | |
borderRadius: BorderRadius.circular(4)), | |
child: Padding( | |
padding: EdgeInsets.only( | |
top: 3, bottom: 3, left: 7, right: 7), | |
child: Center( | |
child: Text(item.statBtnTxt(), | |
style: TextStyle( | |
fontSize: 13, | |
fontWeight: FontWeight.w500, | |
color: Colors.white, | |
)), | |
), | |
), | |
), | |
), | |
Expanded( | |
child: Text( | |
state.detailData != null ? state.detailData!.row!.price : item.price, | |
style: const TextStyle( | |
color: Color.fromRGBO(34, 34, 34, 1), | |
fontSize: 18, | |
fontWeight: FontWeight.bold), | |
)), | |
//조회수251•3.9km•1분 전 | |
Text( | |
state.detailData != null | |
? "${"artical_viewcount".tr()}${state.detailData!.row!.viewCount}${state.detailData!.row!.distStr.isNotEmpty ? "•${state.detailData!.row!.distStr}" : ""}${state.detailData!.row!.date.isNotEmpty ? "•${state.detailData!.row!.date}" : ""}" | |
: "${"artical_viewcount".tr()}${item.viewCount}${item.distStr.isNotEmpty ? "•${item.distStr}" : ""}${item.date.isNotEmpty ? "•${item.date}" : ""}", | |
style: const TextStyle( | |
color: Color.fromRGBO(138, 146, 154, 1), fontSize: 15), | |
) | |
], | |
), | |
); | |
} | |
Widget _buildTitleArea(BuildContext context, ArticalDetailState state) { | |
return Padding( | |
padding: const EdgeInsets.only(left: 16, right: 16, top: 15), | |
child: Text( | |
state.detailData != null ? state.detailData!.row!.title : item.title, | |
style: const TextStyle( | |
color: Color.fromRGBO(34, 34, 34, 1), | |
fontSize: 16, | |
fontWeight: FontWeight.w500), | |
), | |
); | |
} | |
Widget _buildHashArea(BuildContext context, ArticalDetailState state) { | |
late List<String> list; | |
if (state.detailData != null) { | |
list = state.detailData!.row!.hashList; | |
} else { | |
list = item.hashList; | |
} | |
return Padding( | |
padding: const EdgeInsets.only(top: 15, left: 16, right: 16), | |
child: Text.rich(TextSpan(children: [ | |
// item.hashList | |
for (var hashValue in list) | |
TextSpan( | |
text: "${hashValue} ", | |
style: const TextStyle( | |
color: Color.fromRGBO(114, 140, 162, 1), fontSize: 15), | |
recognizer: TapGestureRecognizer()..onTap = () {}) | |
])), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment