Wallpaper-Genie/lib/page/wallpaper_detail/wallpaper_detail_view.dart
2024-07-22 17:52:41 +08:00

387 lines
13 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:ui';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flip_card/flip_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:gradient_borders/box_borders/gradient_box_border.dart';
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';
import 'package:wallpaperx/common/components/view_state_widget.dart';
import 'package:wallpaperx/entity/image_model.dart';
import 'package:wallpaperx/generated/assets.dart';
import 'wallpaper_detail_controller.dart';
class WallpaperDetailView extends GetView<WallpaperDetailController> {
const WallpaperDetailView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
extendBodyBehindAppBar: true,
extendBody: true,
body: FlipCard(
flipOnTouch: false,
controller: controller.flipCardController,
fill: Fill.fillBack,
side: CardSide.FRONT,
direction: FlipDirection.HORIZONTAL,
front: Stack(
fit: StackFit.expand,
children: [
_buildPhotoView(),
_buildBottomOption(context),
],
),
back: _buildImageInfo(context),
),
);
}
/// 图片PageView
Widget _buildPhotoView() {
return Obx(() {
if (controller.wallpaperList.isEmpty) {
return Container();
}
return PhotoViewGallery.builder(
itemCount: controller.wallpaperList.length,
scrollPhysics: const BouncingScrollPhysics(),
wantKeepAlive: true,
gaplessPlayback: true,
builder: (context, index) {
return PhotoViewGalleryPageOptions.customChild(
child: PhotoView(
enableRotation: true,
imageProvider: CachedNetworkImageProvider(
controller.wallpaperList[index].imageUrl,
),
initialScale: PhotoViewComputedScale.covered,
minScale: PhotoViewComputedScale.contained * 0.5,
maxScale: PhotoViewComputedScale.covered * 3,
loadingBuilder: (context, event) => loadingView(),
errorBuilder: (BuildContext context, Object error,
StackTrace? stackTrace) =>
errorView,
),
);
},
pageController: controller.pageController,
onPageChanged: (index) => controller.onPageChanged(index),
);
});
}
/// 底部选项
Widget _buildBottomOption(context) {
return Positioned(
bottom: 0,
left: 0,
right: 0,
child: Column(
children: [
ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom),
width: double.infinity,
height: 70.h,
decoration: const BoxDecoration(
color: Color.fromRGBO(0, 0, 0, 0.65),
),
clipBehavior: Clip.hardEdge,
child: Row(
children: [
16.horizontalSpace,
_buildOptionItem(
Assets.iconBackBig,
'Blur',
controller.showAd,
),
Expanded(child: Container()),
Obx(() => _buildOptionItem(
controller.isFavorite.value
? Assets.iconFavorite
: Assets.iconUnFavorite,
'Favorite',
controller.collectionImage,
)),
24.horizontalSpace,
_buildOptionItem(
Assets.iconDownload,
'Download',
controller.downloadImg,
),
24.horizontalSpace,
_buildOptionItem(
Assets.iconImgInfo,
'Blur',
controller.flipCard,
),
16.horizontalSpace,
],
),
),
),
),
],
),
);
}
/// 图片详情
Widget _buildImageInfo(context) {
return GetBuilder<WallpaperDetailController>(
id: 'buildImageInfo',
builder: (logic) {
ImageModel model = controller.wallpaperList[controller.position];
return Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12).r,
image: DecorationImage(
fit: BoxFit.cover,
image: CachedNetworkImageProvider(
controller.wallpaperList[controller.position].imageUrl,
),
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
padding: EdgeInsets.fromLTRB(
30,
0,
30,
MediaQuery.of(context).padding.bottom + 55,
).w,
width: double.infinity,
decoration: BoxDecoration(
color: const Color(0xff000000).withOpacity(.8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
63.verticalSpace,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
24.horizontalSpace,
Stack(
clipBehavior: Clip.none,
children: [
Image.asset(
Assets.iconImgDelTip,
width: 52.w,
height: 52.w,
),
Positioned(
left: -15.w,
top: 15.w,
child: Image.asset(
Assets.iconStarSymbolS,
width: 20.w,
),
),
Positioned(
left: -8.w,
top: 10.w,
child: Image.asset(
Assets.iconStarSymbolM,
width: 20.w,
),
),
Positioned(
right: -12.w,
bottom: -2.w,
child: Image.asset(
Assets.iconStarSymbolL,
width: 25.w,
),
),
],
),
GestureDetector(
onTap: controller.flipCard,
child: Icon(
Icons.close,
color: Colors.white,
size: 24.w,
),
),
],
),
37.verticalSpace,
Expanded(
child: ListView(
padding: EdgeInsets.zero,
children: [
Wrap(
spacing: 8.w,
runSpacing: 8.w,
children: model.tags!
.map((e) => tagItem(e.taglabel))
.toList(),
),
32.verticalSpace,
genInfo(
Image.asset(
Assets.iconSampler,
width: 28.w,
),
"Sampler",
model.generateInfo!.samplingMethod ?? "",
),
23.verticalSpace,
genInfo(
Image.asset(
Assets.iconCfgScale,
width: 28.w,
),
"CFG scale",
model.generateInfo!.cfgScale.toString(),
),
23.verticalSpace,
genInfo(
Image.asset(
Assets.iconSteps,
width: 28.w,
),
"Steps",
model.generateInfo!.samplingStep.toString(),
),
23.verticalSpace,
genInfo(
Image.asset(
Assets.iconSeed,
width: 28.w,
),
"Seed",
model.generateInfo!.seed.toString(),
),
20.verticalSpace,
Text(
"Prompt",
textAlign: TextAlign.start,
style:
TextStyle(color: Colors.white, fontSize: 16.sp),
),
12.verticalSpace,
Text(
model.generateInfo?.prompt ?? "",
textAlign: TextAlign.start,
style: TextStyle(
color: const Color(0xffA1A9B3), fontSize: 14.sp),
),
20.verticalSpace,
Text(
"Negative Prompt",
textAlign: TextAlign.start,
style:
TextStyle(color: Colors.white, fontSize: 16.sp),
),
12.verticalSpace,
Text(
model.generateInfo?.negativePrompt ?? "",
textAlign: TextAlign.start,
style: TextStyle(
color: const Color(0xffA1A9B3), fontSize: 14.sp),
),
],
),
),
24.verticalSpace,
GestureDetector(
onTap: () => controller.copyPrompt(model.generateInfo),
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
vertical: 15, horizontal: 8)
.w,
decoration: BoxDecoration(
color: const Color(0xff322E31),
borderRadius: BorderRadius.circular(30).r,
),
child: Text(
"copy",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 14.sp),
),
),
),
],
),
),
),
);
},
);
}
Widget genInfo(icon, title, content) {
return Row(
children: [
icon,
16.horizontalSpace,
SizedBox(
width: 250.w,
child: Text(
title + content,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,
style: TextStyle(color: Colors.white, fontSize: 16.sp),
),
),
],
);
}
Widget tagItem(tag) {
return GestureDetector(
onTap: () => controller.toCategoryItem(tag),
child: Container(
decoration: BoxDecoration(
border: const GradientBoxBorder(
gradient: LinearGradient(colors: [
Color(0xffBEEF32),
Color(0xff2795E5),
Color(0xff8041FD),
]),
width: 1,
),
borderRadius: BorderRadius.circular(50.r),
),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12).w,
child: Text(
"#$tag",
style: TextStyle(color: Colors.white, fontSize: 14.sp),
),
),
),
);
}
Widget _buildOptionItem(String iconName, String option, Function() onTap) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Image.asset(
iconName,
width: 24.w,
height: 24.w,
color: Colors.white,
),
),
);
}
}