Skip to content

Instantly share code, notes, and snippets.

@readmycodetanos
Created February 17, 2023 05:29
Show Gist options
  • Save readmycodetanos/064a45703b672718d9ce1deaaa718fcc to your computer and use it in GitHub Desktop.
Save readmycodetanos/064a45703b672718d9ce1deaaa718fcc to your computer and use it in GitHub Desktop.
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