import 'dart:convert';
import 'dart:html';
import 'dart:typed_data';
import 'package:dio/dio.dart' as adio;
import 'package:dio/dio.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:link/view/preview.dart';
import 'package:web_smooth_scroll/web_smooth_scroll.dart';
import '../constants.dart';
import '../utils/api.dart';
import '../utils/http_utils.dart';
import '../utils/size_fit.dart';
import '../utils/storage.dart';
import 'component/link_btn.dart';
import 'component/link_step.dart';
import 'component/toast.dart';
import 'component/top_container.dart';
import 'component/upload_file.dart';
import 'component/web_image.dart';
class EditLink extends StatefulWidget {
const EditLink({Key? key}) : super(key: key);
@override
State createState() => _EditLinkState();
}
class _EditLinkState extends State {
TextEditingController controller = TextEditingController();
TextEditingController titleController = TextEditingController();
TextEditingController descController = TextEditingController();
FileUploadInputElement uploadInput = FileUploadInputElement();
bool isLink = true;
bool showError = false;
Uint8List? chooseImage;
String strLink = '';
String strTitle = '';
String strDesc = '';
String imgUrl = '';
bool isFirstEnter = true;
var social;
late List types;
late ScrollController scrollController;
@override
void initState() {
// TODO: implement initState
scrollController = ScrollController();
Map data = Get.parameters;
social = jsonDecode(data['social']);
types = social['types'];
if (types[0] == 'LINK') {
isLink = true;
} else {
isLink = false;
}
getDetail();
super.initState();
}
@override
dispose(){
controller.dispose();
titleController.dispose();
descController.dispose();
scrollController.dispose();
super.dispose();
}
chooseFile() async {
uploadInput.accept = '.png,.jpg,.jpeg';
uploadInput.multiple = false;
uploadInput.click();
uploadInput.onChange.listen((e) {
final files = uploadInput.files;
if (files?.length == 1) {
FileReader reader = FileReader();
reader.onLoadEnd.listen((event) {
setState(() {
chooseImage = reader.result as Uint8List;
});
});
reader.readAsArrayBuffer(files![0]);
}
});
}
Future getDetail() async {
String id = Get.parameters['id']!;
var data = await HttpUtils.get(Api.userSocials + '/$id');
setState(() {
if (data['type'] == 'LINK') {
isLink = true;
controller.text = data['user_url'];
strLink = data['user_url'];
} else {
isLink = false;
}
strTitle = data['user_nick'];
titleController.text = data['user_nick'];
strDesc = data['description'];
descController.text = data['description'];
});
}
intro() {
Color tapColor = kBtnColor;
if (isLink) {
if (strLink.isNotEmpty) {
tapColor = const Color(0xFFA5A5AD);
}
} else {
if (chooseImage != null) {
tapColor = const Color(0xFFA5A5AD);
}
}
return Container(
color: showError ? const Color(0xFF002FFF) : Colors.transparent,
padding: EdgeInsets.only(
left: 20.px,
right: 20.px,
top: showError ? 12.px : 0,
bottom: showError ? 12.px : 0),
child: Column(
children: [
Row(
children: [
Container(
width: 12.px,
height: 12.px,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.px),
border: Border.all(color: kThemeColor, width: 1.px)),
child: Text(
'1',
style: TextStyle(
color: kThemeColor,
fontFamily: 'Link1',
fontWeight: FontWeight.w800,
fontSize: 8.px),
),
),
SizedBox(
width: 3.px,
),
Text(
'去『已选平台-我』找到「',
style:
TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
),
Text(
isLink ? '分享-复制链接' : '我的二维码',
style: TextStyle(
color: const Color(0xFFA5A5AD),
fontSize: 12.px,
fontWeight: FontWeight.bold),
),
Text(
isLink ? '」' : '」保存',
style:
TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
),
],
),
SizedBox(
height: 5.px,
),
Row(
children: [
Container(
width: 12.px,
height: 12.px,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.px),
border: Border.all(color: kThemeColor, width: 1.px)),
child: Text(
'2',
style: TextStyle(
color: kThemeColor,
fontFamily: 'Link1',
fontWeight: FontWeight.w800,
fontSize: 8.px),
),
),
SizedBox(
width: 3.px,
),
Text(
'回到此处',
style:
TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
),
SizedBox(
width: 3.px,
),
if (!isLink && chooseImage == null)
UploadFile(
child: Text(
'上传二维码',
style: TextStyle(
color: tapColor,
fontSize: 12.px,
fontWeight: FontWeight.bold),
),
callback: (Uint8List file) {
setState(() {
chooseImage = file;
showError = false;
});
},
),
if (isLink || (chooseImage != null))
GestureDetector(
onTap: () {
if (isLink) {
if (strLink.isEmpty) {
getClipData();
}
} else {
if (chooseImage == null) {
chooseFile();
}
}
},
child: Text(
isLink ? '粘贴链接' : '上传二维码',
style: TextStyle(
color: tapColor,
fontSize: 12.px,
fontWeight: FontWeight.bold),
),
)
],
),
],
),
);
}
switchWarn() {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 32.px, bottom: 32.px),
child: Column(
children: [
SvgPicture.asset(
'assets/icons/question.svg',
width: 48.px,
height: 48.px,
),
SizedBox(
height: 12.px,
),
Text(
isLink
? '切换选择「二维码」\n将使现有「链接」不被展示\n确定要切换吗?'
: '切换选择「链接」\n将使现有「二维码」不被展示\n确定要切换吗?',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16.px,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 16.px,
),
AlertButton(
title: '确定',
isCancel: false,
width: 220.px,
height: 40.px,
callback: () {
Toast().hideHud();
setState(() {
showError = false;
if (isLink) {
strLink = '';
isLink = false;
} else {
chooseImage = null;
isLink = true;
}
});
}),
SizedBox(
height: 24.px,
),
AlertButton(
title: '再想想',
isCancel: true,
width: 220.px,
height: 40.px,
callback: () {
Toast().hideHud();
}),
],
),
);
}
switchType() {
if (isLink && strLink.isNotEmpty) {
Toast().showCustomHud(switchWarn(), context: context);
return;
}
if (!isLink && chooseImage != null) {
Toast().showCustomHud(switchWarn(), context: context);
return;
}
setState(() {
showError = false;
isLink = !isLink;
});
}
preview() {
Toast().showText('长按图片识别或保存', context: context);
showDialog(
context: context,
barrierDismissible: false,
barrierColor: Colors.transparent,
useSafeArea: false,
builder: (BuildContext context) {
return Preview(
memory: chooseImage,
);
});
}
Future getClipData() async {
await Clipboard.getData(Clipboard.kTextPlain).then((value) {
if (value != null && value.text != null) {
setState(() {
strLink = value.text!;
controller.text = strLink;
});
}
});
}
content() {
return Column(
children: [
SizedBox(
height: 32.px,
),
Container(
width: 343.px,
padding: EdgeInsets.all(20.px),
margin: EdgeInsets.only(bottom: 20.px),
decoration: BoxDecoration(
color: const Color(0xFF2C2C2E),
borderRadius: BorderRadius.circular(24.px)),
child: GestureDetector(
onTap: () {
Toast().showInfoText('已添加的链接不能更改平台\n建议重新添加新链接\n并删除原有错误的链接',
context: context);
},
child: Row(
children: [
Expanded(
child: Text(
'已选平台',
style: TextStyle(
color: kThemeColor,
fontSize: 16.px,
fontWeight: FontWeight.bold),
)),
// ClipRRect(
// borderRadius: BorderRadius.circular(6.px),
// child: social['logo'].length == 0
// ? SvgPicture.asset(
// 'assets/icons/other_link.svg',
// width: 24.px,
// height: 24.px,
// )
// : WebImage(
// url: social['logo'], width: 24.px, height: 24.px),
// ),
social['logo'].length == 0
? ClipRRect(
borderRadius: BorderRadius.circular(6.px),
child: SvgPicture.asset(
'assets/icons/other_link.svg',
width: 24.px,
height: 24.px,
))
: WebImage(
url: social['logo'],
width: 24.px,
height: 24.px,
borderRadius: 6.px,
),
SizedBox(
width: 8.px,
),
Text(
social['name'],
style: TextStyle(
color: const Color(0xFFA5A5AD), fontSize: 14.px),
),
Image.asset(
'assets/images/arrow_right.png',
width: 20.px,
height: 20.px,
)
// SvgPicture.asset(
// 'assets/icons/arrow_right.svg',
// width: 20.px,
// height: 20.px,
// color: const Color(0xFFA5A5AD),
// )
],
)),
),
Container(
width: 343.px,
padding: EdgeInsets.only(top: 20.px, bottom: 20.px),
margin: EdgeInsets.only(bottom: 20.px),
decoration: BoxDecoration(
color: const Color(0xFF2C2C2E),
borderRadius: BorderRadius.circular(24.px)),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 20.px,
),
Expanded(
child: Text(
'链接方式',
style: TextStyle(
color: kThemeColor,
fontSize: 16.px,
fontWeight: FontWeight.bold),
)),
Container(
height: 28.px,
// width: 98.px,
decoration: BoxDecoration(
color: const Color(0xFF131314),
borderRadius: BorderRadius.circular(14.px)),
child: Row(
children: [
Container(
padding: EdgeInsets.only(left: 10.px, right: 10.px),
height: 28.px,
decoration: BoxDecoration(
color: kThemeColor,
borderRadius: BorderRadius.circular(14.px)),
child: Row(
children: [
SvgPicture.asset(
isLink
? 'assets/icons/link.svg'
: 'assets/icons/qrcode.svg',
width: 16.px,
height: 16.px,
color: const Color(0xFF131314),
),
SizedBox(
width: 2.px,
),
Text(
isLink ? '链接' : '二维码',
style: TextStyle(
color: const Color(0xFF131314),
fontSize: 12.px),
)
],
),
),
if (types.length > 1)
GestureDetector(
onTap: () {
switchType();
},
child: Container(
alignment: Alignment.center,
width: 36.px,
height: 28.px,
child: SvgPicture.asset(
isLink
? 'assets/icons/qrcode.svg'
: 'assets/icons/link.svg',
width: 16.px,
height: 16.px,
color: const Color(0xFF74747A),
),
),
)
],
),
),
SizedBox(
width: 20.px,
)
],
),
SizedBox(
height: 8.px,
),
intro(),
// SizedBox(
// height: 28.px,
// ),
SizedBox(
height: 16.px,
),
if (isLink)
Row(
children: [
SizedBox(
width: 20.px,
),
Expanded(
child: TextField(
controller: controller,
cursorColor: kBtnColor,
onChanged: (value) {
setState(() {
strLink = value;
showError = false;
// keyword = value;
});
},
style: TextStyle(
color: Colors.white,
fontSize: 14.px,
fontFamily: 'Link1'),
decoration: InputDecoration(
border: InputBorder.none,
hintText: '请输入链接',
hintStyle: TextStyle(
fontSize: 14.px, color: const Color(0xFF444447)),
counterText: "",
),
),
),
if (strLink.isEmpty)
GestureDetector(
onTap: () {
getClipData();
},
child: SvgPicture.asset(
'assets/icons/copy_link.svg',
width: 24.px,
height: 24.px,
color: kBtnColor,
),
),
SizedBox(
width: 20.px,
),
],
),
if (!isLink)
Stack(
children: [
DottedBorder(
color: const Color(0xFF444447),
borderType: BorderType.RRect,
radius: Radius.circular(16.px),
child: ClipRRect(
borderRadius: BorderRadius.circular(16.px),
child: Container(
width: 303.px,
alignment: Alignment.center,
padding: EdgeInsets.only(top: 12.px, bottom: 12.px),
child: chooseImage != null
? GestureDetector(
onTap: () {
preview();
},
child: Image.memory(
chooseImage!,
height: 120.px,
),
)
: UploadFile(
// width: 120.px,
// height: 120.px,
child: SvgPicture.asset(
'assets/icons/upload_qrcode.svg',
width: 120.px,
height: 120.px,
),
callback: (Uint8List file) {
setState(() {
chooseImage = file;
showError = false;
});
},
),
),
)),
if (chooseImage != null)
Positioned(
right: 12.px,
top: 12.px,
child: UploadFile(
// width: 68.px,
// height: 28.px,
child: Container(
width: 68.px,
height: 28.px,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14.px),
color: const Color(0xBF131314)),
child: Text(
'重新上传',
style: TextStyle(
color: kBtnColor, fontSize: 12.px),
)),
callback: (Uint8List file) {
setState(() {
chooseImage = file;
showError = false;
});
},
))
// GestureDetector(
// onTap: () {
// chooseFile();
// },
// child: Container(
// width: 68.px,
// height: 28.px,
// alignment: Alignment.center,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(14.px),
// color: const Color(0xBF131314)),
// child: Text(
// '重新上传',
// style: TextStyle(
// color: kBtnColor, fontSize: 12.px),
// )),
// ))
],
),
],
),
),
if ((isLink && strLink.isNotEmpty) || (!isLink && chooseImage != null))
Container(
width: 343.px,
padding: EdgeInsets.all(20.px),
margin: EdgeInsets.only(bottom: 20.px),
decoration: BoxDecoration(
color: const Color(0xFF2C2C2E),
borderRadius: BorderRadius.circular(24.px)),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'标题',
style: TextStyle(
color: kThemeColor,
fontWeight: FontWeight.bold,
fontSize: 16.px,
height: 1.75),
),
SizedBox(
height: 8.px,
),
SelectableText(
'填写在我该平台上的用户名,不填将展示平台名称,如:',
style: TextStyle(
color: const Color(0xFFA5A5AD),
fontSize: 12.px,
height: 1.5),
),
SizedBox(
height: 16.px,
),
TextField(
cursorColor: kBtnColor,
controller: titleController,
onChanged: (value) {
setState(() {
// keyword = value;
strTitle = value;
});
},
style: TextStyle(color: Colors.white, fontSize: 14.px),
decoration: InputDecoration(
border: InputBorder.none,
hintText: social['url_example'],
hintStyle: TextStyle(
fontSize: 14.px, color: const Color(0xFF444447)),
counterText: "",
),
),
Container(
height: 1.px,
color: const Color(0xFF444447),
margin: EdgeInsets.only(top: 18.px, bottom: 18.px),
),
Text(
'描述',
style: TextStyle(
color: kThemeColor,
fontWeight: FontWeight.bold,
fontSize: 16.px,
height: 1.75),
),
SizedBox(
height: 8.px,
),
Text(
'对以上内容的补充描述,如:',
style: TextStyle(
color: const Color(0xFFA5A5AD),
fontSize: 12.px,
height: 1.5),
),
SizedBox(
height: 16.px,
),
TextField(
cursorColor: kBtnColor,
controller: descController,
onChanged: (value) {
setState(() {
strDesc = value;
// keyword = value;
});
},
style: TextStyle(color: Colors.white, fontSize: 14.px),
decoration: InputDecoration(
border: InputBorder.none,
hintText: social['description_example'],
hintStyle: TextStyle(
fontSize: 14.px, color: const Color(0xFF444447)),
counterText: "",
),
),
],
)),
SizedBox(
height: 162.px,
)
],
);
}
Future del() async {
String id = Get.parameters['id']!;
await HttpUtils.delete(Api.userSocials + '/$id');
Get.back();
}
Future commit() async {
String id = Get.parameters['id']!;
if (isLink && strLink.isEmpty) {
Toast().showInfoText('请粘贴链接地址后再提交\n或选择“稍后添加”', context: context);
setState(() {
showError = true;
});
return;
}
if (!isLink && chooseImage == null && imgUrl.isEmpty) {
Toast().showInfoText('请上传二维码后再提交\n或选择“稍后添加”', context: context);
setState(() {
showError = true;
});
return;
}
Toast().showHud(context: context);
if (isLink) {
var data2 = await HttpUtils.put(Api.userSocials + '/$id', data: {
'user_url': strLink,
'description': strDesc,
'social_id': social['id'],
'social_name': social['id'].length == 0 ? social['name'] : '',
'type': 'LINK',
'user_nick': strTitle
});
} else {
Map data = await HttpUtils.get(Api.ossFormUpload,
params: {'type': 'AVATAR', 'file_ext': 'png'});
Dio dio = Dio();
Map map = data['fields'];
map['file'] = await adio.MultipartFile.fromBytes(chooseImage!,
filename: 'avatar.png');
adio.FormData formData = adio.FormData.fromMap(map);
adio.Response response =
await dio.post(data['upload_url'], data: formData);
var data2 = await HttpUtils.put(Api.userSocials + '/$id', data: {
'user_url': data['view_url'],
'description': strDesc,
'social_id': social['id'],
'social_name': social['id'].length == 0 ? social['name'] : '',
'type': 'QR',
'user_nick': strTitle
});
}
Toast().hideHud();
Get.back();
}
tapDelete() {
Toast().showCustomHud(
Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 32.px, bottom: 32.px),
child: Column(
children: [
Text(
'删除此链接后,将无法恢复,\n确定要删除吗?',
style: TextStyle(
color: Colors.white,
fontSize: 16.px,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 16.px,
),
AlertButton(
title: '确定,立即删除',
isCancel: false,
width: 220.px,
height: 40.px,
callback: () {
Toast().hideHud();
del();
}),
SizedBox(
height: 24.px,
),
AlertButton(
title: '取消,再想想',
isCancel: true,
width: 220.px,
height: 40.px,
callback: () {
Toast().hideHud();
}),
],
),
),
context: context);
}
@override
Widget build(BuildContext context) {
SizeFit.initialize(context);
return Material(
color: kBgColor,
child: TopContainer(
child: Stack(children: [
Positioned(
left: 0,
top: 0,
right: 0,
height: MediaQuery.of(context).size.height,
// bottom: 0,
child: WebSmoothScroll(
controller: scrollController,
child: SingleChildScrollView(
// physics: const NeverScrollableScrollPhysics(),
controller: scrollController,
child: content(),
))),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: isFirstEnter ? 162.px : 140.px,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0x00131314),
Color(0xFF131314),
Color(0xFF131314),
])),
child: Column(
children: [
SizedBox(
height: 36.px,
),
LinkButton(
title: '保存修改',
disable: false,
isBlack: false,
callback: () {
commit();
}),
SizedBox(
height: 30.px,
),
GestureDetector(
onTap: () {
tapDelete();
},
child: Text(
'删除已选账号',
style: TextStyle(
color: const Color(0xFF74747A), fontSize: 14.px),
),
)
],
),
))
])));
}
}