Commit f93dea00 authored by netyouli's avatar netyouli

添加AI画图功能

parent 4b706323
......@@ -3,5 +3,7 @@
"debouncetimer",
"roduct"
],
"vue.features.codeActions.enable": false
"vue.features.codeActions.enable": false,
"cmake.configureOnOpen": false,
"cmake.sourceDirectory": "/Users/whc/Documents/fusion/ChatGPT/linux"
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
<application
android:label="AI写作大师"
android:name="${applicationName}"
android:requestLegacyExternalStorage="true"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
......@@ -37,6 +38,8 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<queries>
<intent>
<action android:name="android.speech.RecognitionService" />
......
......@@ -112,6 +112,8 @@ PODS:
- GoogleUtilities/Reachability (7.11.1):
- GoogleUtilities/Logger
- GTMSessionFetcher/Core (3.1.0)
- image_gallery_saver (2.0.2):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
- keyboard_utils (0.0.1):
......@@ -176,6 +178,7 @@ DEPENDENCIES:
- fluttercontactpicker (from `.symlinks/plugins/fluttercontactpicker/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- fluwx (from `.symlinks/plugins/fluwx/ios`)
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- keyboard_utils (from `.symlinks/plugins/keyboard_utils/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
......@@ -249,6 +252,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/fluttertoast/ios"
fluwx:
:path: ".symlinks/plugins/fluwx/ios"
image_gallery_saver:
:path: ".symlinks/plugins/image_gallery_saver/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
keyboard_utils:
......@@ -308,6 +313,7 @@ SPEC CHECKSUMS:
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
GTMSessionFetcher: c9e714f7eec91a55641e2bab9f45fd83a219b882
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
keyboard_utils: ab24bc711be9e91a5937c20489056b8dd650fecc
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
......
......@@ -371,7 +371,7 @@
ENABLE_BITCODE = NO;
FLUTTER_BUILD_NAME = 1.0.3;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AI写作大师";
INFOPLIST_KEY_CFBundleDisplayName = SketchBot;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -509,13 +509,13 @@
ENABLE_BITCODE = NO;
FLUTTER_BUILD_NAME = 1.0.3;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AI写作大师";
INFOPLIST_KEY_CFBundleDisplayName = SketchBot;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5;
PRODUCT_BUNDLE_IDENTIFIER = com.wudi.app;
PRODUCT_BUNDLE_IDENTIFIER = com.wudi.app1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "dev-profile";
......@@ -541,13 +541,13 @@
ENABLE_BITCODE = NO;
FLUTTER_BUILD_NAME = 1.0.3;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AI写作大师";
INFOPLIST_KEY_CFBundleDisplayName = SketchBot;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5;
PRODUCT_BUNDLE_IDENTIFIER = com.wudi.app;
PRODUCT_BUNDLE_IDENTIFIER = com.wudi.app1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "dis-profile";
......
......@@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>AI写作大师</string>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
......@@ -55,11 +55,13 @@
<true/>
</dict>
<key>NSMicrophoneUsageDescription</key>
<string>只有您‘允许使用麦克风’AI写作大师才能听您说话</string>
<string>只有您‘允许使用麦克风’$(EXECUTABLE_NAME)才能听您说话</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>$(EXECUTABLE_NAME)需要权限保存图片到相册</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要相册权限发送图片</string>
<string>$(EXECUTABLE_NAME)需要相册权限发送图片</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>只有您‘允许使用麦克风’AI写作大师才能听您说话</string>
<string>只有您‘允许使用麦克风’$(EXECUTABLE_NAME)才能听您说话</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
......
......@@ -7,6 +7,7 @@ import 'package:chart/common/values/values.dart';
import '../../entity/plan_entity.dart';
import '../../entity/square_entity.dart';
import '../../pages/ai-draw-image-result/model.dart';
/// 新闻
class NewsAPI {
......@@ -61,6 +62,26 @@ class NewsAPI {
return response['status'];
}
// 生成图片
static Future<MidJourneyModel> createImageByMidJourney(String question, int conversionId) async {
var response = await HttpUtil().post('/midJourney/createImageByMidJourney', data: {
"conversionId": conversionId,
"next": 0,
"question": question
});
return MidJourneyModel.fromJson(response);
}
// 生成图片 v1-v4 u1-u4
static Future<MidJourneyModel> createImageByButtonMidJourney(String button, String buttonMessageId) async {
var response = await HttpUtil().post('/midJourney/createImageByButton', data: {
"buttonMessageId": buttonMessageId,
"next": 0,
"button": button
});
return MidJourneyModel.fromJson(response);
}
static Future<List<GoodEntity>> getGoodsList() async {
var response = await HttpUtil().get(
'/goods/goodsList',
......
......@@ -16,6 +16,9 @@ class AppRoutes {
static const WILL_COME = '/will_come';
static const USER_EULA = '/eula';
static const AI_DRAW_IMAGE_PAGE = '/ai_draw_image';
static const AI_DRAW_IMAGE_RESULT_PAGE = '/ai_draw_image/ai_draw_image_result';
static const HOME_PAGE = '/home';
static const CREATION_PAGE = '/creation';
static const CREATION_HISTORY_PAGE = '/creation-history';
......
......@@ -28,6 +28,10 @@ import 'package:chart/pages/frame/notfound/index.dart';
// import 'package:chart/pages/home/home_page.dart';
import 'package:get/get.dart';
import '../../pages/ai-draw-image-result/bingdings.dart';
import '../../pages/ai-draw-image-result/view.dart';
import '../../pages/ai-draw-image/bindings.dart';
import '../../pages/ai-draw-image/view.dart';
import '../../pages/frame/android_pay_list/index.dart';
import '../../pages/frame/pay_list/bindings.dart';
import 'routes.dart';
......@@ -132,6 +136,16 @@ class AppPages {
binding: SignInBinding(),
),
GetPage(
name: AppRoutes.AI_DRAW_IMAGE_PAGE,
page: () => AIDrawImagePage(),
binding: AIDrawImageBinding()),
GetPage(
name: AppRoutes.AI_DRAW_IMAGE_RESULT_PAGE,
page: () => AIDrawImageResultPage(),
binding: AIDrawImageResultBinding()),
GetPage(
name: AppRoutes.TEMPLATE_PAGE,
page: () => TemplatePage(),
......
import 'package:flutter/material.dart';
class AppColor {
/// 主色
static const Color primary = Color.fromARGB(255, 96, 42, 210);
static const Color gray1 = Color.fromARGB(255, 16, 16, 16);
static const Color gray2 = Color.fromARGB(255, 142, 142, 142);
static const Color gray3 = Color.fromARGB(255, 36, 36, 36);
static const Color gray4 = Color.fromARGB(255, 106, 106, 106);
static const Color gray5 = Color.fromARGB(255, 40, 40, 40);
static const Color gray6 = Color.fromARGB(255, 30, 30, 30);
static const Color black1 = Color.fromARGB(255, 20, 20, 20);
static const Color yellow1 = Color.fromARGB(255, 150, 100, 30);
/// 页面背景颜色
static const Color scaffoldBackground = Color(0xFFFFFFFF);
......
import 'dart:async';
import 'dart:typed_data';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
......@@ -208,6 +209,30 @@ class HttpUtil {
return headers;
}
// 请求获取二进制数据
Future<Uint8List?> getData(String path, [Map<String, dynamic>? params]) async {
try {
var response = await dio.get(
path,
queryParameters: params,
options: Options(responseType: ResponseType.stream),
);
print("image Url: $path, statusCode = ${response.statusCode}");
final statusCode = response.statusCode ?? 0;
if (statusCode >= 200 && statusCode < 300) {
final stream = await (response.data as ResponseBody).stream.toList();
final result = BytesBuilder();
for (Uint8List subList in stream) {
result.add(subList);
}
return result.takeBytes();
}
return null;
} on DioError catch (_) {
return null;
}
}
/// restful get 操作
/// refresh 是否下拉刷新 默认 false
/// noCache 是否不缓存 默认 true
......
......@@ -3,4 +3,8 @@ class Logger {
static void write(String text, {bool isError = false}) {
Future.microtask(() => print('** $text. isError: [$isError]'));
}
static void debugPrint(String log) {
print("$log");
}
}
import 'dart:ui';
class AppColors {
/// 主色
static const Color primary = Color.fromARGB(255, 96, 42, 210);
/// 主背景 白色
static const Color primaryBackground = Color.fromARGB(255, 255, 255, 255);
......
// baidu yapi
// const SERVER_API_URL = 'https://yapi.baidu.com/mock/41008';
// const SERVER_API_URL = 'http://192.168.120.175:8083/api';
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';//线上
//http://192.168.110.12:8083/api/doc.html
// const SERVER_API_URL = 'http://192.168.121.180:8083/api';//线上
......@@ -9,7 +9,10 @@ const SERVER_API_URL = 'http://101.34.153.228:8083/api';//线上
// const SERVER_API_URL = "http://192.168.120.108: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.66:8083/api';
const SERVER_API_URL = 'http://192.168.110.23:8083/api'; // 大黄蜂
// const SERVER_API_URL = 'http://192.168.110.116:8083/api'; // 清
// http://192.168.110.25:8083/
// const SERVER_API_URL = 'http://192.168.2.178:8083/api';
// const SERVER_API_URL = 'http://192.168.110.57:8083/api';
......
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:fluwx/fluwx.dart';
......@@ -65,4 +67,56 @@ class WXShare {
));
}
static shareFileData(Uint8List bytes) {
final items = <Widget>[];
_dataMap.forEach((title, image) {
items.add(
InkWell(
onTap: () {
if (title.contains("微信")) {
final WeChatShareBaseModel model;
if (title == "微信好友") {
model = WeChatShareImageModel(WeChatImage.binary(bytes), scene: WeChatScene.SESSION);
} else if (title == "微信朋友圈") {
model = WeChatShareImageModel(WeChatImage.binary(bytes), scene: WeChatScene.TIMELINE);
} else {
model = WeChatShareImageModel(WeChatImage.binary(bytes), scene: WeChatScene.FAVORITE);
}
shareToWeChat(model).then((value) {
if (value) {
EasyLoading.showToast("分享成功");
} else {
EasyLoading.showToast("分享失败");
}
});
} else {
final xfile = XFile.fromData(bytes);
Share.shareXFiles([xfile]);
}
Get.back();
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(image, width: 60, height: 60,),
const SizedBox(height: 8),
Text(title, style: const TextStyle(fontSize: 14, color: Colors.black)),
],
),
)
);
});
Get.bottomSheet(Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20))
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 100),
child: Wrap(
spacing: 30,
children: items,
),
));
}
}
\ No newline at end of file
import 'package:get/get.dart';
import 'controller.dart';
class AIDrawImageResultBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<AIDrawImageResultController>(() => AIDrawImageResultController());
}
}
\ No newline at end of file
import 'dart:convert';
import 'dart:typed_data';
import 'package:chart/common/utils/utils.dart';
import 'package:chart/common/widgets/wx_share.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_client_sse/flutter_client_sse.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:chart/common/values/server.dart';
import 'package:highlight/languages/awk.dart';
import 'package:highlight/languages/http.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import '../../common/apis/news.dart';
import '../../common/routers/names.dart';
import '../../common/store/user.dart';
import '../../common/utils/http.dart';
import 'model.dart';
class AIDrawImageResultController extends GetxController {
late var sseClient;
int conversionId = 0;
var ratio = "4:3";
var s = "";
var styleName = "".obs;
var text = "".obs;
var imageUrl = "".obs;
var progress = 0.obs;
var showProgressView = false.obs;
Rx<Uint8List?> imageData = Rx<Uint8List?>(null);
Uint8List? placehoderImageData;
var _buttonMessageId = "";
Rx<List<String>> bottomButtonTitles = Rx<List<String>>([]);
@override
void onInit() {
// TODO: implement onInit
super.onInit();
final arguments = Get.arguments;
conversionId = arguments["conversionId"];
text.value = arguments["text"];
ratio = arguments["ratio"];
s = arguments["s"];
styleName.value = arguments["styleName"];
}
@override
void onReady() {
super.onReady();
makeDrawImage();
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
@override
void dispose() {
SSEClient.unsubscribeFromSSE();
super.dispose();
}
void share() {
if (imageData.value != null) {
WXShare.shareFileData(imageData.value!);
}
}
void loadImage(String imageUrl) async {
final imageData = await HttpUtil().getData(imageUrl);
if (imageData != null) {
placehoderImageData = this.imageData.value ?? imageData;
this.imageData.value = imageData;
}
}
// 点击v和u
void clickBottomButton(String title) async {
progress.value = 0;
EasyLoading.show(status: "AI正在生成中...");
try {
// state.isLoading = true;
final res = await NewsAPI.createImageByButtonMidJourney(title, _buttonMessageId);
if (res.status == 401) {
EasyLoading.showInfo('您还未登录,请登录后体验功能。');
Get.toNamed(AppRoutes.SIGN_IN);
// state.isLoading = false;
} else {
EasyLoading.dismiss();
showProgressView.value = true;
await initEventSource(res.data ?? "");
}
// state.isLoading = false;
} catch (e) {
// state.isLoading = false;
EasyLoading.dismiss();
}
}
makeDrawImage() async {
progress.value = 0;
final question = '$text --ar $ratio$s';
Logger.debugPrint("question = $question");
EasyLoading.show(status: "AI正在生成中...");
try {
// state.isLoading = true;
final res = await NewsAPI.createImageByMidJourney(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;
await initEventSource(res.data ?? "");
}
}
// state.isLoading = false;
} catch (e) {
// state.isLoading = false;
EasyLoading.dismiss();
}
}
initEventSource(String id) async {
final url = "$SERVER_API_URL/openAi/imgConnect/$id";
Logger.debugPrint("sse url = $url");
sseClient = SSEClient.subscribeToSSE(url: url, header: {})
.listen((event) async {
Logger.debugPrint("data = ${event.data}, event = ${event.event}, id = ${event.id}");
if (event.data!.trim().isEmpty) {
return;
} else if (event.id == "[DONE]") {
showProgressView.value = false;
return;
}
Map<String, dynamic> jsonMap = jsonDecode("${event.data}");
final model = MidJourneyImageModel.fromJson(jsonMap);
if (model.response?.buttonMessageId != null) {
_buttonMessageId = model.response?.buttonMessageId ?? "";
}
progress.value = model.progress ?? 0;
if (model.progress == 100) {
showProgressView.value = false;
}
if (model.response?.imageUrl != null) {
imageUrl.value = model.response?.imageUrl ?? "" ;
} else if (model.progressImageUrl != null) {
imageUrl.value = model.progressImageUrl ?? "";
}
if (imageUrl.value.isNotEmpty) {
loadImage(imageUrl.value);
}
final first = model.response?.buttons?.first ?? "";
if (first == "V1" || first == "U1") {
bottomButtonTitles.value = model.response?.buttons ?? [];
} else {
bottomButtonTitles.value = [];
}
});
}
saveNetworkImage(String imageUrl) async {
EasyLoading.showInfo("正在保存");
var response = await Dio().get(
imageUrl,
options: Options(responseType: ResponseType.bytes));
final result = await ImageGallerySaver.saveImage(
Uint8List.fromList(response.data),
quality: 100);
EasyLoading.showSuccess("保存成功", duration: const Duration(seconds: 2));
Logger.debugPrint("保存:$result");
}
}
\ No newline at end of file
class MidJourneyModel {
int? status;
String? message;
String? data;
int? timestamp;
MidJourneyModel({this.status, this.message, this.data, this.timestamp});
MidJourneyModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'];
timestamp = json['timestamp'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
data['data'] = this.data;
data['timestamp'] = this.timestamp;
return data;
}
}
class MidJourneyImageModel {
int? progress;
String? progressImageUrl;
MidJourneyImageResponse? response;
MidJourneyImageModel({this.progress, this.progressImageUrl, this.response});
MidJourneyImageModel.fromJson(Map<String, dynamic> json) {
progress = json['progress'];
progressImageUrl = json['progressImageUrl'];
response = json['response'] != null
? new MidJourneyImageResponse.fromJson(json['response'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['progress'] = this.progress;
data['progressImageUrl'] = this.progressImageUrl;
if (this.response != null) {
data['response'] = this.response?.toJson();
}
return data;
}
}
class MidJourneyImageResponse {
String? createdAt;
String? originatingMessageId;
List<String>? buttons;
String? imageUrl;
List<String>? imageUrls;
String? buttonMessageId;
MidJourneyImageResponse(
{this.createdAt,
this.originatingMessageId,
this.buttons,
this.imageUrl,
this.imageUrls,
this.buttonMessageId});
MidJourneyImageResponse.fromJson(Map<String, dynamic> json) {
createdAt = json['createdAt'];
originatingMessageId = json['originatingMessageId'];
buttons = json['buttons']?.cast<String>();
imageUrl = json['imageUrl'];
imageUrls = json['imageUrls']?.cast<String>();
buttonMessageId = json['buttonMessageId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['createdAt'] = this.createdAt;
data['originatingMessageId'] = this.originatingMessageId;
data['buttons'] = this.buttons;
data['imageUrl'] = this.imageUrl;
data['imageUrls'] = this.imageUrls;
data['buttonMessageId'] = this.buttonMessageId;
return data;
}
}
\ No newline at end of file
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import '../../common/style/color.dart';
import 'controller.dart';
class AIDrawImageResultPage extends GetView<AIDrawImageResultController> {
Widget makeProgressView() {
return Container(
decoration: BoxDecoration(
color: Colors.black26
),
alignment: Alignment.center,
child: Container(
width: 150,
height: 150,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(10)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
SizedBox(height: 10,),
Text("AI生成进度:${controller.progress.value}%")
],
),
),
);
}
Widget makeBottomButtonsView() {
return Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
height: 80,
child: GridView.count(
crossAxisCount: 4,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 5 / 2, // 设置按钮的宽高比
children: controller.bottomButtonTitles.value.map((e) {
return InkWell(
onTap: () {
controller.clickBottomButton(e);
},
child: Container(
height: 35,
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColor.gray3,
borderRadius: BorderRadius.circular(5)
),
child: Text(e),
),
);
}).toList(),
),
);
}
Widget makeImageView() {
return Visibility(
visible: controller.imageData.value != null,
child: InteractiveViewer(
minScale: 0.1,
maxScale: 5.0,
child: FadeInImage(
image: MemoryImage(controller.imageData.value ?? Uint8List(0)),
placeholder: MemoryImage(controller.placehoderImageData ?? Uint8List(0)),
fit: BoxFit.contain,width: Get.width
)
));
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return GetBuilder<AIDrawImageResultController>(
init: AIDrawImageResultController(),
builder: (_) => Stack(
children: [
// makeImageView(),
Scaffold(
backgroundColor: AppColor.gray1,
appBar: AppBar(
backgroundColor: Colors.black,
elevation: 0,
actions: [
Container(
padding: EdgeInsets.fromLTRB(0, 8, 0, 8),
child: InkWell(
onTap: () {
controller.share();
},
child: Container(
width: 40,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(20),
),
child: Image(image: AssetImage("assets/images/imageShare.png"),
width: 20,
height: 20,)
),
),
)
],
),
body: Obx(() {
return Container(
/*
decoration: BoxDecoration(
color: Colors.black,
image: DecorationImage(
image: NetworkImage(controller.imageUrl.value),
fit: BoxFit.cover,
),
),*/
child: Stack(
children: [
makeImageView(),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Container(
padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
decoration: BoxDecoration(
color: AppColor.gray6,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: AppColor.primary,
width: 1,
)
),
child: Text("风格:${controller.styleName.value}",
style: TextStyle(
color: AppColor.primary,
fontSize: 12
),
),
),
),
SizedBox(height: 20,),
Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Text(controller.text.value,
style: TextStyle(
color: Colors.white70,
fontSize: 14
),
),
),
SizedBox(height: 20,),
makeBottomButtonsView(),
SizedBox(height: 20,),
SafeArea(
child: Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
controller.saveNetworkImage(controller.imageUrl.value);
},
child: Container(
width: 150,
height: 44,
decoration: BoxDecoration(
color: AppColor.gray3,
borderRadius: BorderRadius.circular(22)
),
alignment: Alignment.center,
child: Text("保存原图"),
),
),
InkWell(
onTap: () {
controller.makeDrawImage();
},
child: Container(
width: 150,
height: 44,
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(22)
),
alignment: Alignment.center,
child: Text("生成同款(2金币)"),
),
),
],
),
)
),
],
),
],
)
);
}),
),
Obx(() => Visibility(
visible: controller.showProgressView.value,
child: makeProgressView(),
))
],
)
);
}
}
\ No newline at end of file
import 'package:get/get.dart';
import 'controller.dart';
class AIDrawImageBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<AIDrawImageController>(() => AIDrawImageController());
}
}
\ No newline at end of file
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
import 'package:get/get.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:pinput/pinput.dart';
import '../../common/apis/user.dart';
import '../../common/routers/names.dart';
import 'model.dart';
class AIDrawImageController extends GetxController {
late TabController tabController;
late TabController categoryController;
var model = AIDrawTextToImageModel();
var ratio = "9:16".obs;
var descriptionText = "".obs;
var styleName = "通用风格".obs;
var s = "";
ScrollController categoryScrollController = ScrollController(initialScrollOffset: 0);
TextEditingController textController = TextEditingController(text: "");
Offset startPoint = const Offset(0, 0);
RxList<AIDrawDescriptiveItem> randomDescriptionItems = RxList<AIDrawDescriptiveItem>();
var sizePictures = [
AIDrawSizePictrue(name: "手机壁纸", ratio: "9:16", imageUrl: "assets/images/v_iphone.png"),
AIDrawSizePictrue(name: "电脑壁纸", ratio: "16:9", imageUrl: "assets/images/h_iphone.png"),
AIDrawSizePictrue(name: "头像", ratio: "1:1", imageUrl: "assets/images/rect.png"),
AIDrawSizePictrue(name: "宣传海报", ratio: "3:4", imageUrl: "assets/images/v_iphone.png"),
AIDrawSizePictrue(name: "文章配图", ratio: "4:3", imageUrl: "assets/images/h_iphone.png"),
];
var styles = [
AIDrawImageStyle(s: " --s 50", imageUrl: "assets/images/通用风格.jpg", name: "通用风格", vip: ""),
AIDrawImageStyle(s: " --s 100", imageUrl: "assets/images/2.5D动漫.jpg", name: "2.5D动漫", vip: "VIP"),
AIDrawImageStyle(s: " --s 150", imageUrl: "assets/images/全能风格.jpg", name: "全能风格", vip: "VIP"),
AIDrawImageStyle(s: " --s 200", imageUrl: "assets/images/真实照片.jpg", name: "真实照片", vip: "VIP"),
AIDrawImageStyle(s: " --s 250", imageUrl: "assets/images/日系女生.jpg", name: "日系女生", vip: "VIP"),
AIDrawImageStyle(s: " --s 300", imageUrl: "assets/images/韩系写真.jpg", name: "韩系写真", vip: "VIP"),
AIDrawImageStyle(s: " --s 350", imageUrl: "assets/images/光影风格.jpg", name: "光影风格", vip: "VIP"),
AIDrawImageStyle(s: " --s 400", imageUrl: "assets/images/全能增强.jpg", name: "全能增强", vip: "VIP"),
AIDrawImageStyle(s: " --s 450", imageUrl: "assets/images/韩系女生.jpg", name: "韩系女生", vip: "VIP"),
AIDrawImageStyle(s: " --s 500", imageUrl: "assets/images/吉卜力.jpg", name: "吉卜力", vip: "VIP"),
AIDrawImageStyle(s: " --s 550", imageUrl: "assets/images/人物照片.jpg", name: "人物照片", vip: "VIP"),
AIDrawImageStyle(s: " --s 600", imageUrl: "assets/images/国风写真.jpg", name: "国风写真", vip: "VIP"),
AIDrawImageStyle(s: " --s 650", imageUrl: "assets/images/经典动漫.jpg", name: "经典动漫", vip: "VIP"),
AIDrawImageStyle(s: " --s 700", imageUrl: "assets/images/艺术感.jpg", name: "艺术感", vip: "VIP"),
];
var imageSquareTitles = [
"热门","人物","动漫","设计","未来","风景","插画","场景","脑洞","其他"
];
var textCount = 0.obs;
@override
void onInit() {
// TODO: implement onInit
super.onInit();
replaceIt();
textController.addListener(() {
textCount.value = textController.text.length;
if (textCount.value > 500) {
textController.setText(textController.text.substring(0, 500));
descriptionText.value = textController.text;
}
});
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
replaceIt() {
model.descriptives.shuffle();
randomDescriptionItems.value = [];
randomDescriptionItems.value = model.descriptives.sublist(0, 6);
}
randomInput() {
Random random = Random();
int randomIndex = random.nextInt(model.descriptives.length);
textController.setText(model.descriptives[randomIndex].description);
}
toTextMakeDrawImage() async {
EasyLoading.show(
status: "加载中",
dismissOnTap: false,
maskType: EasyLoadingMaskType.none,
indicator: LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white,
size: 30,
));
Vibrate.feedback(FeedbackType.impact);
final conversionId = await UserAPI.createConversion();
EasyLoading.dismiss();
if (conversionId == 401) {
EasyLoading.showInfo('您还为登录,请登录后体验功能。');
Get.toNamed(AppRoutes.SIGN_IN);
} else {
Get.toNamed(AppRoutes.AI_DRAW_IMAGE_RESULT_PAGE,
arguments: {
"conversionId": conversionId,
"text": textController.text,
"ratio": ratio.value,
"s": s,
"styleName": styleName.value
});
}
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'controller.dart';
class ImageSquareListView extends StatelessWidget {
late ScrollController loadingMoreController = ScrollController(initialScrollOffset: 0);
late EasyRefreshController refreshController = EasyRefreshController();
@override
Widget build(BuildContext context) {
// TODO: implement build
final controller = Get.find<AIDrawImageController>();
return Container(
child: EasyRefresh(
controller: refreshController,
header: ClassicalHeader(
bgColor: Colors.white,
textColor: Colors.pink,
infoColor: Colors.pink,
refreshReadyText: '下拉刷新',
refreshingText: '正在努力刷新',
refreshedText: '加载完成',
showInfo: true,
infoText: '正在加载中',
),
footer: ClassicalFooter(
bgColor: Colors.white,
textColor: Colors.pink,
infoColor: Colors.pink,
showInfo: true,
noMoreText: '暂时没有更多了',
loadReadyText: '上拉加载',
loadedText: '加载完毕',
loadText: '上拉加载更多',
loadingText: '正在努力加载更多',
infoText: '正在加载中',
),
child: MasonryGridView.count(
controller: loadingMoreController,
itemCount: controller.randomDescriptionItems.length,
crossAxisCount: 2,
itemBuilder: (BuildContext context, int index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image(image: AssetImage(controller.randomDescriptionItems[index].imageUrl),
fit: BoxFit.fill,
height: index % 2 == 0 ? 260 : 200,
),
);
},
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
onLoad: () async {
print('没有更多了.......');
},
onRefresh: () async {
print('下拉刷新~~~~');
},
),
);
}
}
\ No newline at end of file
import 'package:chart/pages/ai-draw-image/switch_page_view.dart';
import 'package:chart/pages/ai-draw-image/text_to_image_view.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter/gestures.dart';
import '../../common/style/color.dart';
import 'controller.dart';
import 'image_square_list_view.dart';
Widget makeTopTabView() {
final controller = Get.find<AIDrawImageController>();
return SingleChildScrollView(
controller: controller.categoryScrollController,
scrollDirection: Axis.horizontal,
child: Container(
decoration: BoxDecoration(
color: AppColor.black1,
),
height: 44,
width: controller.imageSquareTitles.length * 70,
child: TabBar(
labelStyle: TextStyle(fontSize: 14),
unselectedLabelStyle: TextStyle(fontSize: 14),
indicator: BoxDecoration(
color: Colors.transparent, // 设置背景颜色
),
controller: controller.categoryController,
tabs: controller.imageSquareTitles.map((e) {
return Tab(text: e);
}).toList(),
onTap: (value) {
},
),
),
);
}
Widget makeTabContentView() {
final controller = Get.find<AIDrawImageController>();
return Container(
child: TabBarView(
controller: controller.categoryController,
children: controller.imageSquareTitles.asMap().map((index, v) {
final widget = ImageSquareListView();
if (index == 0) {
return MapEntry<int, Widget>(index,
Listener(
onPointerDown: (PointerDownEvent event) {
// 记录按下的位置
controller.startPoint = event.position;
},
onPointerMove: (event) {
var xDis = event.position.dx - controller.startPoint.dx;
var yDis = event.position.dy - controller.startPoint.dy;
if (xDis.abs() > yDis.abs()) {
// 计算滑动的距离
double distance = event.position.dx - controller.startPoint.dx;
// 判断滑动的方向
if (distance > 0) {
// 向右滑动
controller.tabController.animateTo(1);
} else if (distance < 0) {
// 向左滑动
// TODO: 处理向左滑动的逻辑
}
}
},
child: widget, // 需要处理右滑事件的小部件
)
);
}
return MapEntry<int, Widget>(index, widget);
}).values.toList() as List<Widget>
),
);
}
Widget makeImageSquareView() {
final controller = Get.find<AIDrawImageController>();
return SwitchPageView(
length: controller.imageSquareTitles.length,
buildCallback: (categoryController) {
controller.categoryController = categoryController;
categoryController.addListener(() {
final contentOffsetX = categoryController.index * Get.width;
final contentSize = controller.imageSquareTitles.length * 70;
var tempItemWidth = 70.0;
var startOffsetIndex = (Get.width / tempItemWidth) / 2.0;
var localOffsetX = contentOffsetX * (tempItemWidth / Get.width) - tempItemWidth * startOffsetIndex;
if (localOffsetX < 0) {
localOffsetX = 0.0;
} else if (contentSize - Get.width < localOffsetX){
localOffsetX = contentSize - Get.width;
}
controller.categoryScrollController.animateTo(localOffsetX, duration: const Duration(milliseconds: 100), curve: Curves.linear);
});
return Column(
children: [
makeTopTabView(),
Expanded(child: makeTabContentView(),),
],
);
},
);
}
\ No newline at end of file
import 'package:chart/pages/ai-draw-image/text_to_image_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../common/style/color.dart';
import 'controller.dart';
Widget makeInsertPictureView() {
// 插入图片
return Container(
height: 220,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
decoration: BoxDecoration(
color: AppColor.gray3,
borderRadius: BorderRadius.circular(20)
),
child: LayoutBuilder(builder: (context, constraints) {
return Column(
children: [
makeSectionTitleView("01.", "插入图片"),
SizedBox(height: 10,),
InkWell(
onTap: () {},
child: Container(
height: 160,
width: constraints.maxWidth - 20,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
decoration: BoxDecoration(
color: AppColor.black1,
borderRadius: BorderRadius.circular(10)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(image: AssetImage("assets/images/jifen1.png", ), width: 20, height: 20,),
SizedBox(height: 20,),
Text("支持图片格式:JPG/PNG,低于10M",
style: TextStyle(
fontSize: 12
),
),
]
),
),
),
],
);
},)
);
}
Widget makeStyleSelectionItem(int index) {
final controller = Get.find<AIDrawImageController>();
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
// color: Colors.red
),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Column(
children: [
Stack(
children: [
Container(
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image(image: AssetImage(controller.styles[index].imageUrl),
fit: BoxFit.fill,
width: constraints.maxWidth,
height: constraints.maxHeight - 30,
),
),
),
Positioned(
right: 15,
top: 8,
child: Container(
padding: EdgeInsets.fromLTRB(5, 2, 5, 2),
decoration: BoxDecoration(
color: AppColor.yellow1,
borderRadius: BorderRadius.circular(5),
),
child: Text("VIP",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold
),
),
),
)
],
),
SizedBox(height: 5,),
Text("通用风格")
],
);
},
)
);
}
Widget makeStyleSelectionView() {
final controller = Get.find<AIDrawImageController>();
// 风格选择
return Container(
height: 320,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
decoration: BoxDecoration(
color: AppColor.gray3,
borderRadius: BorderRadius.circular(20)
),
child: Column(
children: [
makeSectionTitleView("02.", "选择风格"),
SizedBox(height: 10,),
Divider(
color: AppColor.black1,
thickness: 1,
height: 10,
),
SizedBox(height: 15,),
Expanded(
child: GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 5, // 设置垂直间距
childAspectRatio: 200 / 140, // 高宽比
scrollDirection: Axis.horizontal,
children: List.generate(controller.styles.length, (index) {
return InkWell(
onTap: () {},
child: makeStyleSelectionItem(index)
);
}),
),
),
],
),
);
}
Widget makeImageToImageView() {
return Stack(
children: [
SingleChildScrollView(
scrollDirection: Axis.vertical,
padding: EdgeInsets.fromLTRB(10, 10, 10, 70),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// tip
Container(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("AI绘图",
style: TextStyle(
fontWeight: FontWeight.bold
),
),
Text("设计的革命,从这里开始",
style: TextStyle(
fontSize: 12
),)
],
),
),
SizedBox(height: 20,),
makeInsertPictureView(),
SizedBox(height: 20,),
makeStyleSelectionView(),
],
),
),
),
Positioned(
child: Padding(padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: InkWell(
onTap: () {},
child: Container(
height: 50,
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(25),
),
child: Text("立即生成(消耗2金币)"),
),
),
),
bottom: 10,
width: Get.width,)
],
);
}
\ No newline at end of file
class AIDrawSizePictrue {
String name;
String ratio;
String imageUrl;
AIDrawSizePictrue({required this.name, required this.ratio, required this.imageUrl});
}
class AIDrawImageStyle {
String name;
String s;
String imageUrl;
String vip;
AIDrawImageStyle({required this.name, required this.s, required this.imageUrl, required this.vip});
}
class AIDrawDescriptiveItem {
String typeName;
String imageUrl;
String description;
AIDrawDescriptiveItem({required this.typeName, required this.imageUrl, required this.description});
}
class AIDrawTextToImageModel {
// 描述词
var descriptives = [
AIDrawDescriptiveItem(typeName: "场景", imageUrl: "assets/images/Trump_wears.jpg", description: "Trump wears Chinese Hanfu and smiles"),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/Hyperrealism.jpg", description: "Hyperrealism art in the style of Alex Grey, Reflection, Hajime Sorayama --s 200 --chaos 15 --version 5.2 --upbeta"),
AIDrawDescriptiveItem(typeName: "风景", imageUrl: "assets/images/cyberpunk_delapidated.jpg", description: "cyberpunk delapidated brick wall night alley background --q 2"),
AIDrawDescriptiveItem(typeName: "热门", imageUrl: "assets/images/shapes_art.jpg", description: "shapes art, circle, simple, 2D, no people, orange pink tone, mobility, cars, electric, bicycle, Photorealism, cloud --v 5"),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/a_colorful.jpg", description: "a colorful skull is playing a ukulele, in the style of 32k uhd, kawaii aesthetic, bokeh, movie still, guatemalan art,clay animation --v 5 --q 2"),
AIDrawDescriptiveItem(typeName: "热门", imageUrl: "assets/images/cartoon_illustration.jpg", description: "cartoon illustration of a 4 year old girl with tanned skin long wavy light brown hair brown eyes. Sunny and bright colours. She is wearing a colourful dress and she is Native. She is standing outside happily looking above. Smiling at the blue sky. She is adorable."),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/a_raver_girl.jpg", description: "a raver girl in black boots with her hair down covering one eye"),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/generate_a_inspiring.jpg", description: "Generate a inspiring and empowering Christian Church logo colorful and minimal"),
AIDrawDescriptiveItem(typeName: "风景", imageUrl: "assets/images/coloring_page.jpg", description: "coloring page, black outline and white background, monochrome, no shading, clean thick line art, low detail, surreal illusion fantasy landscape concept art made of clouds"),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/logo_Concept.jpg", description: "Logo Concept: \"Cash Offer\": An eye-catching design with a dollar sign (\$) neatly embedded within a house silhouette. This encapsulates the idea of immediate purchase. Stick to a color palette of navy blue, black, and cream."),
AIDrawDescriptiveItem(typeName: "人物", imageUrl: "assets/images/we_see.jpg", description: "We see a 12 year old girl and boy in summer clothes laughing and running. Camera see them from high above and waist up only. Behind and below them there is a greenish sea with many sailboats with colorful sails and above a blue sky of a sunny day. In middle of the sea there is a tall futuristic tower at the distance -"),
AIDrawDescriptiveItem(typeName: "风景", imageUrl: "assets/images/natural_scenery.jpg", description: "Natural scenery, scenery, blue sky, white clouds, flowers, bees, big trees, photograph-like, layered landscapes, referential painting, light blue and green, grass, red and yellow flower, Minecraft game style, blooming flowers, 8k, dreamy, divine cinematic edge lighting")
];
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class SwitchPageView extends StatefulWidget {
Widget Function(TabController tabController) buildCallback;
int length;
SwitchPageView({required this.length, required this.buildCallback});
@override
_SwitchControllerState createState() => _SwitchControllerState(length: this.length, buildCallback: this.buildCallback);
}
class _SwitchControllerState extends State<SwitchPageView> with SingleTickerProviderStateMixin {
late TabController _tabController;
int length;
Widget Function(TabController tabController) buildCallback;
_SwitchControllerState({required this.length, required this.buildCallback});
@override
void initState() {
super.initState();
_tabController = TabController(length: this.length, vsync: this);
_tabController.addListener(_handleTabSelection);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
void _handleTabSelection() {
if (!_tabController.indexIsChanging) {
setState(() {});
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return GestureDetector(
onTap: () {
Get.focusScope?.unfocus();
},
child: buildCallback(_tabController),
);
}
// ...
}
\ No newline at end of file
This diff is collapsed.
import 'package:chart/pages/ai-draw-image/switch_page_view.dart';
import 'package:chart/pages/ai-draw-image/text_to_image_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import '../../common/style/color.dart';
import 'controller.dart';
import 'image_square_view.dart';
import 'image_to_image_view.dart';
class AIDrawImagePage extends GetView<AIDrawImageController> {
late var controller = Get.find<AIDrawImageController>();
AIDrawImagePage({Key? key}) : super(key: key);
var myTabs = [
Tab(text: '文生图'),
Tab(text: '图生图'),
Tab(text: '图片广场'),
];
Widget makeTopTabView() {
return Padding(padding: EdgeInsets.fromLTRB(10, 20, 10, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {},
child: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: AppColor.gray1,
borderRadius: BorderRadius.circular(15),
),
child: Align(alignment: Alignment.center,
child: Image(image: AssetImage("assets/images/jifen1.png", ), width: 20, height: 20,)
),
),
),
Container(
decoration: BoxDecoration(
color: AppColor.gray1,
borderRadius: BorderRadius.circular(15)
),
height: 30,
width: 270,
child: TabBar(
labelStyle: TextStyle(fontSize: 14),
unselectedLabelStyle: TextStyle(fontSize: 14),
indicator: BoxDecoration(
color: AppColor.primary, // 设置背景颜色
borderRadius: BorderRadius.circular(15), // 设置圆角
),
controller: controller.tabController,
tabs: myTabs,
onTap: (value) {
},
),
),
InkWell(
onTap: () {},
child: Container(
height: 30,
decoration: BoxDecoration(
color: AppColor.gray1,
borderRadius: BorderRadius.circular(15),
),
child: Padding(padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(
children: [
Image(image: AssetImage("assets/images/jifen1.png", ), width: 20, height: 20,),
SizedBox(width: 5),
Text("0"),
],
),
),
),
),
],
),
);
}
Widget makeTabContentView() {
return Container(
child: TabBarView(
controller: controller.tabController,
children: [
makeTextToImageView(),
makeImageToImageView(),
Container(
decoration: BoxDecoration(color: AppColor.black1),
child: makeImageSquareView(),
)
]
),
);
}
Widget makeContentView() {
return SwitchPageView(
length: 3,
buildCallback: (tabController) {
tabController.addListener(() {
Get.focusScope?.unfocus();
});
controller.tabController = tabController;
return Column(
children: [
makeTopTabView(),
Expanded(child: makeTabContentView(),),
],
);
},
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return GetBuilder<AIDrawImageController>(
init: AIDrawImageController(),
builder: (_) => Scaffold(
body: Stack(
children: [
Image(
image: AssetImage("assets/images/top_ai_draw_image.jpeg"),
height: 300,
width: Get.width,
fit: BoxFit.fitWidth,
),
SafeArea(
child: makeContentView()
),
],
),
)
);
}
}
\ No newline at end of file
......@@ -219,7 +219,7 @@ class ApplicationController extends GetxController {
// handleIncomingLinks();
// 准备一些静态数据
tabTitles = ['AI对话', '创作', '私人助理', '我的'];
tabTitles = ['AI对话', '创作', '私人助理', 'AI绘图'];
bottomTabs = <BottomNavigationBarItem>[
// ignore: unnecessary_new
const BottomNavigationBarItem(
......@@ -247,6 +247,15 @@ class ApplicationController extends GetxController {
label: '私人助理',
backgroundColor: AppColors.primaryBackground,
),
const BottomNavigationBarItem(
icon: Image(
image: AssetImage("assets/images/assistant.png"), width: 30.0),
activeIcon: Image(
image: AssetImage("assets/images/assistant-selected.png"),
width: 30.0),
label: 'AI绘图',
backgroundColor: AppColors.primaryBackground,
),
];
pageController = PageController(initialPage: state.page);
// await _speechToText.initialize();
......
......@@ -19,6 +19,7 @@ import 'package:highlight/languages/autoit.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
// import 'package:text_editor/text_editor.dart';
// import '../dashboard/dashboard_page.dart';
import '../ai-draw-image/view.dart';
import 'index.dart';
class ApplicationPage extends GetView<ApplicationController> {
......@@ -57,6 +58,7 @@ class ApplicationPage extends GetView<ApplicationController> {
HomePage(),
CreationPage(),
AssistantPage(),
AIDrawImagePage(),
// MyPage()
]);
}
......
......@@ -901,6 +901,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.17"
image_gallery_saver:
dependency: "direct main"
description:
name: image_gallery_saver
sha256: "467de169167b5c4e1ddde65395e4653c336a82f760b6700ea295085b7f2dd248"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
image_picker:
dependency: "direct main"
description:
......
......@@ -132,6 +132,7 @@ dependencies:
sqflite: ^2.2.7
fluwx: ^3.13.1
flutter_native_splash: ^2.2.19
image_gallery_saver: '^2.0.2'
# package:bubble/bubble.dart
dev_dependencies:
......
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