26 changed files with 967 additions and 560 deletions
Split 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