26 changed files with 967 additions and 560 deletions
Unified View
Diff Options
-
BINassets/images/example_content.png
-
BINassets/images/room_video.png
-
244lib/controller/discover/room_controller.dart
-
1lib/generated/assets.dart
-
111lib/model/rtc/rtc_channel_detail.dart
-
2lib/network/api_service.g.dart
-
97lib/network/api_urls.dart
-
2lib/network/home_api.g.dart
-
35lib/network/rtc_api.dart
-
175lib/network/rtc_api.g.dart
-
2lib/network/user_api.g.dart
-
3lib/pages/discover/discover_page.dart
-
36lib/pages/discover/live_room_page.dart
-
2lib/pages/home/nearby_tab.dart
-
51lib/pages/home/recommend_tab.dart
-
67lib/pages/main/main_page.dart
-
182lib/pages/main/tabbar/main_tab_bar.dart
-
77lib/pages/main/tabbar/main_tab_btn.dart
-
13lib/pages/main/tabbar/main_tab_item.dart
-
50lib/rtc/rtc_manager.dart
-
16lib/rtc/rtm_manager.dart
-
9lib/service/live_chat_message_service.dart
-
165lib/widget/live/live_room_anchor_showcase.dart
-
69lib/widget/live/live_room_notice_chat_panel.dart
-
50lib/widget/live/live_room_user_header.dart
-
68location_plugin/example/pubspec.lock
@ -0,0 +1,111 @@ |
|||||
|
class RtcChannelDetail { |
||||
|
final String channelId; |
||||
|
final RtcSeatUserInfo? anchorInfo; |
||||
|
final RtcSeatUserInfo? maleInfo; |
||||
|
final RtcSeatUserInfo? femaleInfo; |
||||
|
|
||||
|
const RtcChannelDetail({ |
||||
|
required this.channelId, |
||||
|
this.anchorInfo, |
||||
|
this.maleInfo, |
||||
|
this.femaleInfo, |
||||
|
}); |
||||
|
|
||||
|
factory RtcChannelDetail.fromJson(Map<String, dynamic> json) { |
||||
|
return RtcChannelDetail( |
||||
|
channelId: json['channelId']?.toString() ?? '', |
||||
|
anchorInfo: _parseSeatInfo(json['anchorInfo']), |
||||
|
maleInfo: _parseSeatInfo(json['maleInfo']), |
||||
|
femaleInfo: _parseSeatInfo(json['femaleInfo']), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'channelId': channelId, |
||||
|
'anchorInfo': anchorInfo?.toJson(), |
||||
|
'maleInfo': maleInfo?.toJson(), |
||||
|
'femaleInfo': femaleInfo?.toJson(), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
static RtcSeatUserInfo? _parseSeatInfo(dynamic value) { |
||||
|
if (value is Map<String, dynamic>) { |
||||
|
return RtcSeatUserInfo.fromJson(value); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class RtcSeatUserInfo { |
||||
|
final String miId; |
||||
|
final String userId; |
||||
|
final String nickName; |
||||
|
final String profilePhoto; |
||||
|
final int genderCode; |
||||
|
final int seatNumber; |
||||
|
final bool isFriend; |
||||
|
final bool isMicrophoneOn; |
||||
|
final bool isVideoOn; |
||||
|
final int? uid; |
||||
|
|
||||
|
const RtcSeatUserInfo({ |
||||
|
required this.miId, |
||||
|
required this.userId, |
||||
|
required this.nickName, |
||||
|
required this.profilePhoto, |
||||
|
required this.genderCode, |
||||
|
required this.seatNumber, |
||||
|
required this.isFriend, |
||||
|
required this.isMicrophoneOn, |
||||
|
required this.isVideoOn, |
||||
|
this.uid, |
||||
|
}); |
||||
|
|
||||
|
factory RtcSeatUserInfo.fromJson(Map<String, dynamic> json) { |
||||
|
return RtcSeatUserInfo( |
||||
|
miId: json['miId']?.toString() ?? '', |
||||
|
userId: json['userId']?.toString() ?? '', |
||||
|
nickName: json['nickName']?.toString() ?? '', |
||||
|
profilePhoto: json['profilePhoto']?.toString() ?? '', |
||||
|
genderCode: json['genderCode'] is int |
||||
|
? json['genderCode'] as int |
||||
|
: int.tryParse(json['genderCode']?.toString() ?? '0') ?? 0, |
||||
|
seatNumber: json['seatNumber'] is int |
||||
|
? json['seatNumber'] as int |
||||
|
: int.tryParse(json['seatNumber']?.toString() ?? '0') ?? 0, |
||||
|
isFriend: _parseBool(json['isFriend']), |
||||
|
isMicrophoneOn: _parseBool(json['isMicrophoneOn']), |
||||
|
isVideoOn: _parseBool(json['isVideoOn']), |
||||
|
uid: json['uid'] is int |
||||
|
? json['uid'] as int |
||||
|
: int.tryParse(json['uid']?.toString() ?? ''), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'miId': miId, |
||||
|
'userId': userId, |
||||
|
'nickName': nickName, |
||||
|
'profilePhoto': profilePhoto, |
||||
|
'genderCode': genderCode, |
||||
|
'seatNumber': seatNumber, |
||||
|
'isFriend': isFriend, |
||||
|
'isMicrophoneOn': isMicrophoneOn, |
||||
|
'isVideoOn': isVideoOn, |
||||
|
'uid': uid, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
static bool _parseBool(dynamic value) { |
||||
|
if (value is bool) return value; |
||||
|
if (value is num) return value != 0; |
||||
|
if (value is String) { |
||||
|
return value == '1' || |
||||
|
value.toLowerCase() == 'true' || |
||||
|
value.toLowerCase() == 'yes'; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
@ -1,182 +0,0 @@ |
|||||
import 'dart:io'; |
|
||||
import 'package:collection/collection.dart'; |
|
||||
import 'package:dating_touchme_app/extension/ex_context.dart'; |
|
||||
import 'package:flutter/material.dart'; |
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
||||
|
|
||||
import '../../../generated/assets.dart'; |
|
||||
import 'main_tab_btn.dart'; |
|
||||
import 'main_tab_item.dart'; |
|
||||
|
|
||||
class MainTabBar extends StatefulWidget { |
|
||||
const MainTabBar({super.key, this.initialIndex = 0, this.onTabChanged}); |
|
||||
|
|
||||
final int initialIndex; |
|
||||
final void Function(int index)? onTabChanged; |
|
||||
|
|
||||
@override |
|
||||
State<MainTabBar> createState() => _MainTabBarState(); |
|
||||
} |
|
||||
|
|
||||
class _MainTabBarState extends State<MainTabBar> { |
|
||||
int _selecteIndex = 0; |
|
||||
|
|
||||
final List<MainTabItem> items = const [ |
|
||||
MainTabItem( |
|
||||
title: "首页", |
|
||||
icon: Assets.imagesHomeNol, |
|
||||
selectedIcon: Assets.imagesHomePre, |
|
||||
), |
|
||||
MainTabItem( |
|
||||
title: "找对象", |
|
||||
icon: Assets.imagesDiscoverNol, |
|
||||
selectedIcon: Assets.imagesDiscoverPre, |
|
||||
), |
|
||||
MainTabItem( |
|
||||
title: "消息", |
|
||||
icon: Assets.imagesMessageNol, |
|
||||
selectedIcon: Assets.imagesMessagePre, |
|
||||
), |
|
||||
MainTabItem( |
|
||||
title: "我的", |
|
||||
icon: Assets.imagesMineNol, |
|
||||
selectedIcon: Assets.imagesMinePre, |
|
||||
), |
|
||||
]; |
|
||||
|
|
||||
@override |
|
||||
void initState() { |
|
||||
_selecteIndex = widget.initialIndex; |
|
||||
super.initState(); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
void didUpdateWidget(covariant MainTabBar oldWidget) { |
|
||||
super.didUpdateWidget(oldWidget); |
|
||||
if (_selecteIndex != widget.initialIndex) { |
|
||||
_selecteIndex = widget.initialIndex; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
Widget build(BuildContext context) { |
|
||||
return Builder(builder: (context) { |
|
||||
if (Platform.isIOS) { |
|
||||
if (context.bottomPadding > 0) { |
|
||||
return Container( |
|
||||
height: 64.w, |
|
||||
color: Colors.white, |
|
||||
child: Stack( |
|
||||
children: [ |
|
||||
Column( |
|
||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||
children: [ |
|
||||
Row( |
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
||||
children: items.mapIndexed((index, item) { |
|
||||
return MainTabButton( |
|
||||
selected: index == _selecteIndex, |
|
||||
isRedDot: item.showRedDot, |
|
||||
title: item.title, |
|
||||
onTap: () { |
|
||||
if (_selecteIndex != index) { |
|
||||
_selecteIndex = index; |
|
||||
setState(() {}); |
|
||||
widget.onTabChanged?.call(index); |
|
||||
} |
|
||||
}, |
|
||||
icon: item.icon, |
|
||||
selectedIcon: item.selectedIcon, |
|
||||
); |
|
||||
}).toList()), |
|
||||
SizedBox( |
|
||||
height: 22.w, |
|
||||
) |
|
||||
], |
|
||||
) |
|
||||
], |
|
||||
), |
|
||||
); |
|
||||
} else { |
|
||||
return SafeArea( |
|
||||
top: false, |
|
||||
child: Container( |
|
||||
height: 64.w, |
|
||||
color: Colors.white, |
|
||||
child: Stack( |
|
||||
children: [ |
|
||||
Column( |
|
||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||
children: [ |
|
||||
Row( |
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
||||
children: items.mapIndexed((index, item) { |
|
||||
return MainTabButton( |
|
||||
selected: index == _selecteIndex, |
|
||||
isRedDot: item.showRedDot, |
|
||||
title: item.title, |
|
||||
onTap: () { |
|
||||
if (_selecteIndex != index) { |
|
||||
_selecteIndex = index; |
|
||||
setState(() {}); |
|
||||
widget.onTabChanged?.call(index); |
|
||||
} |
|
||||
}, |
|
||||
icon: item.icon, |
|
||||
selectedIcon: item.selectedIcon, |
|
||||
); |
|
||||
}).toList()), |
|
||||
SizedBox( |
|
||||
height: 14.w, |
|
||||
) |
|
||||
], |
|
||||
) |
|
||||
], |
|
||||
), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
} else { |
|
||||
return SafeArea( |
|
||||
top: false, |
|
||||
child: Container( |
|
||||
// padding: EdgeInsets.only(bottom: 14.w), |
|
||||
// margin: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 14.w), |
|
||||
height: 64.w, |
|
||||
color: Colors.white, |
|
||||
child: Stack( |
|
||||
children: [ |
|
||||
Column( |
|
||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||
children: [ |
|
||||
Row( |
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
||||
children: items.mapIndexed((index, item) { |
|
||||
return MainTabButton( |
|
||||
selected: index == _selecteIndex, |
|
||||
isRedDot: item.showRedDot, |
|
||||
title: item.title, |
|
||||
onTap: () { |
|
||||
if (_selecteIndex != index) { |
|
||||
_selecteIndex = index; |
|
||||
setState(() {}); |
|
||||
widget.onTabChanged?.call(index); |
|
||||
} |
|
||||
}, |
|
||||
icon: item.icon, |
|
||||
selectedIcon: item.selectedIcon, |
|
||||
); |
|
||||
}).toList()), |
|
||||
SizedBox( |
|
||||
height: 14.w, |
|
||||
) |
|
||||
], |
|
||||
) |
|
||||
], |
|
||||
), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
@ -1,77 +0,0 @@ |
|||||
import 'package:flutter/material.dart'; |
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
||||
|
|
||||
class MainTabButton extends StatefulWidget { |
|
||||
final VoidCallback? onTap; |
|
||||
final bool isRedDot; |
|
||||
final bool selected; |
|
||||
final String icon; |
|
||||
final String title; |
|
||||
final String selectedIcon; |
|
||||
|
|
||||
const MainTabButton({ |
|
||||
super.key, |
|
||||
required this.selected, |
|
||||
required this.icon, |
|
||||
required this.selectedIcon, |
|
||||
this.isRedDot = false, |
|
||||
this.onTap, |
|
||||
required this.title |
|
||||
}); |
|
||||
|
|
||||
@override |
|
||||
State<MainTabButton> createState() => MainTabButtonState(); |
|
||||
} |
|
||||
|
|
||||
class MainTabButtonState extends State<MainTabButton> { |
|
||||
@override |
|
||||
Widget build(BuildContext context) { |
|
||||
if (widget.isRedDot) { |
|
||||
return Expanded( |
|
||||
child: GestureDetector( |
|
||||
onTap: widget.onTap, |
|
||||
child: Container( |
|
||||
color: Colors.transparent, |
|
||||
alignment: Alignment.center, |
|
||||
child: Stack( |
|
||||
clipBehavior: Clip.none, |
|
||||
children: [ |
|
||||
Column( |
|
||||
children: [ |
|
||||
SizedBox(height: 5.w,), |
|
||||
widget.selected |
|
||||
? Image.asset(widget.selectedIcon, width: 25.w, height: 25.w) |
|
||||
: Image.asset(widget.icon, width: 25.w, height: 25.w), |
|
||||
Text(widget.title, style: const TextStyle( |
|
||||
fontSize: 12 |
|
||||
),) |
|
||||
], |
|
||||
), |
|
||||
], |
|
||||
), |
|
||||
), |
|
||||
)); |
|
||||
} |
|
||||
|
|
||||
return Expanded( |
|
||||
child: GestureDetector( |
|
||||
onTap: widget.onTap, |
|
||||
child: Container( |
|
||||
alignment: Alignment.center, |
|
||||
color: Colors.transparent, |
|
||||
child: Column( |
|
||||
children: [ |
|
||||
SizedBox(height: 5.w,), |
|
||||
widget.selected |
|
||||
? Image.asset(widget.selectedIcon, width: 25.w, height: 25.w) |
|
||||
: Image.asset(widget.icon, width: 25.w, height: 25.w), |
|
||||
Text(widget.title, style: const TextStyle( |
|
||||
fontSize: 12 |
|
||||
),) |
|
||||
], |
|
||||
), |
|
||||
), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
@ -1,13 +0,0 @@ |
|||||
class MainTabItem { |
|
||||
final String title; |
|
||||
final String icon; |
|
||||
final String selectedIcon; |
|
||||
final bool showRedDot; |
|
||||
|
|
||||
const MainTabItem({ |
|
||||
required this.title, |
|
||||
required this.icon, |
|
||||
required this.selectedIcon, |
|
||||
this.showRedDot = false, |
|
||||
}); |
|
||||
} |
|
||||
Write
Preview
Loading…
Cancel
Save