Commit 69d460ba authored by netyouli's avatar netyouli

优化图片作品,收藏,广场列表分页功能,图片生成界面蒙层效果

parent 0e9173ca
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IsASCIICapable</key>
<false/>
<key>PrefersRightToLeft</key>
<false/>
<key>PrimaryLanguage</key>
<string>en-US</string>
<key>RequestsOpenAccess</key>
<false/>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.keyboard-service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).KeyboardViewController</string>
</dict>
</dict>
</plist>
//
// KeyboardViewController.swift
// MyKeyboradExtension
//
// Created by WHC on 2023/7/19.
//
import UIKit
class KeyboardViewController: UIInputViewController {
@IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
// Perform custom UI setup here
self.nextKeyboardButton = UIButton(type: .system)
self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard", comment: "Title for 'Next Keyboard' button"), for: [])
self.nextKeyboardButton.sizeToFit()
self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false
self.nextKeyboardButton.addTarget(self, action: #selector(handleInputModeList(from:with:)), for: .allTouchEvents)
self.view.addSubview(self.nextKeyboardButton)
self.nextKeyboardButton.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.nextKeyboardButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
override func viewWillLayoutSubviews() {
self.nextKeyboardButton.isHidden = !self.needsInputModeSwitchKey
super.viewWillLayoutSubviews()
}
override func textWillChange(_ textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(_ textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.dark {
textColor = UIColor.white
} else {
textColor = UIColor.black
}
self.nextKeyboardButton.setTitleColor(textColor, for: [])
}
}
......@@ -77,6 +77,32 @@ class NewsAPI {
return MidJourneyModel.fromJson(response);
}
// sd生成图片
static Future<SdCreateImageModel> createlmageBySdTxtTolmg(String question, int conversionId) async {
var response = await HttpUtil().post('/sd/createImageBySdTxtToImage', data: {
// "conversionId": conversionId,
// "next": 0,
"prompt": question,
"batch_size": 1,
"override_settings": {
"sd_model_checkpoint":"v1-5-pruned-emaonly.safetensors [6ce0161689]"
}
});
return SdCreateImageModel.fromJson(response);
}
// sd获取图片生成进度
static Future<SdImageProgressModel> getSdlmgProgress() async {
var response = await HttpUtil().get('/sd/getSdImageProgress');
return SdImageProgressModel.fromJson(response);
}
// sd获取所有模型
static Future<SdImageProgressModel> getSdModels() async {
var response = await HttpUtil().get('/sd/getSdModels');
return SdImageProgressModel.fromJson(response);
}
// https://api.kertennet.com/live/translate?text=美女喜欢帅哥&to=en
// 'https://frozenland.cc/index.php/translate?query='
static Future<TranslateModel> translate(String content) async {
......@@ -89,6 +115,7 @@ class NewsAPI {
);
return TranslateModel.fromJson(response.data);
}
static Future<CommonResponse> shareImageSquare(String imgId) async {
var response = await HttpUtil().get(
......@@ -98,11 +125,12 @@ class NewsAPI {
}
// 收藏图片
static Future<CommonResponse> updateCollectImg(String imgUrl, int isCancel) async {
static Future<CommonResponse> updateCollectImg(String imgUrl, int isCancel, String prompt) async {
var response = await HttpUtil().post('/imgInfo/updateCollectImg', data: {
"imgUrl": imgUrl,
"isCancel": isCancel,
"userId": "${UserStore.to.profile.id}"
"userId": "${UserStore.to.profile.id}",
"prompt": prompt
});
return CommonResponse.fromJson(response);
}
......
......@@ -240,23 +240,36 @@ class UserAPI {
// UserLoginResponseEntity.fromJson(response);
}
static Future<MyWorkResponse> getMyWorkImages() async {
// 我的作品列表
static Future<MyWorkResponse> getMyWorkImages(int page) async {
var response = await HttpUtil().get(
'/imgInfo/getImgInfoList',
queryParameters: {
"page": page,
"size": 10
},
);
return MyWorkResponse.fromJson(response);
}
static Future<MyCollectResponse> getMyCollectImages() async {
static Future<MyCollectResponse> getMyCollectImages(int page) async {
var response = await HttpUtil().get(
'/imgInfo/getCollectImg',
queryParameters: {
"page": page,
"size": 10
}
);
return MyCollectResponse.fromJson(response);
}
static Future<MyWorkResponse> getSquareImages() async {
static Future<MyWorkResponse> getSquareImages(int page) async {
var response = await HttpUtil().get(
'/imgInfo/squareImgList',
queryParameters: {
"page": page,
"size": 10
}
);
return MyWorkResponse.fromJson(response);
}
......
......@@ -38,7 +38,7 @@ class HttpUtil {
connectTimeout: 10000,
// 响应流上前后两次接受到数据的间隔,单位为毫秒。
receiveTimeout: 150000,
receiveTimeout: 5000000,
// Http请求头.
headers: {},
......
// baidu yapi
// const SERVER_API_URL = 'https://yapi.baidu.com/mock/41008';
const SERVER_API_URL = 'http://101.34.153.228:8083/api';//线上
// const SERVER_API_URL = 'http://101.34.153.228:8083/api';//线上
// const SERVER_API_URL = 'http://192.168.110.116:8083/api';//内
// const SERVER_API_URL = 'http://192.168.110.12:8083/api';//线上
......@@ -11,7 +11,7 @@ const SERVER_API_URL = 'http://101.34.153.228:8083/api';//线上
// http://192.168.110.127:8083/api/doc.html
// http://192.168.110.66:8083/api/doc.html
// const SERVER_API_URL = 'http://192.168.110.23:8083/api'; // 大黄蜂
const SERVER_API_URL = 'http://192.168.110.1:8083/api'; // 大黄蜂
// const SERVER_API_URL = 'http://192.168.110.193:8083/api'; // 清
// http://192.168.110.25:8083/
......
import 'package:flutter/material.dart';
class KeepAliveWrapper extends StatefulWidget {
final Widget child;
const KeepAliveWrapper(this.child, {Key? key}) : super(key: key);
@override
_KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
@override
bool get wantKeepAlive => true;
}
......@@ -27,6 +27,11 @@ enum OpearterType {
imageResult
}
enum MakeModelType {
MJ,
SD
}
class AIDrawImageResultController extends GetxController {
late var sseClient;
......@@ -52,6 +57,7 @@ class AIDrawImageResultController extends GetxController {
var opearter = OpearterType.textToImage;
var imageUrls = List.generate(0, (index) => "");
Timer? _timer;
var modelType = MakeModelType.MJ;
@override
void onInit() {
......@@ -67,6 +73,7 @@ class AIDrawImageResultController extends GetxController {
styleName.value = arguments["styleName"];
imageUrls = arguments["imageUrls"] ?? [];
messageId = arguments["messageId"] ?? "";
modelType = arguments["modelType"] ?? MakeModelType.MJ;
}
@override
......@@ -79,6 +86,8 @@ class AIDrawImageResultController extends GetxController {
void onClose() {
// TODO: implement onClose
super.onClose();
SSEClient.unsubscribeFromSSE();
_timer?.cancel();
}
@override
......@@ -113,7 +122,7 @@ class AIDrawImageResultController extends GetxController {
void doCollect() async {
if (didCollected.value) {
EasyLoading.show(status: "取消收藏中...");
final res = await NewsAPI.updateCollectImg(resultImageUrl, 0);
final res = await NewsAPI.updateCollectImg(resultImageUrl, 0, enText);
EasyLoading.dismiss();
if (res.status == 401) {
EasyLoading.showInfo('您还未登录,请登录后体验功能。');
......@@ -128,7 +137,7 @@ class AIDrawImageResultController extends GetxController {
}
} else {
EasyLoading.show(status: "收藏中...");
final res = await NewsAPI.updateCollectImg(resultImageUrl, 1);
final res = await NewsAPI.updateCollectImg(resultImageUrl, 1, enText);
EasyLoading.dismiss();
if (res.status == 401) {
EasyLoading.showInfo('您还未登录,请登录后体验功能。');
......@@ -144,13 +153,21 @@ class AIDrawImageResultController extends GetxController {
}
}
void startTimer() {
void startTimer({void Function()? progressCallback}) {
_timer?.cancel();
const oneSec = Duration(milliseconds: 10);
var sumTime = 0.0;
var oldTime = 0;
_timer = Timer.periodic(oneSec, (Timer timer) {
sumTime += 0.01;
loseTime.value = "${sumTime.toStringAsFixed(2)}s";
if (progressCallback != null) {
final time = sumTime.toInt();
if (time != oldTime) {
progressCallback();
}
oldTime = time;
}
});
}
......@@ -207,7 +224,16 @@ class AIDrawImageResultController extends GetxController {
makeImage() async {
switch (opearter) {
case OpearterType.textToImage:
makeDrawImage();
switch(modelType) {
case MakeModelType.MJ:
makeDrawImage();
break;
case MakeModelType.SD:
sdMakeDrawImage();
break;
default:
break;
}
break;
case OpearterType.imageBlend:
makeBlendImage();
......@@ -291,6 +317,100 @@ class AIDrawImageResultController extends GetxController {
}
}
sdMakeDrawImage() async {
progress.value = 0;
var question = "";
if (opearter == OpearterType.imageResult) {
question = enText;
} else {
final imageUrl = imageUrls.isNotEmpty ? imageUrls.first : "";
/*
if (imageUrl.isNotEmpty) {
question = '$imageUrl $enText --iw 2 --ar $ratio$s';
} else {
question = '$enText --ar $ratio$s';
}*/
question = '$enText';
}
Logger.debugPrint("question = $question");
// EasyLoading.show(status: "AI正在生成中...");
try {
/*
final res = await NewsAPI.createlmageBySdTxtTolmg(question, conversionId);
if (res.status == 401) {
EasyLoading.showInfo('您还未登录,请登录后体验功能。');
Get.toNamed(AppRoutes.SIGN_IN);
// state.isLoading = false;
} else {
EasyLoading.dismiss();
if (res.data == null) {
EasyLoading.showToast(res.message ?? "未知错误");
} else {
showProgressView.value = true;
var canQuery = true;
startTimer(progressCallback: () {
if (canQuery) {
canQuery = false;
NewsAPI.getSdlmgProgress().then((value) {
canQuery = true;
});
}
});
}
} */
var canQuery = true;
NewsAPI.createlmageBySdTxtTolmg(question, conversionId).then((res) {
canQuery = false;
if (res.status == 200) {
if ((res.data?.images?.length ?? 0) > 0) {
if (res.data?.images?[0].startsWith("http") == true) {
loadImage(res.data?.images?[0] ?? "", 100);
} else {
final decode = base64Decode(res.data?.images?[0] ?? "");
placehoderImageData = imageData.value ?? decode;
imageData.value = decode;
}
}
progress.value = 100;
} else {
if (res.status == 401) {
EasyLoading.showInfo('您还未登录,请登录后体验功能。');
Get.toNamed(AppRoutes.SIGN_IN);
} else {
EasyLoading.showError(res.message ?? "");
}
}
});
showProgressView.value = true;
startTimer(progressCallback: () {
if (canQuery) {
canQuery = false;
NewsAPI.getSdlmgProgress().then((res) {
if (res.status == 200) {
canQuery = true;
if (res.data?.currentImage != null) {
if (res.data?.currentImage?.startsWith("http") == true) {
loadImage(res.data?.currentImage ?? "", ((res.data?.progress ?? 0.0) * 100).toInt());
} else {
final decode = base64Decode(res.data?.currentImage?.replaceAll('\n', '') ?? "");
placehoderImageData = imageData.value ?? decode;
imageData.value = decode;
}
}
progress.value = ((res.data?.progress ?? 0.0) * 100).toInt();
} else {
canQuery = false;
EasyLoading.showError(res.message ?? "");
}
});
}
});
} catch (e) {
EasyLoading.showError(e.toString());
}
}
initEventSource(String id) async {
final url = "$SERVER_API_URL/openAi/imgConnect/$id";
Logger.debugPrint("sse url = $url");
......@@ -336,7 +456,7 @@ class AIDrawImageResultController extends GetxController {
loadImage(resultImageUrl, model.progress ?? 0);
}
}
bottomButtonTitles.value = model.response?.buttons?.where((element) => element.toLowerCase() != "web").toList() ?? [];
bottomButtonTitles.value = model.response?.buttons?.where((element) => element.toLowerCase() != "web" && element.toLowerCase().contains("custom")).toList() ?? [];
messageId = model.response?.buttonMessageId ?? "";
});
}
......
......@@ -169,4 +169,152 @@ class CommonResponse {
data['timestamp'] = this.timestamp;
return data;
}
}
class SdCreateImageModel {
int? status;
String? message;
SdCreateImagData? data;
SdCreateImageModel({this.status, this.message, this.data});
SdCreateImageModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] != null ? new SdCreateImagData.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data?.toJson();
}
return data;
}
}
class SdCreateImagData {
List<String>? images;
SdCreateImagData({this.images});
SdCreateImagData.fromJson(Map<String, dynamic> json) {
images = json['images'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['images'] = this.images;
return data;
}
}
class SdImageProgressModel {
int? status;
String? message;
SdImageProgressData? data;
int? timestamp;
SdImageProgressModel({this.status, this.message, this.data, this.timestamp});
SdImageProgressModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] != null ? new SdImageProgressData.fromJson(json['data']) : null;
timestamp = json['timestamp'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data?.toJson();
}
data['timestamp'] = this.timestamp;
return data;
}
}
class SdImageProgressData {
String? currentImage;
double? progress;
SdImageProgressState? state;
String? textinfo;
double? etaRelative;
SdImageProgressData(
{this.currentImage,
this.progress,
this.state,
this.textinfo,
this.etaRelative});
SdImageProgressData.fromJson(Map<String, dynamic> json) {
currentImage = json['current_image'];
progress = json['progress'];
state = json['state'] != null ? new SdImageProgressState.fromJson(json['state']) : null;
textinfo = json['textinfo'];
etaRelative = json['eta_relative'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['current_image'] = this.currentImage;
data['progress'] = this.progress;
if (this.state != null) {
data['state'] = this.state?.toJson();
}
data['textinfo'] = this.textinfo;
data['eta_relative'] = this.etaRelative;
return data;
}
}
class SdImageProgressState {
int? jobCount;
int? jobNo;
String? jobTimestamp;
bool? interrupted;
String? job;
int? samplingStep;
bool? skipped;
int? samplingSteps;
SdImageProgressState(
{this.jobCount,
this.jobNo,
this.jobTimestamp,
this.interrupted,
this.job,
this.samplingStep,
this.skipped,
this.samplingSteps});
SdImageProgressState.fromJson(Map<String, dynamic> json) {
jobCount = json['job_count'];
jobNo = json['job_no'];
jobTimestamp = json['job_timestamp'];
interrupted = json['interrupted'];
job = json['job'];
samplingStep = json['sampling_step'];
skipped = json['skipped'];
samplingSteps = json['sampling_steps'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['job_count'] = this.jobCount;
data['job_no'] = this.jobNo;
data['job_timestamp'] = this.jobTimestamp;
data['interrupted'] = this.interrupted;
data['job'] = this.job;
data['sampling_step'] = this.samplingStep;
data['skipped'] = this.skipped;
data['sampling_steps'] = this.samplingSteps;
return data;
}
}
\ No newline at end of file
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
......@@ -37,7 +38,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("AI生成进度:${controller.progress.value}%"),
SizedBox(height: 10,),
const SizedBox(height: 10,),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: LinearProgressIndicator(
......@@ -46,7 +47,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
value: controller.progress.value.toDouble() / 100.0,
),
),
SizedBox(height: 10,),
const SizedBox(height: 10,),
Text(controller.loseTime.value),
],
),
......@@ -56,7 +57,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
Widget makeBottomButtonsView() {
return Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: const EdgeInsets.fromLTRB(20, 10, 20, 0),
height: 100,
child: SingleChildScrollView(
child: Wrap(
......@@ -86,7 +87,6 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
}
Widget makeImageView() {
return Visibility(
visible: controller.imageData.value != null,
child: InteractiveViewer(
......@@ -100,6 +100,28 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
));
}
Widget makeBlurView() {
return Obx(() => Stack(
children: [
Visibility(
visible: controller.imageData.value != null,
child: FadeInImage(
image: MemoryImage(controller.imageData.value ?? Uint8List(0)),
placeholder: MemoryImage(controller.placehoderImageData ?? Uint8List(0)),
fit: BoxFit.fitHeight,width: Get.width, height: Get.height,
)
),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
color: Colors.white.withOpacity(0.3),
width: Get.width, height: Get.height,
),
),
],
));
}
@override
Widget build(BuildContext context) {
// TODO: implement build
......@@ -107,11 +129,11 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
init: AIDrawImageResultController(),
builder: (_) => Stack(
children: [
// makeImageView(),
makeBlurView(),
Scaffold(
backgroundColor: AppColor.gray1,
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.black,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
Container(
......@@ -128,11 +150,11 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
color: AppColor.primary,
borderRadius: BorderRadius.circular(20),
),
child: Text("分享到广场")
child: const Text("分享到广场")
),
),
),
SizedBox(width: 10,),
const SizedBox(width: 10,),
Container(
padding: const EdgeInsets.fromLTRB(0, 8, 0, 8),
child: InkWell(
......@@ -153,9 +175,9 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
),
),
),
SizedBox(width: 10,),
const SizedBox(width: 10,),
Container(
padding: const EdgeInsets.fromLTRB(0, 8, 0, 8),
padding: const EdgeInsets.fromLTRB(0, 8, 10, 8),
child: InkWell(
onTap: () {
controller.share();
......@@ -168,7 +190,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
color: AppColor.primary,
borderRadius: BorderRadius.circular(20),
),
child: Image(image: AssetImage("assets/images/imageShare.png"),
child: const Image(image: AssetImage("assets/images/imageShare.png"),
width: 20,
height: 20,)
),
......@@ -180,7 +202,10 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
return Container(
child: Stack(
children: [
makeImageView(),
Center(
heightFactor: 1.6,
child: makeImageView(),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -206,22 +231,30 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
),
),
),
const SizedBox(height: 20,),
Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Text(controller.text.value,
style: const TextStyle(
color: Colors.white70,
fontSize: 14
const SizedBox(height: 5,),
SizedBox(
height: 50,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Text(controller.text.value,
style: const TextStyle(
color: Colors.white70,
fontSize: 14
),
),
),
),
),
SizedBox(height: 20,),
makeBottomButtonsView(),
SizedBox(height: 20,),
Visibility(
visible: controller.bottomButtonTitles.value.isNotEmpty,
child: makeBottomButtonsView(),
),
const SizedBox(height: 20,),
SafeArea(
child: Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
......@@ -237,7 +270,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
borderRadius: BorderRadius.circular(22)
),
alignment: Alignment.center,
child: Text("保存原图"),
child: const Text("保存原图"),
),
),
......@@ -253,7 +286,7 @@ class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
borderRadius: BorderRadius.circular(22)
),
alignment: Alignment.center,
child: Text("生成同款(2金币)"),
child: const Text("生成同款(2金币)"),
),
),
],
......
......@@ -29,8 +29,9 @@ class AIDrawImageController extends GetxController {
var model = AIDrawTextToImageModel();
var ratio = "9:16".obs;
var descriptionText = "".obs;
var styleName = "通用风格".obs;
var styleName = "--v 5.2".obs;
var s = "";
var page = 1;
ScrollController categoryScrollController = ScrollController(initialScrollOffset: 0);
TextEditingController textController = TextEditingController(text: "");
Offset startPoint = const Offset(0, 0);
......@@ -69,11 +70,14 @@ class AIDrawImageController extends GetxController {
];
var squareImgaes = Rx<List<MyWorkData>>([]);
var squareImageCount = 0.obs;
var textCount = 0.obs;
var uploadBlendImageUrls = List<String>.generate(0, (index) => "");
var uploadTextImageUrls = List<String>.generate(0, (index) => "");
var modelApiOption = "使用MidJourney".obs;
@override
void onInit() {
// TODO: implement onInit
......@@ -108,15 +112,13 @@ class AIDrawImageController extends GetxController {
}
onPullRefresh(RefreshController refreshController) {
Future.delayed(Duration(seconds: 3), () {
refreshController.refreshCompleted();
});
page = 1;
requestSquareImages(false, refreshController);
}
onLoadMore(RefreshController refreshController) {
Future.delayed(Duration(seconds: 3), () {
refreshController.loadComplete();
});
page += 1;
requestSquareImages(true, refreshController);
}
replaceIt() {
......@@ -160,26 +162,38 @@ class AIDrawImageController extends GetxController {
"text": item.content ?? "",
"ratio": "16:9",
"s": "",
"styleName": item.style ?? "通用风格",
"styleName": item.style ?? "--v 5.2",
"messageId": item.messageId ?? ""
});
}
}
}
requestSquareImages() async {
EasyLoading.show(
status: "正在加载广场图片",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
final res = await UserAPI.getSquareImages();
requestSquareImages(bool ismore, RefreshController? refreshController) async {
if (!ismore) {
EasyLoading.show(
status: "正在加载广场图片",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
}
final res = await UserAPI.getSquareImages(page);
if (ismore) {
refreshController?.loadComplete();
} else {
refreshController?.refreshCompleted();
}
EasyLoading.dismiss();
if (res.status == 200) {
squareImgaes.value = res.data ?? [];
if (ismore) {
squareImgaes.value.addAll(res.data ?? []);
} else {
squareImgaes.value = res.data ?? [];
}
squareImageCount.value = squareImgaes.value.length;
} else {
EasyLoading.showError(res.message ?? "请求广场图片异常");
}
......@@ -326,8 +340,9 @@ class AIDrawImageController extends GetxController {
"text": textController.text,
"ratio": ratio.value,
"s": s,
"styleName": styleName.value
});
"styleName": styleName.value,
"modelType": modelApiOption.value == "使用MidJourney" ? MakeModelType.MJ : MakeModelType.SD
});
clearTextSelectedImage();
}
}
......
......@@ -14,58 +14,58 @@ class ImageSquareListView extends StatelessWidget {
Widget build(BuildContext context) {
// TODO: implement build
final controller = Get.find<AIDrawImageController>();
return SmartRefresher(
return Obx(() => SmartRefresher(
enablePullUp: true,
controller: refreshController,
onRefresh: () => controller.onPullRefresh(refreshController),
onLoading: () => controller.onLoadMore(refreshController),
header: const ClassicHeader(
releaseText: "松开刷新",
refreshingText: "刷新数据中",
completeText: "刷新数据成功",
idleText: "下拉刷新"
),
footer: const ClassicFooter(
loadingText: "正在加载中...",
noDataText: '没有更多数据啦'
),
child: Obx(() => MasonryGridView.count(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
itemCount: controller.squareImgaes.value.length,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickSquareImage(index);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
memCacheHeight: index % 2 == 0 ? 260 * 2 : 200 * 2,
maxHeightDiskCache: index % 2 == 0 ? 260 * 2 : 200 * 2,
imageUrl: controller.squareImgaes.value[index].minioUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
),
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
))
);
controller: refreshController,
onRefresh: () => controller.onPullRefresh(refreshController),
onLoading: () => controller.onLoadMore(refreshController),
header: const ClassicHeader(
releaseText: "松开刷新",
refreshingText: "刷新数据中",
completeText: "刷新数据成功",
idleText: "下拉刷新"
),
footer: const ClassicFooter(
loadingText: "正在加载中...",
noDataText: '没有更多数据啦'
),
child: MasonryGridView.count(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
itemCount: controller.squareImageCount.value,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickSquareImage(index);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
memCacheHeight: index % 2 == 0 ? 260 * 2 : 200 * 2,
maxHeightDiskCache: index % 2 == 0 ? 260 * 2 : 200 * 2,
imageUrl: controller.squareImgaes.value[index].minioUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
),
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
)
));
}
}
\ No newline at end of file
import 'dart:io';
import 'package:chart/pages/ai-draw-image/image_square_view.dart';
import 'package:chart/pages/ai-draw-image/text_to_image_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
......@@ -107,14 +106,7 @@ import 'controller.dart';
},
child: Container(
alignment: Alignment.center,
// decoration: BoxDecoration(
// border: Border.all(
// width: 1,
// color: AppColor.primary
// ),
// borderRadius: BorderRadius.circular(5)
// ),
child: Image(image: AssetImage("assets/images/添加图片.png", ), width: 30, height: 30,),
child: const Image(image: AssetImage("assets/images/添加图片.png", ), width: 30, height: 30,),
),
),
);
......
......@@ -616,18 +616,79 @@ Widget makeSectionTitleView(String index, String name) {
// tip
Container(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text("AI绘图",
style: TextStyle(
fontWeight: FontWeight.bold
child: Row(
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text("AI绘图",
style: TextStyle(
fontWeight: FontWeight.bold
),
),
Text("设计的革命,从这里开始",
style: TextStyle(
fontSize: 12
),)
],
),
),
Text("设计的革命,从这里开始",
style: TextStyle(
fontSize: 12
),)
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () => controller.modelApiOption.value = '使用MidJourney',
child: Container(
height: 30,
child: Row(
children: [
Obx(() => Radio<String>(
value: '使用MidJourney',
groupValue: controller.modelApiOption.value,
activeColor: AppColor.primary,
onChanged: (value) {
controller.modelApiOption.value = value as String;
}
)),
const Text('使用MidJourney',
style: TextStyle(
fontSize: 13
),
)
],
),
),
),
InkWell(
onTap: () => controller.modelApiOption.value = '使用StableDiffusion',
child: Container(
height: 30,
child: Row(
children: [
Obx(() => Radio<String>(
value: '使用StableDiffusion',
groupValue: controller.modelApiOption.value,
activeColor: AppColor.primary,
onChanged: (value) {
controller.modelApiOption.value = value as String;
}
)),
const Text('使用StableDiffusion',
style: TextStyle(
fontSize: 13
),
)
],
),
),
)
],
)
)
],
),
),
......
......@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import '../../common/routers/names.dart';
import '../../common/style/color.dart';
import 'controller.dart';
import 'image_square_view.dart';
......@@ -15,19 +16,21 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
AIDrawImagePage({Key? key}) : super(key: key);
var myTabs = [
var myTabs = const [
Tab(text: '文生图'),
Tab(text: '图生图'),
Tab(text: '图片广场'),
];
Widget makeTopTabView() {
return Padding(padding: EdgeInsets.fromLTRB(10, 20, 10, 10),
return Padding(padding: const EdgeInsets.fromLTRB(10, 20, 10, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {},
onTap: () {
Get.toNamed(AppRoutes.MY_WORK, arguments: {"operator": "work"});
},
child: Container(
height: 30,
width: 30,
......@@ -35,7 +38,7 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
color: AppColor.gray1,
borderRadius: BorderRadius.circular(15),
),
child: Align(alignment: Alignment.center,
child: const Align(alignment: Alignment.center,
child: Image(image: AssetImage("assets/images/jifen1.png", ), width: 20, height: 20,)
),
),
......@@ -48,8 +51,8 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
height: 30,
width: 270,
child: TabBar(
labelStyle: TextStyle(fontSize: 14),
unselectedLabelStyle: TextStyle(fontSize: 14),
labelStyle: const TextStyle(fontSize: 14),
unselectedLabelStyle: const TextStyle(fontSize: 14),
indicator: BoxDecoration(
color: AppColor.primary, // 设置背景颜色
borderRadius: BorderRadius.circular(15), // 设置圆角
......@@ -69,9 +72,9 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
color: AppColor.gray1,
borderRadius: BorderRadius.circular(15),
),
child: Padding(padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Padding(padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(
children: [
children: const [
Image(image: AssetImage("assets/images/jifen1.png", ), width: 20, height: 20,),
SizedBox(width: 5),
Text("0"),
......@@ -93,7 +96,7 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
makeTextToImageView(),
makeImageToImageView(),
Container(
decoration: BoxDecoration(color: AppColor.black1),
decoration: const BoxDecoration(color: AppColor.black1),
child: makeImageSquareView(),
)
]
......@@ -111,7 +114,7 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
controller.tabController = tabController;
tabController.addListener(() {
if (tabController.index == 2 && controller.currentIndex != tabController.index) {
controller.requestSquareImages();
controller.requestSquareImages(false, null);
}
controller.currentIndex = tabController.index;
});
......@@ -137,7 +140,7 @@ class AIDrawImagePage extends GetView<AIDrawImageController> {
top: -20,
left: -(Get.width * 1.2 - Get.width) / 2.0,
child: Image(
image: AssetImage("assets/images/top_ai_draw_image.png"),
image: const AssetImage("assets/images/top_ai_draw_image.png"),
height: 300,
width: Get.width * 1.2,
fit: BoxFit.cover,
......
import 'dart:math';
import 'package:chart/common/widgets/keep_alive_wrapper.dart';
import 'package:chart/common/widgets/wx_share.dart';
import 'package:chart/pages/assistant/index.dart';
import 'package:chart/pages/creation/index.dart';
......@@ -59,8 +60,8 @@ class ApplicationPage extends GetView<ApplicationController> {
HomePage(),
CreationPage(),
// AssistantPage(),
AIDrawImagePage(),
MyPage()
KeepAliveWrapper(AIDrawImagePage()),
KeepAliveWrapper(MyPage()),
]);
}
......
......@@ -25,23 +25,33 @@ class MyWorkController extends GetxController {
var models = AIDrawTextToImageModel();
var collectImages = Rx<List<MyCollectData>>([]);
var workImages = Rx<List<MyWorkData>>([]);
var workImageCount = 0.obs;
var collectImageCount = 0.obs;
var title = "".obs;
var page = 1;
var operator = "";
@override
void onInit() {
// TODO: implement onInit
super.onInit();
final arguments = Get.arguments;
final operator = arguments["operator"];
operator = arguments["operator"];
if (operator == "work") {
title.value = "我的作品";
requestMyWorkImages();
requestMyWorkImages(false);
} else {
title.value = "我的收藏";
requestMyCollectImages();
requestMyCollectImages(false);
}
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
onClickCollectImage(int index) async {
if (index >= 0 && index < collectImages.value.length) {
final item = collectImages.value[index];
......@@ -60,7 +70,7 @@ class MyWorkController extends GetxController {
"text": "",
"ratio": "16:9",
"s": "",
"styleName": "通用风格",
"styleName": "--v 5.2",
"messageId": ""
});
}
......@@ -85,58 +95,90 @@ class MyWorkController extends GetxController {
"text": item.content ?? "",
"ratio": "16:9",
"s": "",
"styleName": item.style ?? "通用风格",
"styleName": item.style ?? "--v 5.2",
"messageId": item.messageId ?? ""
});
}
}
}
requestMyWorkImages() async {
EasyLoading.show(
status: "正在加载我的作品",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
final res = await UserAPI.getMyWorkImages();
requestMyWorkImages(bool ismore) async {
if (!ismore) {
EasyLoading.show(
status: "正在加载我的作品",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
}
final res = await UserAPI.getMyWorkImages(page);
if (ismore) {
refreshController.loadComplete();
} else {
refreshController.refreshCompleted();
}
EasyLoading.dismiss();
if (res.status == 200) {
workImages.value = res.data ?? [];
if (ismore) {
var array = workImages.value;
array.addAll(res.data ?? []);
workImages.value = array;
} else {
workImages.value = res.data ?? [];
}
workImageCount.value = workImages.value.length;
} else {
EasyLoading.showError(res.message ?? "请求我的作品异常");
}
}
requestMyCollectImages() async {
EasyLoading.show(
status: "正在加载我的收藏",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
final res = await UserAPI.getMyCollectImages();
requestMyCollectImages(bool ismore) async {
if (!ismore) {
EasyLoading.show(
status: "正在加载我的收藏",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
}
final res = await UserAPI.getMyCollectImages(page);
refreshController.refreshCompleted();
EasyLoading.dismiss();
if (res.status == 200) {
collectImages.value = res.data ?? [];
if (ismore) {
var array = collectImages.value;
array.addAll(res.data ?? []);
collectImages.value = array;
} else {
collectImages.value = res.data ?? [];
}
collectImageCount.value = collectImages.value.length;
} else {
EasyLoading.showError(res.message ?? "请求我的收藏异常");
}
}
onPullRefresh() {
Future.delayed(Duration(seconds: 3), () {
refreshController.refreshCompleted();
});
page = 0;
if (operator == "work") {
title.value = "我的作品";
requestMyWorkImages(false);
} else {
title.value = "我的收藏";
requestMyCollectImages(false);
}
}
onLoadMore() {
Future.delayed(Duration(seconds: 3), () {
refreshController.loadComplete();
});
onLoadMore() async {
page += 1;
if (operator == "work") {
requestMyWorkImages(true);
} else {
requestMyCollectImages(true);
}
}
}
\ No newline at end of file
......@@ -118,6 +118,7 @@ class MyCollectData {
int? isCancel;
String? createTime;
String? updateTime;
String? prompt;
MyCollectData(
{this.id,
......@@ -125,6 +126,7 @@ class MyCollectData {
this.imgUrl,
this.isCancel,
this.createTime,
this.prompt,
this.updateTime});
MyCollectData.fromJson(Map<String, dynamic> json) {
......@@ -134,6 +136,7 @@ class MyCollectData {
isCancel = json['isCancel'];
createTime = json['createTime'];
updateTime = json['updateTime'];
prompt = json['prompt'];
}
Map<String, dynamic> toJson() {
......@@ -144,6 +147,7 @@ class MyCollectData {
data['isCancel'] = this.isCancel;
data['createTime'] = this.createTime;
data['updateTime'] = this.updateTime;
data['prompt'] = this.prompt;
return data;
}
}
\ No newline at end of file
......@@ -15,97 +15,114 @@ import './controller.dart';
class MyWorkPage extends GetView<MyWorkController> {
const MyWorkPage({Key? key}) : super(key: key);
Widget makeListView() {
// TODO: implement build
Widget makeMyWorkListView() {
final controller = Get.find<MyWorkController>();
return SmartRefresher(
return Obx(() => SmartRefresher(
enablePullUp: true,
controller: controller.refreshController,
onRefresh: controller.onPullRefresh,
onLoading: controller.onLoadMore,
header: const ClassicHeader(
releaseText: "松开刷新",
refreshingText: "刷新数据中",
completeText: "刷新数据成功",
idleText: "下拉刷新"
),
footer: const ClassicFooter(
loadingText: "正在加载中...",
noDataText: '没有更多数据啦'
),
child: Obx(() {
if (controller.title.value == "我的收藏") {
return MasonryGridView.count(
itemCount: controller.collectImages.value.length,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickCollectImage(index);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
imageUrl: controller.collectImages.value[index].imgUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
enablePullDown: true,
controller: controller.refreshController,
onRefresh: controller.onPullRefresh,
onLoading: controller.onLoadMore,
header: const ClassicHeader(
releaseText: "松开刷新",
refreshingText: "刷新数据中",
completeText: "刷新数据成功",
idleText: "下拉刷新"
),
footer: const ClassicFooter(
loadingText: "正在加载中...",
noDataText: '没有更多数据啦'
),
child: MasonryGridView.count(
itemCount: controller.workImageCount.value,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickWorkImage(index);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
memCacheHeight: index % 2 == 0 ? 260 * 2 : 200 * 2,
maxHeightDiskCache: index % 2 == 0 ? 260 * 2 : 200 * 2,
imageUrl: controller.workImages.value[index].minioUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
);
}
return MasonryGridView.count(
itemCount: controller.workImages.value.length,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickWorkImage(index);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
memCacheHeight: index % 2 == 0 ? 260 * 2 : 200 * 2,
maxHeightDiskCache: index % 2 == 0 ? 260 * 2 : 200 * 2,
imageUrl: controller.workImages.value[index].minioUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
),
);
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
),
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
)
));
}
Widget makeMyCollectListView() {
// TODO: implement build
final controller = Get.find<MyWorkController>();
return Obx(() => SmartRefresher(
enablePullUp: true,
controller: controller.refreshController,
onRefresh: controller.onPullRefresh,
onLoading: controller.onLoadMore,
header: const ClassicHeader(
releaseText: "松开刷新",
refreshingText: "刷新数据中",
completeText: "刷新数据成功",
idleText: "下拉刷新"
),
footer: const ClassicFooter(
loadingText: "正在加载中...",
noDataText: '没有更多数据啦'
),
child: MasonryGridView.count(
itemCount: controller.collectImageCount.value,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
controller.onClickCollectImage(index);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
fit: BoxFit.cover,
height: index % 2 == 0 ? 260 : 200,
imageUrl: controller.collectImages.value[index].imgUrl ?? "",
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
alignment: Alignment.center,
child: Text(error.toString()),
),
)
),
);
})
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
)
));
}
@override
......@@ -125,7 +142,9 @@ class MyWorkPage extends GetView<MyWorkController> {
backgroundColor: const Color.fromARGB(0, 29, 33, 60),
),
body: SafeArea(
child: makeListView(),
child: controller.title.value == "我的收藏" ?
makeMyCollectListView() :
makeMyWorkListView(),
),
);
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment