479 lines
15 KiB
Dart
479 lines
15 KiB
Dart
import 'dart:async';
|
||
import 'dart:io';
|
||
import 'dart:typed_data';
|
||
|
||
import 'package:circle_app/util/util.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:image_picker/image_picker.dart';
|
||
import 'package:video_player/video_player.dart';
|
||
import 'package:video_thumbnail/video_thumbnail.dart';
|
||
|
||
import '../../common/Widgets/open_vip_tip/view.dart';
|
||
import '../../network/api.dart';
|
||
import '../../network/dio_manager.dart';
|
||
import '../../router/app_routers.dart';
|
||
import '../../util/SharedPreferencesHelper.dart';
|
||
import '../../util/eventBus.dart';
|
||
import '../../util/qiniu.dart';
|
||
import '../circle/logic.dart';
|
||
import '../select_circle/logic.dart';
|
||
import 'state.dart';
|
||
import '../../common/config.dart';
|
||
|
||
class Call_outLogic extends GetxController {
|
||
final Call_outState state = Call_outState();
|
||
TextEditingController textEditingController = TextEditingController();
|
||
bool isCheck = false;
|
||
late ConfigBean configBean;
|
||
String circleName = "";
|
||
final ImagePicker _picker = ImagePicker();
|
||
var quToken = '';
|
||
VideoPlayerController? videoPlayerController;
|
||
List<MyConfigData> numbers = [];
|
||
List<MyConfigData> myConfigData = Get.arguments['numbers'];
|
||
int vip = 0;
|
||
|
||
@override
|
||
void onClose() {
|
||
super.onClose();
|
||
videoPlayerController?.dispose();
|
||
}
|
||
|
||
@override
|
||
void onInit() async {
|
||
super.onInit();
|
||
if (myConfigData != null) {
|
||
// print(myConfigData.name);
|
||
numbers.addAll(myConfigData);
|
||
circleName = numbers[0].name;
|
||
SharedPreferencesHelper.getInstance().then((sharedPreferences) {
|
||
vip = sharedPreferences.getInt(SharedPreferencesHelper.VIP);
|
||
print(vip);
|
||
if (vip == 2) {
|
||
isCheck = true;
|
||
}
|
||
update();
|
||
});
|
||
|
||
update();
|
||
}
|
||
|
||
var data =
|
||
await DioManager.instance.get(url: Api.getCircleList, params: {});
|
||
var bean = BaseResponse<ConfigBean>.fromJson(
|
||
data, (data) => ConfigBean.fromJson(data));
|
||
if (bean.isSuccess()) {
|
||
configBean = bean.data!;
|
||
} else {
|
||
showToast(bean.msg);
|
||
}
|
||
|
||
var quniuData =
|
||
await DioManager.instance.get(url: Api.getqiniuToken, params: {});
|
||
var qiniuBean = BaseResponse<QnTokenData>.fromJson(
|
||
quniuData, (quniuData) => QnTokenData.fromJson(quniuData));
|
||
quToken = qiniuBean.data!.token.toString();
|
||
|
||
|
||
|
||
|
||
StreamSubscription subscription = EventBusManager.on<CommentVipEvent>().listen((event) {
|
||
vip = event.vip;
|
||
});
|
||
|
||
}
|
||
|
||
|
||
|
||
showRechargeDialog(){
|
||
Get.bottomSheet(
|
||
Scaffold(
|
||
backgroundColor: Colors.transparent,
|
||
body: Open_vip_tipPage(true),
|
||
),
|
||
isScrollControlled: true,
|
||
enableDrag: false);
|
||
|
||
}
|
||
|
||
sendShout() async {
|
||
if (numbers.isEmpty) {
|
||
showToast("请选择要喊话的圈子。");
|
||
return;
|
||
}
|
||
if (textEditingController.text.isEmpty) {
|
||
showToast("请输入喊话内容");
|
||
return;
|
||
}
|
||
if (state.imaglist.isEmpty && state.videolist.isEmpty) {
|
||
if (textEditingController.text.length < 30) {
|
||
showToast("您当前未添加图片或视频,请至少输入30字故事内容。");
|
||
return;
|
||
}
|
||
} else {
|
||
if (!state.imaglist.isEmpty) {
|
||
if (textEditingController.text.length < 5) {
|
||
showToast("请至少输入5个字内容");
|
||
return;
|
||
}
|
||
}
|
||
if (!state.videolist.isEmpty) {
|
||
if (textEditingController.text.length < 5) {
|
||
showToast("请至少输入5个字内容");
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
List myBean = [];
|
||
if (!state.imaglist.isEmpty) {
|
||
state.imaglist.forEach((element) {
|
||
myBean.add(MyBean(type: 1, url: element).toJson());
|
||
});
|
||
}
|
||
if (!state.videolist.isEmpty) {
|
||
myBean.add(MyBean(type: 2, url: state.videolist[0]).toJson());
|
||
}
|
||
print(myBean.toString());
|
||
SmartDialog.showLoading();
|
||
var data = await DioManager.instance.post(url: Api.SendShout, params: {
|
||
'album': myBean,
|
||
'content': textEditingController.text.trim(),
|
||
'interest_id': numbers[0].id,
|
||
'use_queen': isCheck ? 1 : 0,
|
||
});
|
||
|
||
var beandata = BaseResponse<dynamic>.fromJson(
|
||
data,
|
||
(jsonData) => jsonData,
|
||
);
|
||
SmartDialog.dismiss();
|
||
if (beandata.isSuccess()) {
|
||
showToast(beandata.msg);
|
||
final logic = Get.put(CircleLogic());
|
||
logic.refresh();
|
||
// Navigator.pop(Get.context!, numbers);
|
||
Get.back();
|
||
} else if (beandata.code == 30503) {
|
||
// if (beandata.data == null) {
|
||
// return;
|
||
// }
|
||
showToast(beandata.msg);
|
||
var callOutBean = BaseResponse<List<String>>.fromJson(data, (jsonData) => List<String>.from(jsonData),);
|
||
|
||
textEditingController.text =
|
||
filterSensitiveWords(textEditingController.text, callOutBean.data!);
|
||
print(filterSensitiveWords(textEditingController.text, callOutBean.data!));
|
||
update();
|
||
} else if (beandata.code == 30505) {
|
||
var callOutBean = BaseResponse<CirclePaymentBean>.fromJson(
|
||
data,
|
||
(jsonData) => CirclePaymentBean.fromJson(jsonData),
|
||
);
|
||
showDialog();
|
||
// tipWdiget()
|
||
} else {
|
||
showToast(beandata.msg);
|
||
}
|
||
}
|
||
|
||
void showDialog() {
|
||
Get.bottomSheet(
|
||
Scaffold(
|
||
backgroundColor: Colors.transparent,
|
||
body: Container(
|
||
width: Get.width,
|
||
height: Get.height,
|
||
child: Center(
|
||
child: Container(
|
||
width: 339.sp,
|
||
height: 330.sp,
|
||
decoration: BoxDecoration(
|
||
image: DecorationImage(
|
||
fit: BoxFit.fill,
|
||
image: AssetImage(getCircleImage('add_tip_bg')))),
|
||
child: Stack(
|
||
alignment: Alignment.center,
|
||
children: [
|
||
Positioned(
|
||
top: 5.sp,
|
||
right: 12.sp,
|
||
child: GestureDetector(
|
||
onTap: () {
|
||
Get.back();
|
||
},
|
||
child: Image.asset(
|
||
getCircleImage('close'),
|
||
width: 24.sp,
|
||
),
|
||
)),
|
||
Positioned(
|
||
top: 24.sp,
|
||
child: Text(
|
||
'解锁圈子才能发布喊话',
|
||
style:
|
||
TextStyle(color: Colors.white, fontSize: 16.sp),
|
||
)),
|
||
Positioned(
|
||
left: 17.sp,
|
||
top: 64.sp,
|
||
child: Text(
|
||
'为什么要解锁圈子?',
|
||
style:
|
||
TextStyle(color: Colors.white, fontSize: 16.sp),
|
||
)),
|
||
Positioned(
|
||
top: 98.sp,
|
||
child: Container(
|
||
width: 339.sp,
|
||
padding: EdgeInsets.only(left: 17.sp, right: 17.sp),
|
||
child: Text(
|
||
'为打造纯净的社交环境,更好地服务大家,基于以下几方面考虑:1、平台升级为全天24小时人工审核,保证用户真实,避免骗子、酒托、虚假人士等扰乱平台 ;2、杜绝未入圈用户随意骚扰或影响已入圈;3、谢绝只会白嫖的猎奇人士。',
|
||
style: TextStyle(
|
||
color: Color.fromRGBO(247, 250, 250, 0.8),
|
||
fontSize: 12.sp)),
|
||
)),
|
||
Positioned(
|
||
bottom: 18.sp,
|
||
child: Container(
|
||
width: 168.sp,
|
||
height: 42.sp,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(21.sp),
|
||
gradient: const LinearGradient(
|
||
begin: Alignment.centerLeft,
|
||
end: Alignment.centerRight,
|
||
colors: [
|
||
Color(0xff0AFCFF),
|
||
Color(0xffD739EA)
|
||
])),
|
||
child: Text(
|
||
'立即解锁',
|
||
style:
|
||
TextStyle(color: Colors.white, fontSize: 16.sp),
|
||
),
|
||
)),
|
||
Positioned(
|
||
bottom: 72.sp,
|
||
child: Container(
|
||
child: Row(
|
||
children: [
|
||
Text(
|
||
'¥18',
|
||
style: TextStyle(
|
||
color: Color(0xffE845FF),
|
||
fontSize: 16.sp,
|
||
fontWeight: FontWeight.w600),
|
||
),
|
||
SizedBox(
|
||
width: 2.sp,
|
||
),
|
||
Text(
|
||
'(原价60)',
|
||
style: TextStyle(
|
||
color: Colors.white70,
|
||
fontSize: 16.sp,
|
||
fontWeight: FontWeight.w400,
|
||
decoration: TextDecoration.lineThrough,
|
||
decorationColor: Colors.white70,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
))
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
isScrollControlled: true,
|
||
enableDrag: false);
|
||
}
|
||
|
||
startSelectCircleActivity() async {
|
||
var data = await Get.toNamed(AppRoutes.SelectCircleActivity, arguments: {
|
||
"interestMap": configBean.interestMap,
|
||
'selectCircle': numbers,
|
||
"isRodio": true
|
||
});
|
||
if (null != data) {
|
||
numbers = data;
|
||
circleName = numbers[0].name;
|
||
|
||
print(circleName);
|
||
update();
|
||
}
|
||
}
|
||
|
||
showImg() async {
|
||
try {
|
||
if (state.videolist.length != 0) {
|
||
showToast("已添加视频,无法添加图片。");
|
||
return;
|
||
}
|
||
if (state.imaglist.length == 6) {
|
||
showToast("最多上传6张图片哦~");
|
||
return;
|
||
}
|
||
final XFile? pickedFile = await _picker.pickImage(
|
||
source: ImageSource.gallery,
|
||
);
|
||
if(null==pickedFile){
|
||
return;
|
||
}
|
||
|
||
SmartDialog.showLoading();
|
||
upDataImage(quToken,pickedFile!,CONFIG.CALL_OUT_IMAGE,(result){
|
||
SmartDialog.dismiss();
|
||
state.imaglist.add(result);
|
||
update();
|
||
});
|
||
} catch (e) {
|
||
print(e);
|
||
}
|
||
}
|
||
|
||
Future<ThumbnailResult> getFirstPic(url) async {
|
||
Uint8List? bytes = await VideoThumbnail.thumbnailData(video: url);
|
||
final Completer<ThumbnailResult> completer = Completer();
|
||
if (bytes != null) {
|
||
int _imageDataSize = bytes.length;
|
||
print("image size: $_imageDataSize");
|
||
|
||
final _image = Image.memory(bytes);
|
||
_image.image
|
||
.resolve(ImageConfiguration())
|
||
.addListener(ImageStreamListener((ImageInfo info, bool _) {
|
||
completer.complete(ThumbnailResult(
|
||
image: _image,
|
||
dataSize: _imageDataSize,
|
||
height: info.image.height,
|
||
width: info.image.width,
|
||
));
|
||
}));
|
||
}
|
||
|
||
return completer.future;
|
||
}
|
||
|
||
showVideo() async {
|
||
if (state.imaglist.length != 0) {
|
||
showToast("已添加图片,无法添加视频。");
|
||
return;
|
||
}
|
||
if (state.videolist.length != 0) {
|
||
showToast("最多上传1个视频哦~");
|
||
return;
|
||
}
|
||
try {
|
||
final XFile? pickedFile = await _picker.pickVideo(
|
||
source: ImageSource.gallery,
|
||
);
|
||
if(null==pickedFile){
|
||
return;
|
||
}
|
||
SmartDialog.showLoading();
|
||
var path = await getApplicationSupportDirectoryPath();
|
||
compressVideo(pickedFile.path, path, (result) async {
|
||
print(result);
|
||
videoPlayerController = VideoPlayerController.file(
|
||
File(result),
|
||
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
|
||
);
|
||
await videoPlayerController?.initialize();
|
||
final Duration videoDuration = videoPlayerController!.value.duration;
|
||
final double durationInSeconds = videoDuration.inSeconds.toDouble();
|
||
print(durationInSeconds.toString());
|
||
if (durationInSeconds >= 5 && durationInSeconds <= 30) {
|
||
videoPlayerController?.setLooping(true);
|
||
videoPlayerController?.addListener(() {
|
||
if (!videoPlayerController!.value.isPlaying) {
|
||
// Navigator.pop(context);
|
||
}
|
||
});
|
||
|
||
updataQiniu(result, pickedFile.name, CONFIG.CALL_OUT_VIDEO, quToken,
|
||
(result) {
|
||
SmartDialog.dismiss();
|
||
state.videolist.add(result);
|
||
update();
|
||
});
|
||
} else {
|
||
SmartDialog.dismiss();
|
||
showToast("请上传5-30秒的视频");
|
||
}
|
||
});
|
||
} catch (e) {}
|
||
}
|
||
|
||
Future<ClosedCaptionFile> _loadCaptions(BuildContext context) async {
|
||
final String fileContents = await DefaultAssetBundle.of(context)
|
||
.loadString('assets/bumble_bee_captions.vtt');
|
||
return WebVTTCaptionFile(
|
||
fileContents); // For vtt files, use WebVTTCaptionFile
|
||
}
|
||
}
|
||
|
||
class MyBean {
|
||
int type;
|
||
String url;
|
||
|
||
MyBean({required this.type, required this.url});
|
||
|
||
factory MyBean.fromJson(Map<String, dynamic> json) {
|
||
return MyBean(
|
||
type: json['type'],
|
||
url: json['url'],
|
||
);
|
||
}
|
||
|
||
Map<String, dynamic> toJson() {
|
||
return {
|
||
'type': type,
|
||
'url': url,
|
||
};
|
||
}
|
||
}
|
||
|
||
class ThumbnailResult {
|
||
final Image image;
|
||
final int dataSize;
|
||
final int height;
|
||
final int width;
|
||
|
||
const ThumbnailResult(
|
||
{required this.image,
|
||
required this.dataSize,
|
||
required this.height,
|
||
required this.width});
|
||
}
|
||
|
||
class CirclePaymentBean {
|
||
final int id;
|
||
final String title;
|
||
final double amount;
|
||
final double oldAmount;
|
||
|
||
CirclePaymentBean({
|
||
required this.id,
|
||
required this.title,
|
||
required this.amount,
|
||
required this.oldAmount,
|
||
});
|
||
|
||
factory CirclePaymentBean.fromJson(Map<String, dynamic> json) {
|
||
return CirclePaymentBean(
|
||
id: json['id'] as int,
|
||
title: json['title'] as String,
|
||
amount: json['amount'] as double,
|
||
oldAmount: json['old_amount'] as double,
|
||
);
|
||
}
|
||
}
|