diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart new file mode 100644 index 0000000..552d480 --- /dev/null +++ b/lib/controller/discover/room_controller.dart @@ -0,0 +1,56 @@ +import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart'; +import 'package:dating_touchme_app/network/network_service.dart'; +import 'package:dating_touchme_app/rtc/rtc_manager.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; + +import '../../pages/discover/live_room_page.dart'; + +/// 直播房间相关控制器 +class RoomController extends GetxController { + RoomController({NetworkService? networkService}) + : _networkService = networkService ?? Get.find(); + + final NetworkService _networkService; + + /// 当前频道信息 + final Rxn rtcChannel = Rxn(); + + /// 是否正在创建 + final RxBool isLoading = false.obs; + + /// 调用接口创建 RTC 频道 + Future createRtcChannel() async { + if (isLoading.value) return ; + + try { + isLoading.value = true; + final response = await _networkService.rtcApi.createRtcChannel(); + final base = response.data; + + if (base.isSuccess && base.data != null) { + rtcChannel.value = base.data; + await _joinRtcChannel(base.data!); + } else { + final message = base.message.isNotEmpty ? base.message : '创建频道失败'; + SmartDialog.showToast(message); + } + } catch (e) { + SmartDialog.showToast('创建频道异常:$e'); + } finally { + isLoading.value = false; + } + } + Future _joinRtcChannel(RtcChannelData data) async { + try { + await RTCManager.instance.joinChannel( + token: data.token, + channelId: data.channelId, + ); + Get.to(() => const LiveRoomPage(id: 0)); + } catch (e) { + SmartDialog.showToast('加入频道失败:$e'); + } + } +} + diff --git a/lib/model/rtc/rtc_channel_data.dart b/lib/model/rtc/rtc_channel_data.dart new file mode 100644 index 0000000..05c65e0 --- /dev/null +++ b/lib/model/rtc/rtc_channel_data.dart @@ -0,0 +1,28 @@ +/// RTC 频道创建返回数据 +class RtcChannelData { + final String channelId; + final String token; + + RtcChannelData({ + required this.channelId, + required this.token, + }); + + factory RtcChannelData.fromJson(Map json) { + return RtcChannelData( + channelId: json['channelId']?.toString() ?? '', + token: json['token']?.toString() ?? '', + ); + } + + Map toJson() { + return { + 'channelId': channelId, + 'token': token, + }; + } + + @override + String toString() => 'RtcChannelData(channelId: $channelId)'; +} + diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 26ae64e..d5336df 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -23,6 +23,7 @@ class ApiUrls { static const String getMaritalStatusList = 'dating-agency-service/user/get/marital/status/list'; static const String getPropertyList = 'dating-agency-service/user/get/property/permits'; static const String getOccupationList = 'dating-agency-service/user/get/occupation/list'; + static const String createRtcChannel = 'dating-agency-chat-audio/user/create/rtc-channel'; //首页相关接口 static const String getMarriageList = 'dating-agency-service/user/page/dongwo/marriage-information'; diff --git a/lib/network/index.dart b/lib/network/index.dart index cd5873c..86c6913 100644 --- a/lib/network/index.dart +++ b/lib/network/index.dart @@ -1,4 +1,5 @@ export 'api_service.dart'; export 'network_config.dart'; export 'network_service.dart'; -export 'response_model.dart'; \ No newline at end of file +export 'response_model.dart'; +export 'rtc_api.dart'; \ No newline at end of file diff --git a/lib/network/network_service.dart b/lib/network/network_service.dart index 5ef54a2..07231da 100644 --- a/lib/network/network_service.dart +++ b/lib/network/network_service.dart @@ -5,6 +5,7 @@ import 'api_service.dart'; import 'home_api.dart'; import 'network_config.dart'; import 'user_api.dart'; +import 'rtc_api.dart'; /// 网络请求服务管理器 class NetworkService { @@ -14,6 +15,7 @@ class NetworkService { late final ApiService _apiService; // 主API服务 late final UserApi _userApi; late final HomeApi _homeApi; + late final RtcApi _rtcApi; /// 获取单例实例 factory NetworkService() { @@ -26,6 +28,7 @@ class NetworkService { _apiService = ApiService(dio); _userApi = UserApi(dio); _homeApi = HomeApi(dio); + _rtcApi = RtcApi(dio); } /// 通用GET请求 @@ -165,6 +168,9 @@ class NetworkService { /// 首页相关API HomeApi get homeApi => _homeApi; + /// RTC相关API + RtcApi get rtcApi => _rtcApi; + void _showLoading() { // 使用FlutterSmartDialog显示加载指示器 SmartDialog.showLoading(); diff --git a/lib/network/rtc_api.dart b/lib/network/rtc_api.dart new file mode 100644 index 0000000..c298e3c --- /dev/null +++ b/lib/network/rtc_api.dart @@ -0,0 +1,18 @@ +import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart'; +import 'package:dating_touchme_app/network/api_urls.dart'; +import 'package:dating_touchme_app/network/response_model.dart'; +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'rtc_api.g.dart'; + +/// RTC 相关接口 +@RestApi(baseUrl: '') +abstract class RtcApi { + factory RtcApi(Dio dio) = _RtcApi; + + /// 创建实时音视频频道 + @POST(ApiUrls.createRtcChannel) + Future>> createRtcChannel(); +} + diff --git a/lib/network/rtc_api.g.dart b/lib/network/rtc_api.g.dart new file mode 100644 index 0000000..528db3a --- /dev/null +++ b/lib/network/rtc_api.g.dart @@ -0,0 +1,81 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'rtc_api.dart'; + +// dart format off + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations,unused_element_parameter,avoid_unused_constructor_parameters,unreachable_from_main + +class _RtcApi implements RtcApi { + _RtcApi(this._dio, {this.baseUrl, this.errorLogger}); + + final Dio _dio; + + String? baseUrl; + + final ParseErrorLogger? errorLogger; + + @override + Future>> createRtcChannel() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/create/rtc-channel', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => RtcChannelData.fromJson(json as Map), + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} + +// dart format on diff --git a/lib/pages/discover/discover_page.dart b/lib/pages/discover/discover_page.dart index 4a5380a..ecafdad 100644 --- a/lib/pages/discover/discover_page.dart +++ b/lib/pages/discover/discover_page.dart @@ -1,4 +1,5 @@ import 'package:dating_touchme_app/components/home_appbar.dart'; +import 'package:dating_touchme_app/controller/discover/room_controller.dart'; import 'package:dating_touchme_app/generated/assets.dart'; import 'package:dating_touchme_app/pages/discover/live_room_page.dart'; import 'package:flutter/material.dart'; @@ -13,8 +14,7 @@ class DiscoverPage extends StatefulWidget { } class _DiscoverPageState extends State with AutomaticKeepAliveClientMixin{ - - + late final RoomController roomController; List topNav = ["相亲", "聚会脱单"]; @@ -42,6 +42,15 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie print("当前项: $active"); } + @override + void initState() { + super.initState(); + if (Get.isRegistered()) { + roomController = Get.find(); + } else { + roomController = Get.put(RoomController()); + } + } @override Widget build(BuildContext context) { @@ -61,8 +70,8 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie child: Column( children: [ HomeAppbar(topNav: topNav, changeNav: changeNav, right: InkWell( - onTap: (){ - print("12121"); + onTap: () async { + await roomController.createRtcChannel(); }, child: Container( width: 52.w,