ar_tourism_flutter_unity/lib/components/work_edit copy.dart
2025-05-14 17:04:13 +08:00

607 lines
17 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:io';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import '../pages/center/fullScreenImg.dart';
import '../pages/mine/drafts.dart';
import '../pages/mine/work/works.dart';
import 'gradientButton.dart';
import 'work_utils.dart';
class WorkEditor extends StatefulWidget {
final String? initialImage;
final String? initialTitle;
final String? initialContent;
final String? workId;
final AssetEntity? selectedAsset;
final bool isEditMode;
final bool isNetworkImage;
final bool isFromDrafts;
const WorkEditor({
super.key,
this.initialImage,
this.initialTitle,
this.initialContent,
this.workId,
this.selectedAsset,
this.isEditMode = false,
this.isNetworkImage = false,
this.isFromDrafts = false,
});
@override
State<WorkEditor> createState() => _WorkEditorState();
}
class _WorkEditorState extends State<WorkEditor> {
final TextEditingController titleController = TextEditingController();
final TextEditingController contentController = TextEditingController();
AssetEntity? currentAsset;
String? currentImage;
VideoPlayerController? videoController;
int _titleLength = 0;
int _contentLength = 0;
File? _cachedFile;
@override
void initState() {
super.initState();
titleController.text = widget.initialTitle ?? '';
contentController.text = widget.initialContent ?? '';
currentAsset = widget.selectedAsset;
currentImage = widget.initialImage;
_titleLength = titleController.text.length;
_contentLength = contentController.text.length;
titleController.addListener(() {
setState(() {
_titleLength = titleController.text.length;
});
});
contentController.addListener(() {
setState(() {
_contentLength = contentController.text.length;
});
});
if (currentAsset?.type == AssetType.video) {
_initializeVideoPlayer();
}
}
@override
void didUpdateWidget(WorkEditor oldWidget) {
super.didUpdateWidget(oldWidget);
// 如果selectedAsset改变了更新currentAsset
if (widget.selectedAsset != oldWidget.selectedAsset && widget.selectedAsset != null) {
// 清除旧的缓存
_cachedFile = null;
setState(() {
currentAsset = widget.selectedAsset;
if (widget.selectedAsset!.type == AssetType.video) {
videoController?.dispose();
_initializeVideoPlayer();
}
});
// 预加载新的文件
_loadAssetFile();
}
}
// 添加加载资产文件的辅助方法
Future<void> _loadAssetFile() async {
if (currentAsset != null) {
_cachedFile = await currentAsset!.file;
if (mounted) {
setState(() {});
}
}
}
@override
void dispose() {
// 清理缓存
_cachedFile = null;
titleController.dispose();
contentController.dispose();
videoController?.dispose();
super.dispose();
}
Future<void> _initializeVideoPlayer() async {
if (currentAsset == null) return;
final file = await currentAsset!.file;
if (file != null) {
videoController = VideoPlayerController.file(file)
..initialize().then((_) {
setState(() {});
});
}
}
void _handleImageTap() async {
if (currentAsset != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullscreenImagePage(
asset: currentAsset!,
onReplace: (newAsset) async {
// 清除旧的缓存
_cachedFile = null;
setState(() {
currentAsset = newAsset;
if (newAsset.type == AssetType.video) {
videoController?.dispose();
_initializeVideoPlayer();
}
});
// 预加载新的文件
_cachedFile = await newAsset.file;
},
),
),
);
} else {
_pickAsset();
}
}
Future<void> _pickAsset() async {
final List<AssetEntity>? result = await AssetPicker.pickAssets(
context,
pickerConfig: AssetPickerConfig(
maxAssets: 1,
themeColor: const Color(0xff7CDBC8),
textDelegate: const AssetPickerTextDelegate(),
requestType: RequestType.image,
specialItemPosition: SpecialItemPosition.none,
specialItemBuilder: null,
shouldRevertGrid: false,
selectedAssets: currentAsset != null ? [currentAsset!] : null,
gridCount: 4,
pathThumbnailSize: const ThumbnailSize.square(80),
selectPredicate: (BuildContext context, AssetEntity asset, bool isSelected) {
return true;
},
),
);
if (result != null && result.isNotEmpty) {
// 清除旧的缓存
_cachedFile = null;
setState(() {
currentAsset = result.first;
if (result.first.type == AssetType.video) {
videoController?.dispose();
_initializeVideoPlayer();
}
});
// 预加载新的文件
_cachedFile = await result.first.file;
}
}
void _showErrorMessage(String error) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'保存失败: $error',
textAlign: TextAlign.center,
),
behavior: SnackBarBehavior.floating,
backgroundColor: const Color.fromRGBO(255, 0, 0, 0.9),
duration: const Duration(seconds: 2),
),
);
}
void _showSuccessMessage(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
message,
textAlign: TextAlign.center,
),
behavior: SnackBarBehavior.floating,
backgroundColor: const Color.fromRGBO(43, 46, 61, 0.9),
duration: const Duration(seconds: 2),
),
);
}
Future<void> _handleSaveAndNavigate(String status) async {
if (!mounted) return;
// print('开始保存操作');
// print('isEditMode: ${widget.isEditMode}');
// print('isFromDrafts: ${widget.isFromDrafts}');
// print('status: $status');
try {
final content = _getContent();
// print('准备保存的内容: $content');
if (widget.isEditMode) {
// print('执行编辑模式保存');
await WorkUtils.handleEditSave(context, content, status);
} else {
// print('执行创建模式保存');
await WorkUtils.handleNewSave(context, content, status);
}
if (!mounted) return;
// print('开始处理导航');
await _handleNavigation(status);
} catch (e) {
// print('保存过程出错: $e');
if (!mounted) return;
_showErrorMessage(e.toString());
}
}
Future<void> _handleNavigation(String status) async {
if (!mounted) return;
// print('进入_handleNavigation');
// print('isEditMode: ${widget.isEditMode}');
// print('isFromDrafts: ${widget.isFromDrafts}');
// print('status: $status');
if (!widget.isEditMode) {
// print('执行新建模式导航');
await _handleNewWorkNavigation(status);
} else if (widget.isFromDrafts) {
// print('执行草稿箱编辑模式导航');
await _handleDraftsEditNavigation(status);
} else {
// print('执行作品集编辑模式导航');
await _handleWorksEditNavigation(status);
}
}
Future<void> _handleNewWorkNavigation(String status) async {
if (!mounted) return;
if (status == "1") {
// 发布 - 跳转到首页 tab1
await Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 1},
);
_showSuccessMessage('作品已创建成功,快去发布吧');
} else {
// 存草稿 - 跳转到首页 tab0
await Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 0},
);
_showSuccessMessage('作品已存入草稿箱');
}
}
Future<void> _handleDraftsEditNavigation(String status) async {
if (!mounted) return;
if (status == "1") {
// 如果是发布,跳转到首页 tab1发布界面
await Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 1},
);
if (!mounted) return;
_showSuccessMessage('作品已发布成功');
} else {
// 如果是存草稿,直接返回上一级
Navigator.of(context).pop(true);
// if (!mounted) return;
// _showSuccessMessage('作品已更新到草稿箱');
}
}
Future<void> _handleWorksEditNavigation(String status) async {
if (!mounted) return;
if (status == "1") {
// 如果是发布,跳转到首页 tab1发布界面
await Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 1},
);
} else {
// 如果是存草稿,先跳转到草稿箱页面,然后在草稿箱页面返回时跳转到我的页面
await Navigator.pushNamed(
context,
'/drafts',
).then((_) {
Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 4},
);
});
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: _handleImageTap,
child: _buildMediaPreview(),
),
const SizedBox(height: 16),
_buildTextField(
controller: titleController,
hintText: '填写标题',
isTitle: true,
),
const SizedBox(height: 16),
_buildTextField(
controller: contentController,
hintText: '添加正文',
isTitle: false,
),
],
),
),
),
),
Container(
color: const Color(0xff0C0C16),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 20, // 适配底部安全区
left: 16,
right: 16,
top: 10,
),
child: _buildActionButtons(),
),
],
);
}
Widget _buildMediaPreview() {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(8),
),
child: AspectRatio( // 使用 AspectRatio 固定宽高比为 1:1
aspectRatio: 1,
child: _buildMediaContent(),
),
),
);
}
Widget _buildMediaContent() {
if (widget.isNetworkImage && currentImage != null) {
return GestureDetector(
onTap: () => _handleNetworkImageTap(),
child: FittedBox( // 使用 FittedBox 控制子组件的缩放行为
fit: BoxFit.cover,
clipBehavior: Clip.hardEdge,
child: Image.network(
currentImage!,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return const Center(child: Text('加载失败'));
},
),
),
);
}
if (currentAsset != null) {
// 使用缓存的文件
if (_cachedFile != null) {
if (currentAsset!.type == AssetType.video) {
return videoController != null && videoController!.value.isInitialized
? AspectRatio(
aspectRatio: videoController!.value.aspectRatio,
child: VideoPlayer(videoController!),
)
: const Center(child: CircularProgressIndicator());
}
return Image.file(_cachedFile!, fit: BoxFit.cover);
}
return FutureBuilder<File?>(
future: currentAsset!.file,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
// 缓存文件
_cachedFile = snapshot.data;
if (currentAsset!.type == AssetType.video) {
return videoController != null &&
videoController!.value.isInitialized
? AspectRatio(
aspectRatio: videoController!.value.aspectRatio,
child: VideoPlayer(videoController!),
)
: const Center(child: CircularProgressIndicator());
}
return Image.file(snapshot.data!, fit: BoxFit.cover);
}
return const Center(child: CircularProgressIndicator());
},
);
}
// 无图片时显示添加图片图标
return const Center(
child: Icon(
Icons.add_circle_outline,
color: Color(0xFFC1C1C1),
size: 32,
),
);
}
Widget _buildTextField({
required TextEditingController controller,
required String hintText,
bool isTitle = false,
}) {
return Container(
child: Stack(
children: [
TextField(
controller: controller,
maxLength: isTitle ? 15 : 500,
maxLines: isTitle ? 1 : 10,
textAlign: isTitle ? TextAlign.left : TextAlign.justify, // 添加两端对齐
style: TextStyle(
color: Colors.white,
fontSize: isTitle ? 16 : 14,
height: isTitle ? 1.0 : 1.5, // 设置行距标题1.0正文1.5
),
cursorColor: const Color(0xFF7CDBC8), // 设置光标颜色
cursorWidth: 2, // 设置光标宽度
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(
color: const Color(0xFFC1C1C1),
fontSize: isTitle ? 16 : 14,
height: isTitle ? 1.0 : 1.5, // 提示文本也使用相同的行距
),
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
counterText: '', // 隐藏默认计数器
contentPadding: EdgeInsets.only( // 添加底部padding为计数器留出空间
bottom: isTitle ? 8 : 24,
),
),
),
Positioned(
right: 8,
bottom: 8,
child: Text(
'${isTitle ? _titleLength : _contentLength}/${isTitle ? 15 : 500}',
style: const TextStyle(
color: Color(0xFFC1C1C1),
fontSize: 12,
),
),
),
],
),
);
}
Widget _buildActionButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildDraftButton(),
_buildPublishButton(),
],
);
}
Widget _buildDraftButton() {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Image.asset(
'images/save_drafts.png',
width: 31,
height: 31,
),
onPressed: () => _handleSaveAndNavigate("0"),
),
Transform.translate(
offset: const Offset(0, -8),
child: const Text(
"存草稿",
style: TextStyle(
fontSize: 10,
color: Color(0xFFC1C1C1),
),
),
),
],
);
}
Widget _buildPublishButton() {
return GradientButton(
width: 240,
height: 41,
text: '保存并发布',
onPressed: () => _handleSaveAndNavigate("1"),
);
}
Map<String, dynamic> _getContent() {
if (widget.isEditMode) {
// 编辑模式
return {
"workId": widget.workId,
"workName": titleController.text,
"detail": contentController.text,
"workAddress": currentImage,
};
} else {
// 创建模式
if (currentAsset == null) {
// 如果未选择图片,提示用户
throw "请先选择一张图片";
}
return {
"workname": titleController.text,
"detail": contentController.text,
"asset": currentAsset,
};
}
}
void _handleNetworkImageTap() async {
final List<AssetEntity>? result = await AssetPicker.pickAssets(
context,
pickerConfig: const AssetPickerConfig(maxAssets: 1 ,textDelegate: AssetPickerTextDelegate(), ),
);
if (result != null && result.isNotEmpty) {
setState(() {
currentAsset = result.first;
currentImage = null;
});
}
}
}