对接讲解接口

master
laiiihz 5 years ago
parent 50a62a59d6
commit 9a5dfa055a

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

@ -443,6 +443,9 @@ class R {
/// ![preview](file:///Users/akufe/Desktop/recook_temp/assets/live/shop.png)
static const String ASSETS_LIVE_SHOP_PNG = 'assets/live/shop.png';
/// ![preview](file:///Users/akufe/Desktop/recook_temp/assets/live/shutdown.png)
static const String ASSETS_LIVE_SHUTDOWN_PNG = 'assets/live/shutdown.png';
/// ![preview](file:///Users/akufe/Desktop/recook_temp/assets/live/small_red_cart.png)
static const String ASSETS_LIVE_SMALL_RED_CART_PNG = 'assets/live/small_red_cart.png';

@ -499,4 +499,13 @@ class LiveAPI {
///
static const String activityVideoList = '/v1/live/user/live/list';
///
static const String liveLike = '/v1/live/live/praise/add';
///
static const String liveStartExplain = '/v1/live/live/explain';
///
static const String liveStopExplain = '/v1/live/live/un_explain';
}

@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:recook/constants/api.dart';
@ -6,12 +7,17 @@ import 'package:recook/constants/header.dart';
import 'package:recook/manager/http_manager.dart';
import 'package:recook/manager/user_manager.dart';
import 'package:recook/pages/live/live_stream/live_pick_goods_page.dart';
import 'package:recook/pages/live/live_stream/show_goods_list.dart';
import 'package:recook/pages/live/models/live_stream_info_model.dart';
import 'package:recook/pages/live/models/topic_list_model.dart';
import 'package:recook/pages/live/tencent_im/tencent_im_tool.dart';
import 'package:recook/pages/live/video/pick_topic_page.dart';
import 'package:recook/pages/live/widget/live_user_bar.dart';
import 'package:recook/utils/custom_route.dart';
import 'package:recook/widgets/bottom_sheet/action_sheet.dart';
import 'package:recook/widgets/custom_image_button.dart';
import 'package:tencent_im_plugin/entity/message_entity.dart';
import 'package:tencent_im_plugin/tencent_im_plugin.dart';
import 'package:tencent_live_fluttify/tencent_live_fluttify.dart';
import 'package:image_picker/image_picker.dart';
@ -30,10 +36,16 @@ class _LivePageState extends State<LivePage> {
List<int> pickedIds = [];
int liveItemId = 0;
bool _isStream = false;
LiveStreamInfoModel _streamInfoModel;
TencentGroupTool group;
List<MessageEntity> chatObjects = [];
ScrollController _scrollController = ScrollController();
int nowExplain = 0;
@override
void initState() {
super.initState();
_editingController.text = '${UserManager.instance.user.info.nickname}正在直播';
}
@ -42,6 +54,9 @@ class _LivePageState extends State<LivePage> {
_livePusher?.stopPush();
_livePusher?.stopPreview();
_editingController?.dispose();
TencentImPlugin.quitGroup(groupId: _streamInfoModel.groupId);
TencentImPlugin.removeListener(parseMessage);
TencentImPlugin.logout();
if (_isStream)
HttpManager.post(LiveAPI.exitLive, {
'liveItemId': liveItemId,
@ -160,29 +175,45 @@ class _LivePageState extends State<LivePage> {
minWidth: rSize(205),
height: rSize(40),
onPressed: () {
_isStream = true;
setState(() {});
// GSDialog.of(context).showLoadingDialog(context, '上传图片中');
// HttpManager.uploadFile(
// url: CommonApi.upload,
// file: _imageFile,
// key: "photo",
// ).then((result) {
// GSDialog.of(context).dismiss(context);
// GSDialog.of(context)
// .showLoadingDialog(context, '准备开始直播中');
// HttpManager.post(LiveAPI.startLive, {
// 'title': _editingController.text,
// 'cover': result.url,
// 'topic': _topicModel == null ? 0 : _topicModel.id,
// 'goodsIds': pickedIds,
// }).then((resultData) {
// GSDialog.of(context).dismiss(context);
// liveItemId = resultData.data['data']['liveItemId'];
// _livePusher
// .startPush(resultData.data['data']['pushUrl']);
// });
// });
GSDialog.of(context).showLoadingDialog(context, '上传图片中');
HttpManager.uploadFile(
url: CommonApi.upload,
file: _imageFile,
key: "photo",
).then((result) {
GSDialog.of(context).dismiss(context);
GSDialog.of(context)
.showLoadingDialog(context, '准备开始直播中');
HttpManager.post(LiveAPI.startLive, {
'title': _editingController.text,
'cover': result.url,
'topic': _topicModel == null ? 0 : _topicModel.id,
'goodsIds': pickedIds,
}).then((resultData) {
GSDialog.of(context).dismiss(context);
liveItemId = resultData.data['data']['liveItemId'];
_livePusher
.startPush(resultData.data['data']['pushUrl']);
_isStream = true;
setState(() {});
TencentIMTool.login().then((_) {
DPrint.printLongJson('用户登陆');
getLiveStreamModel(liveItemId).then((model) {
if (model == null)
Navigator.pop(context);
else {
setState(() {
_streamInfoModel = model;
});
TencentImPlugin.applyJoinGroup(
groupId: model.groupId, reason: 'enterLive');
TencentImPlugin.addListener(parseMessage);
group = TencentGroupTool.fromId(model.groupId);
}
});
});
});
});
},
child: Text(
'开始直播',
@ -199,10 +230,72 @@ class _LivePageState extends State<LivePage> {
],
),
),
AnimatedPositioned(
bottom: _isStream ? 0 : -300,
left: 0,
right: 0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Container(
height: 300,
child: ListView.builder(
reverse: true,
controller: _scrollController,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return _buildChatBox(
chatObjects[index].sender, chatObjects[index].note);
},
itemCount: chatObjects.length,
),
),
),
CustomImageButton(
child: Container(
alignment: Alignment.bottomCenter,
width: rSize(44),
height: rSize(44),
child: Text(
_streamInfoModel == null
? ''
: _streamInfoModel.goodsLists.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: rSP(13),
height: 28 / 13,
),
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(R.ASSETS_LIVE_LIVE_GOOD_PNG),
),
),
),
onPressed: () {
showGoodsListDialog(
context,
models: _streamInfoModel.goodsLists,
onExplain: (index) {
setState(() {
nowExplain = index;
});
},
initExplain: nowExplain,
id: _streamInfoModel.id,
isLive: true,
);
},
),
],
),
duration: Duration(milliseconds: 250),
),
AnimatedPositioned(
duration: Duration(milliseconds: 250),
right: _isStream ? -100 : 0,
top: MediaQuery.of(context).viewPadding.top,
top: MediaQuery.of(context).viewPadding.top + rSize(15),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
@ -222,9 +315,11 @@ class _LivePageState extends State<LivePage> {
),
AnimatedPositioned(
duration: Duration(milliseconds: 250),
right: 0,
left: 0,
top: _isStream ? -100 : MediaQuery.of(context).viewPadding.top,
right: rSize(15),
left: rSize(15),
top: _isStream
? (MediaQuery.of(context).viewPadding.top + rSize(15))
: -100,
child: Row(
children: [
LiveUserBar(
@ -234,6 +329,17 @@ class _LivePageState extends State<LivePage> {
avatar:
Api.getImgUrl(UserManager.instance.user.info.headImgUrl),
),
Spacer(),
CustomImageButton(
onPressed: () {
Navigator.pop(context);
},
child: Image.asset(
R.ASSETS_LIVE_SHUTDOWN_PNG,
height: rSize(21),
width: rSize(21),
),
),
],
),
),
@ -242,6 +348,107 @@ class _LivePageState extends State<LivePage> {
);
}
Future<LiveStreamInfoModel> getLiveStreamModel(int id) async {
ResultData resultData = await HttpManager.post(
LiveAPI.liveStreamInfo,
{'id': id},
);
if (resultData?.data['data'] == null)
return null;
else
return LiveStreamInfoModel.fromJson(resultData.data['data']);
}
_buildChatBox(String sender, String note) {
final Color color = Color.fromRGBO(
180 + Random().nextInt(55),
180 + Random().nextInt(55),
180 + Random().nextInt(55),
1,
);
return Align(
alignment: Alignment.centerLeft,
child: Container(
child: Text.rich(
TextSpan(children: [
TextSpan(
text: '$sender:',
style: TextStyle(
color: color,
fontSize: rSP(13),
),
),
TextSpan(
text: note,
style: TextStyle(
color: Colors.white,
fontSize: rSP(13),
),
),
]),
maxLines: 5,
),
margin: EdgeInsets.symmetric(vertical: rSize(5 / 2)),
padding: EdgeInsets.symmetric(
horizontal: rSize(10),
vertical: rSize(4),
),
constraints: BoxConstraints(
maxWidth: rSize(200),
),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.1),
borderRadius: BorderRadius.circular(rSize(16)),
),
),
);
}
parseMessage(ListenerTypeEnum type, params) {
print('ListenerTypeEnum$type');
switch (type) {
case ListenerTypeEnum.ForceOffline:
break;
case ListenerTypeEnum.UserSigExpired:
break;
case ListenerTypeEnum.Connected:
break;
case ListenerTypeEnum.Disconnected:
break;
case ListenerTypeEnum.WifiNeedAuth:
break;
case ListenerTypeEnum.Refresh:
break;
case ListenerTypeEnum.RefreshConversation:
break;
case ListenerTypeEnum.MessageRevoked:
break;
case ListenerTypeEnum.NewMessages:
chatObjects.insertAll(0, params);
_scrollController.animateTo(
-50,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOutCubic,
);
setState(() {});
break;
case ListenerTypeEnum.GroupTips:
break;
case ListenerTypeEnum.RecvReceipt:
break;
case ListenerTypeEnum.ReConnFailed:
break;
case ListenerTypeEnum.ConnFailed:
break;
case ListenerTypeEnum.Connecting:
break;
case ListenerTypeEnum.UploadProgress:
break;
case ListenerTypeEnum.DownloadProgress:
break;
}
}
_buildVerticalButton(String img, String title, VoidCallback onTap) {
return CustomImageButton(
padding: EdgeInsets.symmetric(

@ -191,6 +191,12 @@ class _LivePlaybackViewPageState extends State<LivePlaybackViewPage> {
width: rSize(32),
height: rSize(32),
),
onTap: () {
HttpManager.post(
LiveAPI.liveLike,
{'liveItemId': widget.id},
);
},
),
SizedBox(width: rSize(10)),
Spacer(),

@ -336,6 +336,12 @@ class _LiveStreamViewPageState extends State<LiveStreamViewPage> {
width: rSize(32),
height: rSize(32),
),
onTap: () {
HttpManager.post(
LiveAPI.liveLike,
{'liveItemId': widget.id},
);
},
),
SizedBox(width: rSize(10)),
CustomImageButton(

@ -1,17 +1,24 @@
import 'package:flutter/material.dart';
import 'package:recook/constants/api.dart';
import 'package:recook/constants/header.dart';
import 'package:recook/manager/http_manager.dart';
import 'package:recook/pages/goods/small_coupon_widget.dart';
import 'package:recook/pages/live/models/live_stream_info_model.dart'
show GoodsLists;
class GoodsListDialog extends StatefulWidget {
final List<GoodsLists> models;
final bool onLive;
final bool isLive;
final Function(int explain) onExplain;
final int initExplain;
final int id;
GoodsListDialog({
Key key,
@required this.models,
this.onLive,
this.isLive = false,
this.onExplain,
this.initExplain,
this.id,
}) : super(key: key);
@override
@ -19,6 +26,13 @@ class GoodsListDialog extends StatefulWidget {
}
class _GoodsListDialogState extends State<GoodsListDialog> {
int explain = 0;
@override
void initState() {
super.initState();
explain = widget.initExplain;
}
@override
Widget build(BuildContext context) {
return DraggableScrollableSheet(
@ -229,17 +243,72 @@ class _GoodsListDialogState extends State<GoodsListDialog> {
),
),
Spacer(),
MaterialButton(
color: Color(0xFFDB2D2D),
height: rSize(22),
minWidth: rSize(58),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(rSize(11)),
),
padding: EdgeInsets.zero,
onPressed: () {},
child: Text('马上抢'),
),
widget.isLive
? explain == model.id
? SizedBox(
height: rSize(22),
width: rSize(58),
child: OutlineButton(
onPressed: () {
explain = 0;
widget.onExplain(0);
setState(() {});
HttpManager.post(LiveAPI.liveStopExplain, {
'liveItemId': widget.id,
'goodsId': model.id,
});
},
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(rSize(11)),
),
padding: EdgeInsets.zero,
child: Text(
'取消讲解',
softWrap: false,
overflow: TextOverflow.visible,
style: TextStyle(
color: Color(0xFFDB2D2D),
fontSize: rSP(12),
),
),
borderSide: BorderSide(
color: Color(0xFFDB2D2D),
width: rSize(1),
),
),
)
: MaterialButton(
color: Color(0xFFDB2D2D),
height: rSize(22),
minWidth: rSize(58),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(rSize(11)),
),
padding: EdgeInsets.zero,
onPressed: () {
explain = model.id;
widget.onExplain(model.id);
setState(() {});
HttpManager.post(LiveAPI.liveStartExplain, {
'liveItemId': widget.id,
'goodsId': model.id,
});
},
child: Text('讲解'),
)
: MaterialButton(
color: Color(0xFFDB2D2D),
height: rSize(22),
minWidth: rSize(58),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(rSize(11)),
),
padding: EdgeInsets.zero,
onPressed: () {},
child: Text('马上抢'),
),
],
),
],
@ -254,13 +323,23 @@ class _GoodsListDialogState extends State<GoodsListDialog> {
showGoodsListDialog(
BuildContext context, {
@required List<GoodsLists> models,
bool isLive = false,
Function(int onExplain) onExplain,
int initExplain,
int id,
}) {
showGeneralDialog(
context: context,
pageBuilder: (context, animation, secondaryAnimation) {
return Align(
alignment: Alignment.bottomCenter,
child: GoodsListDialog(models: models),
child: GoodsListDialog(
models: models,
isLive: isLive,
onExplain: onExplain,
initExplain: initExplain,
id: id,
),
);
},
transitionBuilder: (context, animation, secondaryAnimation, child) {

@ -1,3 +1,4 @@
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:recook/constants/api.dart';
import 'package:recook/constants/header.dart';
@ -24,7 +25,7 @@ class _UserPlaybackCardState extends State<UserPlaybackCard> {
RecookDateUtil.fromMillsecond(widget.model.startAt * 1000);
return UserBaseCard(
date: dateUtil.prefixDay,
detailDate: '14:30',
detailDate: DateUtil.formatDate(dateUtil.dateTime, format: 'HH:mm'),
children: [
SizedBox(height: rSize(35)),
Row(

@ -638,7 +638,7 @@ packages:
name: many_like
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.2"
version: "0.0.3"
matcher:
dependency: transitive
description:

@ -192,7 +192,7 @@ dependencies:
video_trimmer: ^0.2.7
#点赞组件
many_like: ^0.0.2
many_like: ^0.0.3
dev_dependencies:
flutter_test:

Loading…
Cancel
Save