➕ Add webrtc deps
This commit is contained in:
		| @@ -15,12 +15,12 @@ android { | |||||||
|     ndkVersion = flutter.ndkVersion |     ndkVersion = flutter.ndkVersion | ||||||
|  |  | ||||||
|     compileOptions { |     compileOptions { | ||||||
|         sourceCompatibility = JavaVersion.VERSION_1_8 |       sourceCompatibility JavaVersion.VERSION_17 | ||||||
|         targetCompatibility = JavaVersion.VERSION_1_8 |       targetCompatibility JavaVersion.VERSION_17 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     kotlinOptions { |     kotlinOptions { | ||||||
|         jvmTarget = JavaVersion.VERSION_1_8 |         jvmTarget = JavaVersion.VERSION_17 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     defaultConfig { |     defaultConfig { | ||||||
|   | |||||||
| @@ -1,4 +1,15 @@ | |||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <uses-feature android:name="android.hardware.camera" /> | ||||||
|  |     <uses-feature android:name="android.hardware.camera.autofocus" /> | ||||||
|  |     <uses-permission android:name="android.permission.INTERNET" /> | ||||||
|  |     <uses-permission android:name="android.permission.CAMERA" /> | ||||||
|  |     <uses-permission android:name="android.permission.RECORD_AUDIO" /> | ||||||
|  |     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||||||
|  |     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> | ||||||
|  |     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> | ||||||
|  |     <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> | ||||||
|  |     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> | ||||||
|  |  | ||||||
|     <application |     <application | ||||||
|         android:label="Solian" |         android:label="Solian" | ||||||
|         android:name="${applicationName}" |         android:name="${applicationName}" | ||||||
| @@ -17,12 +28,12 @@ | |||||||
|                  while the Flutter UI initializes. After that, this theme continues |                  while the Flutter UI initializes. After that, this theme continues | ||||||
|                  to determine the Window background behind the Flutter UI. --> |                  to determine the Window background behind the Flutter UI. --> | ||||||
|             <meta-data |             <meta-data | ||||||
|               android:name="io.flutter.embedding.android.NormalTheme" |                 android:name="io.flutter.embedding.android.NormalTheme" | ||||||
|               android:resource="@style/NormalTheme" |                 android:resource="@style/NormalTheme" | ||||||
|               /> |             /> | ||||||
|             <intent-filter> |             <intent-filter> | ||||||
|                 <action android:name="android.intent.action.MAIN"/> |                 <action android:name="android.intent.action.MAIN" /> | ||||||
|                 <category android:name="android.intent.category.LAUNCHER"/> |                 <category android:name="android.intent.category.LAUNCHER" /> | ||||||
|             </intent-filter> |             </intent-filter> | ||||||
|         </activity> |         </activity> | ||||||
|         <!-- Don't delete the meta-data below. |         <!-- Don't delete the meta-data below. | ||||||
| @@ -38,8 +49,8 @@ | |||||||
|          In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> |          In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> | ||||||
|     <queries> |     <queries> | ||||||
|         <intent> |         <intent> | ||||||
|             <action android:name="android.intent.action.PROCESS_TEXT"/> |             <action android:name="android.intent.action.PROCESS_TEXT" /> | ||||||
|             <data android:mimeType="text/plain"/> |             <data android:mimeType="text/plain" /> | ||||||
|         </intent> |         </intent> | ||||||
|     </queries> |     </queries> | ||||||
| </manifest> | </manifest> | ||||||
| @@ -40,5 +40,9 @@ end | |||||||
| post_install do |installer| | post_install do |installer| | ||||||
|   installer.pods_project.targets.each do |target| |   installer.pods_project.targets.each do |target| | ||||||
|     flutter_additional_ios_build_settings(target) |     flutter_additional_ios_build_settings(target) | ||||||
|  |     target.build_configurations.each do |config| | ||||||
|  |       # Workaround for https://github.com/flutter/flutter/issues/64502 | ||||||
|  |       config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' | ||||||
|  |      end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -105,6 +105,9 @@ PODS: | |||||||
|   - flutter_udid (0.0.1): |   - flutter_udid (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - SAMKeychain |     - SAMKeychain | ||||||
|  |   - flutter_webrtc (0.11.8): | ||||||
|  |     - Flutter | ||||||
|  |     - WebRTC-SDK (= 125.6422.05) | ||||||
|   - GoogleAppMeasurement (11.4.0): |   - GoogleAppMeasurement (11.4.0): | ||||||
|     - GoogleAppMeasurement/AdIdSupport (= 11.4.0) |     - GoogleAppMeasurement/AdIdSupport (= 11.4.0) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.0) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.0) | ||||||
| @@ -202,6 +205,7 @@ PODS: | |||||||
|     - Flutter |     - Flutter | ||||||
|   - wakelock_plus (0.0.1): |   - wakelock_plus (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|  |   - WebRTC-SDK (125.6422.05) | ||||||
|  |  | ||||||
| DEPENDENCIES: | DEPENDENCIES: | ||||||
|   - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) |   - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) | ||||||
| @@ -214,6 +218,7 @@ DEPENDENCIES: | |||||||
|   - Flutter (from `Flutter`) |   - Flutter (from `Flutter`) | ||||||
|   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) |   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) | ||||||
|   - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) |   - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) | ||||||
|  |   - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) | ||||||
|   - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) |   - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) | ||||||
|   - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`) |   - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`) | ||||||
|   - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) |   - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) | ||||||
| @@ -249,6 +254,7 @@ SPEC REPOS: | |||||||
|     - SDWebImage |     - SDWebImage | ||||||
|     - Sentry |     - Sentry | ||||||
|     - SwiftyGif |     - SwiftyGif | ||||||
|  |     - WebRTC-SDK | ||||||
|  |  | ||||||
| EXTERNAL SOURCES: | EXTERNAL SOURCES: | ||||||
|   connectivity_plus: |   connectivity_plus: | ||||||
| @@ -271,6 +277,8 @@ EXTERNAL SOURCES: | |||||||
|     :path: ".symlinks/plugins/flutter_native_splash/ios" |     :path: ".symlinks/plugins/flutter_native_splash/ios" | ||||||
|   flutter_udid: |   flutter_udid: | ||||||
|     :path: ".symlinks/plugins/flutter_udid/ios" |     :path: ".symlinks/plugins/flutter_udid/ios" | ||||||
|  |   flutter_webrtc: | ||||||
|  |     :path: ".symlinks/plugins/flutter_webrtc/ios" | ||||||
|   image_picker_ios: |   image_picker_ios: | ||||||
|     :path: ".symlinks/plugins/image_picker_ios/ios" |     :path: ".symlinks/plugins/image_picker_ios/ios" | ||||||
|   isar_flutter_libs: |   isar_flutter_libs: | ||||||
| @@ -321,6 +329,7 @@ SPEC CHECKSUMS: | |||||||
|   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 |   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 | ||||||
|   flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a |   flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a | ||||||
|   flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04 |   flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04 | ||||||
|  |   flutter_webrtc: 4f730f3d58a28b0afdea039c8bf4a0f616a6b20c | ||||||
|   GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e |   GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e | ||||||
|   GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 |   GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 | ||||||
|   GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d |   GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d | ||||||
| @@ -345,7 +354,8 @@ SPEC CHECKSUMS: | |||||||
|   url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe |   url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe | ||||||
|   volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 |   volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 | ||||||
|   wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 |   wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 | ||||||
|  |   WebRTC-SDK: 1990a1a595bd0b59c17485ce13ff17f575732c12 | ||||||
|  |  | ||||||
| PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5 | PODFILE CHECKSUM: d2bdaa1cc7915e14cf47235c34a21fcb07b00390 | ||||||
|  |  | ||||||
| COCOAPODS: 1.15.2 | COCOAPODS: 1.15.2 | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import 'package:easy_localization_loader/easy_localization_loader.dart'; | |||||||
| import 'package:firebase_core/firebase_core.dart'; | import 'package:firebase_core/firebase_core.dart'; | ||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:hive_flutter/hive_flutter.dart'; | import 'package:hive_flutter/hive_flutter.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| import 'package:relative_time/relative_time.dart'; | import 'package:relative_time/relative_time.dart'; | ||||||
| @@ -22,6 +23,7 @@ import 'package:surface/providers/websocket.dart'; | |||||||
| import 'package:surface/router.dart'; | import 'package:surface/router.dart'; | ||||||
| import 'package:surface/types/chat.dart'; | import 'package:surface/types/chat.dart'; | ||||||
| import 'package:surface/types/realm.dart'; | import 'package:surface/types/realm.dart'; | ||||||
|  | import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy; | ||||||
|  |  | ||||||
| void main() async { | void main() async { | ||||||
|   WidgetsFlutterBinding.ensureInitialized(); |   WidgetsFlutterBinding.ensureInitialized(); | ||||||
| @@ -41,6 +43,9 @@ void main() async { | |||||||
|     debugInvertOversizedImages = true; |     debugInvertOversizedImages = true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   GoRouter.optionURLReflectsImperativeAPIs = true; | ||||||
|  |   usePathUrlStrategy(); | ||||||
|  |  | ||||||
|   await SentryFlutter.init( |   await SentryFlutter.init( | ||||||
|     (options) { |     (options) { | ||||||
|       options.dsn = |       options.dsn = | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import 'package:surface/screens/album.dart'; | |||||||
| import 'package:surface/screens/auth/login.dart'; | import 'package:surface/screens/auth/login.dart'; | ||||||
| import 'package:surface/screens/auth/register.dart'; | import 'package:surface/screens/auth/register.dart'; | ||||||
| import 'package:surface/screens/chat.dart'; | import 'package:surface/screens/chat.dart'; | ||||||
|  | import 'package:surface/screens/chat/call_room.dart'; | ||||||
| import 'package:surface/screens/chat/manage.dart'; | import 'package:surface/screens/chat/manage.dart'; | ||||||
| import 'package:surface/screens/chat/room.dart'; | import 'package:surface/screens/chat/room.dart'; | ||||||
| import 'package:surface/screens/explore.dart'; | import 'package:surface/screens/explore.dart'; | ||||||
| @@ -47,7 +48,7 @@ final _appRoutes = [ | |||||||
|         ), |         ), | ||||||
|         routes: [ |         routes: [ | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/post/write/:mode', |             path: '/write/:mode', | ||||||
|             name: 'postEditor', |             name: 'postEditor', | ||||||
|             builder: (context, state) => AppBackground( |             builder: (context, state) => AppBackground( | ||||||
|               isLessOptimization: true, |               isLessOptimization: true, | ||||||
| @@ -66,14 +67,14 @@ final _appRoutes = [ | |||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/post/search', |             path: '/search', | ||||||
|             name: 'postSearch', |             name: 'postSearch', | ||||||
|             builder: (context, state) => const AppBackground( |             builder: (context, state) => const AppBackground( | ||||||
|               child: PostSearchScreen(), |               child: PostSearchScreen(), | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/post/:slug', |             path: '/:slug', | ||||||
|             name: 'postDetail', |             name: 'postDetail', | ||||||
|             builder: (context, state) => AppBackground( |             builder: (context, state) => AppBackground( | ||||||
|               child: PostDetailScreen( |               child: PostDetailScreen( | ||||||
| @@ -99,7 +100,7 @@ final _appRoutes = [ | |||||||
|         ), |         ), | ||||||
|         routes: [ |         routes: [ | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/chat/:scope/:alias', |             path: '/:scope/:alias', | ||||||
|             name: 'chatRoom', |             name: 'chatRoom', | ||||||
|             builder: (context, state) => AppBackground( |             builder: (context, state) => AppBackground( | ||||||
|               isLessOptimization: true, |               isLessOptimization: true, | ||||||
| @@ -110,7 +111,18 @@ final _appRoutes = [ | |||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/chat/manage', |             path: '/:scope/:alias/call', | ||||||
|  |             name: 'chatCallRoom', | ||||||
|  |             builder: (context, state) => AppBackground( | ||||||
|  |               isLessOptimization: true, | ||||||
|  |               child: CallRoomScreen( | ||||||
|  |                 scope: state.pathParameters['scope']!, | ||||||
|  |                 alias: state.pathParameters['alias']!, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           GoRoute( | ||||||
|  |             path: '/manage', | ||||||
|             name: 'chatManage', |             name: 'chatManage', | ||||||
|             pageBuilder: (context, state) => CustomTransitionPage( |             pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|               child: ChatManageScreen(), |               child: ChatManageScreen(), | ||||||
| @@ -138,7 +150,7 @@ final _appRoutes = [ | |||||||
|         ), |         ), | ||||||
|         routes: [ |         routes: [ | ||||||
|           GoRoute( |           GoRoute( | ||||||
|             path: '/realm/manage', |             path: '/manage', | ||||||
|             name: 'realmManage', |             name: 'realmManage', | ||||||
|             pageBuilder: (context, state) => CustomTransitionPage( |             pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|               child: RealmManageScreen( |               child: RealmManageScreen( | ||||||
|   | |||||||
							
								
								
									
										137
									
								
								lib/screens/chat/call_room.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/screens/chat/call_room.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
|  | import 'package:dio/dio.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_webrtc/flutter_webrtc.dart'; | ||||||
|  | import 'package:web_socket_channel/web_socket_channel.dart'; | ||||||
|  |  | ||||||
|  | class CallRoomScreen extends StatefulWidget { | ||||||
|  |   final String scope; | ||||||
|  |   final String alias; | ||||||
|  |   const CallRoomScreen({super.key, required this.scope, required this.alias}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CallRoomScreen> createState() => _CallRoomScreenState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const _kLocalWebRtcBaseUrl = 'http://localhost:8001'; | ||||||
|  |  | ||||||
|  | class _CallRoomScreenState extends State<CallRoomScreen> { | ||||||
|  |   RTCPeerConnection? _peerConnection; | ||||||
|  |   MediaStream? _localStream; | ||||||
|  |   WebSocketChannel? _wsChannel; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _initWebRtc(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> _initWebRtc() async { | ||||||
|  |     final client = Dio(); | ||||||
|  |     client.options.baseUrl = _kLocalWebRtcBaseUrl; | ||||||
|  |  | ||||||
|  |     final configResp = await client.get('/.well-known/webrtc'); | ||||||
|  |  | ||||||
|  |     // Get user media (audio only) | ||||||
|  |     _localStream = await navigator.mediaDevices.getUserMedia({ | ||||||
|  |       'audio': true, | ||||||
|  |       'video': false, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // Configure Peer Connection | ||||||
|  |     Map<String, dynamic> config = { | ||||||
|  |       'iceServers': configResp.data['ice_servers'] | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     _peerConnection = await createPeerConnection(config); | ||||||
|  |  | ||||||
|  |     // Add local stream to peer connection | ||||||
|  |     _peerConnection?.addStream(_localStream!); | ||||||
|  |  | ||||||
|  |     // Listen for ICE candidates | ||||||
|  |     _peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { | ||||||
|  |       print('New ICE candidate: ${candidate.candidate}'); | ||||||
|  |       // Send the candidate to the signaling server | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Handle remote stream | ||||||
|  |     _peerConnection?.onAddStream = (MediaStream stream) { | ||||||
|  |       print('Remote stream added'); | ||||||
|  |       // Play the remote stream | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     _wsChannel = WebSocketChannel.connect( | ||||||
|  |       Uri.parse('$_kLocalWebRtcBaseUrl/webrtc'), | ||||||
|  |     ); | ||||||
|  |     await _wsChannel!.ready; | ||||||
|  |  | ||||||
|  |     _wsChannel!.stream.listen((event) { | ||||||
|  |       final Map<String, dynamic> data = jsonDecode(event); | ||||||
|  |  | ||||||
|  |       switch (data['type']) { | ||||||
|  |         case 'offer': | ||||||
|  |           _handleOffer(data); | ||||||
|  |           break; | ||||||
|  |         case 'answer': | ||||||
|  |           _handleAnswer(data); | ||||||
|  |           break; | ||||||
|  |         case 'candidate': | ||||||
|  |           _handleCandidate(data); | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> _handleOffer(Map<String, dynamic> data) async { | ||||||
|  |     // Set remote description | ||||||
|  |     final offer = RTCSessionDescription(data['sdp'], data['type']); | ||||||
|  |     await _peerConnection?.setRemoteDescription(offer); | ||||||
|  |  | ||||||
|  |     // Create and send answer | ||||||
|  |     final answer = await _peerConnection?.createAnswer(); | ||||||
|  |     await _peerConnection?.setLocalDescription(answer!); | ||||||
|  |  | ||||||
|  |     _wsChannel?.sink.add({ | ||||||
|  |       'type': 'answer', | ||||||
|  |       'sdp': answer?.sdp, | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> _handleAnswer(Map<String, dynamic> data) async { | ||||||
|  |     // Set remote description | ||||||
|  |     final answer = RTCSessionDescription(data['sdp'], data['type']); | ||||||
|  |     await _peerConnection?.setRemoteDescription(answer); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> _handleCandidate(Map<String, dynamic> data) async { | ||||||
|  |     // Add ICE candidate | ||||||
|  |     final candidate = RTCIceCandidate( | ||||||
|  |       data['candidate'], | ||||||
|  |       data['sdpMid'], | ||||||
|  |       data['sdpMLineIndex'], | ||||||
|  |     ); | ||||||
|  |     await _peerConnection?.addCandidate(candidate); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _wsChannel?.sink.close(); | ||||||
|  |     _localStream?.dispose(); | ||||||
|  |     _peerConnection?.close(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       appBar: AppBar(title: Text('Voice Chat')), | ||||||
|  |       body: Center( | ||||||
|  |         child: ElevatedButton( | ||||||
|  |           onPressed: () {}, | ||||||
|  |           child: Text('Start Call'), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,5 +1,7 @@ | |||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| import 'package:surface/controllers/chat_message_controller.dart'; | import 'package:surface/controllers/chat_message_controller.dart'; | ||||||
| @@ -62,6 +64,18 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> { | |||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
|         title: Text(_channel?.name ?? 'loading'.tr()), |         title: Text(_channel?.name ?? 'loading'.tr()), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             onPressed: () { | ||||||
|  |               GoRouter.of(context).pushNamed('chatCallRoom', pathParameters: { | ||||||
|  |                 'scope': widget.scope, | ||||||
|  |                 'alias': widget.alias, | ||||||
|  |               }); | ||||||
|  |             }, | ||||||
|  |             icon: const Icon(Symbols.voice_chat), | ||||||
|  |           ), | ||||||
|  |           IconButton(onPressed: () {}, icon: const Icon(Symbols.more_vert)), | ||||||
|  |         ], | ||||||
|       ), |       ), | ||||||
|       body: ListenableBuilder( |       body: ListenableBuilder( | ||||||
|         listenable: _messageController, |         listenable: _messageController, | ||||||
|   | |||||||
| @@ -122,21 +122,25 @@ class _PostDetailScreenState extends State<PostDetailScreen> { | |||||||
|           const SliverToBoxAdapter(child: Divider(height: 1)), |           const SliverToBoxAdapter(child: Divider(height: 1)), | ||||||
|           if (_data != null) |           if (_data != null) | ||||||
|             SliverToBoxAdapter( |             SliverToBoxAdapter( | ||||||
|               child: Row( |               child: Container( | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.center, |                 constraints: const BoxConstraints(maxWidth: 640), | ||||||
|                 children: [ |                 child: Row( | ||||||
|                   const Icon(Symbols.comment, size: 24), |                   crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|                   const Gap(16), |                   children: [ | ||||||
|                   Text('postCommentsDetailed') |                     const Icon(Symbols.comment, size: 24), | ||||||
|                       .plural(_data!.metric.replyCount) |                     const Gap(16), | ||||||
|                       .textStyle(Theme.of(context).textTheme.titleLarge!), |                     Text('postCommentsDetailed') | ||||||
|                 ], |                         .plural(_data!.metric.replyCount) | ||||||
|               ).padding(horizontal: 20, vertical: 12), |                         .textStyle(Theme.of(context).textTheme.titleLarge!), | ||||||
|  |                   ], | ||||||
|  |                 ).padding(horizontal: 20, vertical: 12).center(), | ||||||
|  |               ), | ||||||
|             ), |             ), | ||||||
|           if (_data != null && ua.isAuthorized) |           if (_data != null && ua.isAuthorized) | ||||||
|             SliverToBoxAdapter( |             SliverToBoxAdapter( | ||||||
|               child: Container( |               child: Container( | ||||||
|                 height: 240, |                 height: 240, | ||||||
|  |                 constraints: const BoxConstraints(maxWidth: 640), | ||||||
|                 decoration: BoxDecoration( |                 decoration: BoxDecoration( | ||||||
|                   border: Border.symmetric( |                   border: Border.symmetric( | ||||||
|                     horizontal: BorderSide( |                     horizontal: BorderSide( | ||||||
| @@ -158,7 +162,7 @@ class _PostDetailScreenState extends State<PostDetailScreen> { | |||||||
|                     _childListKey.currentState!.refresh(); |                     _childListKey.currentState!.refresh(); | ||||||
|                   }, |                   }, | ||||||
|                 ), |                 ), | ||||||
|               ), |               ).center(), | ||||||
|             ), |             ), | ||||||
|           if (_data != null) |           if (_data != null) | ||||||
|             PostCommentSliverList( |             PostCommentSliverList( | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
|  |  | ||||||
| #include <file_selector_linux/file_selector_plugin.h> | #include <file_selector_linux/file_selector_plugin.h> | ||||||
| #include <flutter_udid/flutter_udid_plugin.h> | #include <flutter_udid/flutter_udid_plugin.h> | ||||||
| #include <isar_flutter_libs/isar_flutter_libs_plugin.h> | #include <flutter_webrtc/flutter_web_r_t_c_plugin.h> | ||||||
| #include <media_kit_libs_linux/media_kit_libs_linux_plugin.h> | #include <media_kit_libs_linux/media_kit_libs_linux_plugin.h> | ||||||
| #include <media_kit_video/media_kit_video_plugin.h> | #include <media_kit_video/media_kit_video_plugin.h> | ||||||
| #include <pasteboard/pasteboard_plugin.h> | #include <pasteboard/pasteboard_plugin.h> | ||||||
| @@ -22,9 +22,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { | |||||||
|   g_autoptr(FlPluginRegistrar) flutter_udid_registrar = |   g_autoptr(FlPluginRegistrar) flutter_udid_registrar = | ||||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterUdidPlugin"); |       fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterUdidPlugin"); | ||||||
|   flutter_udid_plugin_register_with_registrar(flutter_udid_registrar); |   flutter_udid_plugin_register_with_registrar(flutter_udid_registrar); | ||||||
|   g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = |   g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar = | ||||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); |       fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin"); | ||||||
|   isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); |   flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar); | ||||||
|   g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = |   g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = | ||||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); |       fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); | ||||||
|   media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); |   media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
| list(APPEND FLUTTER_PLUGIN_LIST | list(APPEND FLUTTER_PLUGIN_LIST | ||||||
|   file_selector_linux |   file_selector_linux | ||||||
|   flutter_udid |   flutter_udid | ||||||
|   isar_flutter_libs |   flutter_webrtc | ||||||
|   media_kit_libs_linux |   media_kit_libs_linux | ||||||
|   media_kit_video |   media_kit_video | ||||||
|   pasteboard |   pasteboard | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import firebase_analytics | |||||||
| import firebase_core | import firebase_core | ||||||
| import firebase_messaging | import firebase_messaging | ||||||
| import flutter_udid | import flutter_udid | ||||||
| import isar_flutter_libs | import flutter_webrtc | ||||||
| import media_kit_libs_macos_video | import media_kit_libs_macos_video | ||||||
| import media_kit_video | import media_kit_video | ||||||
| import package_info_plus | import package_info_plus | ||||||
| @@ -31,7 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | |||||||
|   FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) |   FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) | ||||||
|   FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) |   FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) | ||||||
|   FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) |   FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) | ||||||
|   IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) |   FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) | ||||||
|   MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) |   MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) | ||||||
|   MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) |   MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) | ||||||
|   FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) |   FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -310,6 +310,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "2.3.7" |     version: "2.3.7" | ||||||
|  |   dart_webrtc: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: dart_webrtc | ||||||
|  |       sha256: c664ad88d5646735753add421ee2118486c100febef5e92b7f59cdbabf6a51f6 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.4.9" | ||||||
|   dbus: |   dbus: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -630,10 +638,18 @@ packages: | |||||||
|     source: hosted |     source: hosted | ||||||
|     version: "3.0.0" |     version: "3.0.0" | ||||||
|   flutter_web_plugins: |   flutter_web_plugins: | ||||||
|     dependency: transitive |     dependency: "direct main" | ||||||
|     description: flutter |     description: flutter | ||||||
|     source: sdk |     source: sdk | ||||||
|     version: "0.0.0" |     version: "0.0.0" | ||||||
|  |   flutter_webrtc: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: flutter_webrtc | ||||||
|  |       sha256: "0b69ecab98211504c10d40c1c4cb48eb387e03ea8e732079bd0d2665d8c20d3f" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.12.1+hotfix.1" | ||||||
|   freezed: |   freezed: | ||||||
|     dependency: "direct dev" |     dependency: "direct dev" | ||||||
|     description: |     description: | ||||||
| @@ -858,22 +874,6 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.0.4" |     version: "1.0.4" | ||||||
|   isar: |  | ||||||
|     dependency: "direct main" |  | ||||||
|     description: |  | ||||||
|       name: isar |  | ||||||
|       sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea" |  | ||||||
|       url: "https://pub.dev" |  | ||||||
|     source: hosted |  | ||||||
|     version: "3.1.0+1" |  | ||||||
|   isar_flutter_libs: |  | ||||||
|     dependency: "direct main" |  | ||||||
|     description: |  | ||||||
|       name: isar_flutter_libs |  | ||||||
|       sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8 |  | ||||||
|       url: "https://pub.dev" |  | ||||||
|     source: hosted |  | ||||||
|     version: "3.1.0+1" |  | ||||||
|   jni: |   jni: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -1226,6 +1226,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "3.1.6" |     version: "3.1.6" | ||||||
|  |   platform_detect: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: platform_detect | ||||||
|  |       sha256: a62f99417fc4fa2d099ce0ccdbb1bd3977920f2a64292c326271f049d4bc3a4f | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.1.0" | ||||||
|   plugin_platform_interface: |   plugin_platform_interface: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -1791,6 +1799,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "3.0.1" |     version: "3.0.1" | ||||||
|  |   webrtc_interface: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: webrtc_interface | ||||||
|  |       sha256: abec3ab7956bd5ac539cf34a42fa0c82ea26675847c0966bb85160400eea9388 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.2.0" | ||||||
|   win32: |   win32: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|   | |||||||
| @@ -30,6 +30,8 @@ environment: | |||||||
| dependencies: | dependencies: | ||||||
|   flutter: |   flutter: | ||||||
|     sdk: flutter |     sdk: flutter | ||||||
|  |   flutter_web_plugins: | ||||||
|  |     sdk: flutter | ||||||
|  |  | ||||||
|   # The following adds the Cupertino Icons font to your application. |   # The following adds the Cupertino Icons font to your application. | ||||||
|   # Use with the CupertinoIcons class for iOS style icons. |   # Use with the CupertinoIcons class for iOS style icons. | ||||||
| @@ -73,8 +75,6 @@ dependencies: | |||||||
|   collection: ^1.18.0 |   collection: ^1.18.0 | ||||||
|   mime: ^2.0.0 |   mime: ^2.0.0 | ||||||
|   web_socket_channel: ^3.0.1 |   web_socket_channel: ^3.0.1 | ||||||
|   isar: ^3.1.0+1 |  | ||||||
|   isar_flutter_libs: ^3.1.0+1 |  | ||||||
|   hive: ^2.2.3 |   hive: ^2.2.3 | ||||||
|   hive_flutter: ^1.1.0 |   hive_flutter: ^1.1.0 | ||||||
|   swipe_to: ^1.0.6 |   swipe_to: ^1.0.6 | ||||||
| @@ -88,6 +88,7 @@ dependencies: | |||||||
|   pasteboard: ^0.3.0 |   pasteboard: ^0.3.0 | ||||||
|   sentry_flutter: ^8.10.1 |   sentry_flutter: ^8.10.1 | ||||||
|   synchronized: ^3.3.0+3 |   synchronized: ^3.3.0+3 | ||||||
|  |   flutter_webrtc: ^0.12.1+hotfix.1 | ||||||
|  |  | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   flutter_test: |   flutter_test: | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| #include <file_selector_windows/file_selector_windows.h> | #include <file_selector_windows/file_selector_windows.h> | ||||||
| #include <firebase_core/firebase_core_plugin_c_api.h> | #include <firebase_core/firebase_core_plugin_c_api.h> | ||||||
| #include <flutter_udid/flutter_udid_plugin_c_api.h> | #include <flutter_udid/flutter_udid_plugin_c_api.h> | ||||||
| #include <isar_flutter_libs/isar_flutter_libs_plugin.h> | #include <flutter_webrtc/flutter_web_r_t_c_plugin.h> | ||||||
| #include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h> | #include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h> | ||||||
| #include <media_kit_video/media_kit_video_plugin_c_api.h> | #include <media_kit_video/media_kit_video_plugin_c_api.h> | ||||||
| #include <pasteboard/pasteboard_plugin.h> | #include <pasteboard/pasteboard_plugin.h> | ||||||
| @@ -27,8 +27,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { | |||||||
|       registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); |       registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); | ||||||
|   FlutterUdidPluginCApiRegisterWithRegistrar( |   FlutterUdidPluginCApiRegisterWithRegistrar( | ||||||
|       registry->GetRegistrarForPlugin("FlutterUdidPluginCApi")); |       registry->GetRegistrarForPlugin("FlutterUdidPluginCApi")); | ||||||
|   IsarFlutterLibsPluginRegisterWithRegistrar( |   FlutterWebRTCPluginRegisterWithRegistrar( | ||||||
|       registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); |       registry->GetRegistrarForPlugin("FlutterWebRTCPlugin")); | ||||||
|   MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( |   MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( | ||||||
|       registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); |       registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); | ||||||
|   MediaKitVideoPluginCApiRegisterWithRegistrar( |   MediaKitVideoPluginCApiRegisterWithRegistrar( | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST | |||||||
|   file_selector_windows |   file_selector_windows | ||||||
|   firebase_core |   firebase_core | ||||||
|   flutter_udid |   flutter_udid | ||||||
|   isar_flutter_libs |   flutter_webrtc | ||||||
|   media_kit_libs_windows_video |   media_kit_libs_windows_video | ||||||
|   media_kit_video |   media_kit_video | ||||||
|   pasteboard |   pasteboard | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user