Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
fd587270da | |||
6b4189a93b | |||
fed8171b36 | |||
f39a066f71 | |||
edf4ff1c5b | |||
9abc61a310 | |||
205d52df46 | |||
a2053aa772 | |||
81103ba8b6 | |||
76faa4172f | |||
9866c22746 |
@ -41,5 +41,9 @@ end
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |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' # <= this line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,6 @@
|
||||
PODS:
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- croppy (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
@ -84,6 +86,9 @@ PODS:
|
||||
- flutter_udid (0.0.1):
|
||||
- Flutter
|
||||
- SAMKeychain
|
||||
- flutter_webrtc (0.14.0):
|
||||
- Flutter
|
||||
- WebRTC-SDK (= 125.6422.07)
|
||||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
@ -116,6 +121,10 @@ PODS:
|
||||
- irondash_engine_context (0.0.1):
|
||||
- Flutter
|
||||
- Kingfisher (8.3.2)
|
||||
- livekit_client (2.4.7):
|
||||
- Flutter
|
||||
- flutter_webrtc
|
||||
- WebRTC-SDK (= 125.6422.07)
|
||||
- media_kit_libs_ios_video (1.0.4):
|
||||
- Flutter
|
||||
- media_kit_video (0.0.1):
|
||||
@ -173,8 +182,10 @@ PODS:
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
- WebRTC-SDK (125.6422.07)
|
||||
|
||||
DEPENDENCIES:
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
@ -185,9 +196,11 @@ DEPENDENCIES:
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/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`)
|
||||
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
||||
- Kingfisher (~> 8.0)
|
||||
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
@ -219,8 +232,11 @@ SPEC REPOS:
|
||||
- SDWebImage
|
||||
- sqlite3
|
||||
- SwiftyGif
|
||||
- WebRTC-SDK
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
croppy:
|
||||
:path: ".symlinks/plugins/croppy/ios"
|
||||
device_info_plus:
|
||||
@ -241,10 +257,14 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_platform_alert/ios"
|
||||
flutter_udid:
|
||||
:path: ".symlinks/plugins/flutter_udid/ios"
|
||||
flutter_webrtc:
|
||||
:path: ".symlinks/plugins/flutter_webrtc/ios"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
irondash_engine_context:
|
||||
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
||||
livekit_client:
|
||||
:path: ".symlinks/plugins/livekit_client/ios"
|
||||
media_kit_libs_ios_video:
|
||||
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
||||
media_kit_video:
|
||||
@ -269,6 +289,7 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
@ -286,11 +307,13 @@ SPEC CHECKSUMS:
|
||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||
flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3
|
||||
flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
|
||||
flutter_webrtc: fd0d3bdef8766a0736dbbe2e5b7e85f1f3c52117
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
|
||||
livekit_client: c30950bf36aa4c0244dd5551b1818cd15f90ba32
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
@ -309,7 +332,8 @@ SPEC CHECKSUMS:
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
WebRTC-SDK: dff00a3892bc570b6014e046297782084071657e
|
||||
|
||||
PODFILE CHECKSUM: 4c3fad73fbbc9053a824d880097bda7884240991
|
||||
PODFILE CHECKSUM: 2608312fddeea6d787ca3aa478c756da8f4ca66d
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
@ -498,6 +498,7 @@
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -683,6 +684,7 @@
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -708,6 +710,7 @@
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@ -54,6 +55,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -7,7 +7,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Island</string>
|
||||
<string>Solian</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>island</string>
|
||||
<string>solian</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
@ -26,6 +26,16 @@
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
@ -33,11 +43,14 @@
|
||||
<string>fetch</string>
|
||||
<string>audio</string>
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
@ -51,17 +64,5 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -85,4 +85,5 @@ class DefaultFirebaseOptions {
|
||||
storageBucket: 'solian-0x001.firebasestorage.app',
|
||||
measurementId: 'G-JD1YEG9D6F',
|
||||
);
|
||||
|
||||
}
|
@ -19,6 +19,7 @@ import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/route.dart';
|
||||
import 'package:island/screens/auth/tabs.dart';
|
||||
import 'package:island/services/notify.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:relative_time/relative_time.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@ -28,11 +29,21 @@ import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
void main() async {
|
||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||
log(
|
||||
"[SplashScreen] Keeping the flash screen to loading other resources...",
|
||||
);
|
||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
}
|
||||
|
||||
try {
|
||||
await EasyLocalization.ensureInitialized();
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
log("[SplashScreen] Firebase is ready!");
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
}
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
@ -43,6 +54,7 @@ void main() async {
|
||||
appWindow.size = initialSize;
|
||||
appWindow.alignment = Alignment.center;
|
||||
appWindow.show();
|
||||
log("[SplashScreen] Desktop window is ready!");
|
||||
});
|
||||
}
|
||||
|
||||
@ -52,10 +64,12 @@ void main() async {
|
||||
if (imagePickerImplementation is ImagePickerAndroid) {
|
||||
imagePickerImplementation.useAndroidPhotoPicker = true;
|
||||
}
|
||||
log("[SplashScreen] Android image picker is ready!");
|
||||
}
|
||||
|
||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||
FlutterNativeSplash.remove();
|
||||
log("[SplashScreen] Now hiding the splash screen...");
|
||||
}
|
||||
|
||||
runApp(
|
||||
|
@ -5,7 +5,7 @@ part 'activity.freezed.dart';
|
||||
part 'activity.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnActivity with _$SnActivity {
|
||||
sealed class SnActivity with _$SnActivity {
|
||||
const factory SnActivity({
|
||||
required String id,
|
||||
required String type,
|
||||
@ -24,7 +24,7 @@ abstract class SnActivity with _$SnActivity {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnCheckInResult with _$SnCheckInResult {
|
||||
sealed class SnCheckInResult with _$SnCheckInResult {
|
||||
const factory SnCheckInResult({
|
||||
required String id,
|
||||
required int level,
|
||||
@ -41,7 +41,7 @@ abstract class SnCheckInResult with _$SnCheckInResult {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnFortuneTip with _$SnFortuneTip {
|
||||
sealed class SnFortuneTip with _$SnFortuneTip {
|
||||
const factory SnFortuneTip({
|
||||
required bool isPositive,
|
||||
required String title,
|
||||
@ -53,7 +53,7 @@ abstract class SnFortuneTip with _$SnFortuneTip {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnEventCalendarEntry with _$SnEventCalendarEntry {
|
||||
sealed class SnEventCalendarEntry with _$SnEventCalendarEntry {
|
||||
const factory SnEventCalendarEntry({
|
||||
required DateTime date,
|
||||
required SnCheckInResult? checkInResult,
|
||||
|
@ -4,7 +4,7 @@ part 'auth.freezed.dart';
|
||||
part 'auth.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class AppTokenPair with _$AppTokenPair {
|
||||
sealed class AppTokenPair with _$AppTokenPair {
|
||||
const factory AppTokenPair({
|
||||
required String accessToken,
|
||||
required String refreshToken,
|
||||
@ -15,7 +15,7 @@ abstract class AppTokenPair with _$AppTokenPair {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnAuthChallenge with _$SnAuthChallenge {
|
||||
sealed class SnAuthChallenge with _$SnAuthChallenge {
|
||||
const factory SnAuthChallenge({
|
||||
required String id,
|
||||
required DateTime expiredAt,
|
||||
@ -38,7 +38,7 @@ abstract class SnAuthChallenge with _$SnAuthChallenge {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnAuthFactor with _$SnAuthFactor {
|
||||
sealed class SnAuthFactor with _$SnAuthFactor {
|
||||
const factory SnAuthFactor({
|
||||
required String id,
|
||||
required int type,
|
||||
|
@ -7,7 +7,7 @@ part 'chat.freezed.dart';
|
||||
part 'chat.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnChatRoom with _$SnChatRoom {
|
||||
sealed class SnChatRoom with _$SnChatRoom {
|
||||
const factory SnChatRoom({
|
||||
required String id,
|
||||
required String? name,
|
||||
@ -31,12 +31,13 @@ abstract class SnChatRoom with _$SnChatRoom {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnChatMessage with _$SnChatMessage {
|
||||
sealed class SnChatMessage with _$SnChatMessage {
|
||||
const factory SnChatMessage({
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
DateTime? deletedAt,
|
||||
required String id,
|
||||
@Default('text') String type,
|
||||
String? content,
|
||||
String? nonce,
|
||||
@Default({}) Map<String, dynamic> meta,
|
||||
@ -56,7 +57,7 @@ abstract class SnChatMessage with _$SnChatMessage {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnChatReaction with _$SnChatReaction {
|
||||
sealed class SnChatReaction with _$SnChatReaction {
|
||||
const factory SnChatReaction({
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
@ -74,7 +75,7 @@ abstract class SnChatReaction with _$SnChatReaction {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnChatMember with _$SnChatMember {
|
||||
sealed class SnChatMember with _$SnChatMember {
|
||||
const factory SnChatMember({
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
@ -96,7 +97,7 @@ abstract class SnChatMember with _$SnChatMember {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnChatSummary with _$SnChatSummary {
|
||||
sealed class SnChatSummary with _$SnChatSummary {
|
||||
const factory SnChatSummary({
|
||||
required int unreadCount,
|
||||
required SnChatMessage lastMessage,
|
||||
@ -113,7 +114,7 @@ class MessageChangeAction {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class MessageChange with _$MessageChange {
|
||||
sealed class MessageChange with _$MessageChange {
|
||||
const factory MessageChange({
|
||||
required String messageId,
|
||||
required String action,
|
||||
@ -126,7 +127,7 @@ abstract class MessageChange with _$MessageChange {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class MessageSyncResponse with _$MessageSyncResponse {
|
||||
sealed class MessageSyncResponse with _$MessageSyncResponse {
|
||||
const factory MessageSyncResponse({
|
||||
@Default([]) List<MessageChange> changes,
|
||||
required DateTime currentTimestamp,
|
||||
@ -137,12 +138,52 @@ abstract class MessageSyncResponse with _$MessageSyncResponse {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ChatRealtimeJoinResponse with _$ChatRealtimeJoinResponse {
|
||||
sealed class ChatRealtimeJoinResponse with _$ChatRealtimeJoinResponse {
|
||||
const factory ChatRealtimeJoinResponse({
|
||||
required String provider,
|
||||
required String endpoint,
|
||||
required String token,
|
||||
required Map<String, dynamic> config,
|
||||
required String callId,
|
||||
required String roomName,
|
||||
required bool isAdmin,
|
||||
required List<CallParticipant> participants,
|
||||
}) = _ChatRealtimeJoinResponse;
|
||||
|
||||
factory ChatRealtimeJoinResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChatRealtimeJoinResponseFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class CallParticipant with _$CallParticipant {
|
||||
const factory CallParticipant({
|
||||
required String identity,
|
||||
required String name,
|
||||
required DateTime joinedAt,
|
||||
required String? accountId,
|
||||
required SnChatMember? profile,
|
||||
}) = _CallParticipant;
|
||||
|
||||
factory CallParticipant.fromJson(Map<String, dynamic> json) =>
|
||||
_$CallParticipantFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnRealtimeCall with _$SnRealtimeCall {
|
||||
const factory SnRealtimeCall({
|
||||
required String id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
required DateTime? endedAt,
|
||||
required String senderId,
|
||||
required SnChatMember sender,
|
||||
required String roomId,
|
||||
required SnChatRoom room,
|
||||
required Map<String, dynamic> upstreamConfig,
|
||||
String? providerName,
|
||||
String? sessionId,
|
||||
}) = _SnRealtimeCall;
|
||||
|
||||
factory SnRealtimeCall.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnRealtimeCallFromJson(json);
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ $SnRealmCopyWith<$Res>? get realm {
|
||||
/// @nodoc
|
||||
mixin _$SnChatMessage {
|
||||
|
||||
DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String? get content; String? get nonce; Map<String, dynamic> get meta; List<String> get membersMetioned; DateTime? get editedAt; List<SnCloudFile> get attachments; List<SnChatReaction> get reactions; String? get repliedMessageId; String? get forwardedMessageId; String get senderId; SnChatMember get sender; String get chatRoomId;
|
||||
DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get type; String? get content; String? get nonce; Map<String, dynamic> get meta; List<String> get membersMetioned; DateTime? get editedAt; List<SnCloudFile> get attachments; List<SnChatReaction> get reactions; String? get repliedMessageId; String? get forwardedMessageId; String get senderId; SnChatMember get sender; String get chatRoomId;
|
||||
/// Create a copy of SnChatMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -284,16 +284,16 @@ $SnChatMessageCopyWith<SnChatMessage> get copyWith => _$SnChatMessageCopyWithImp
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMessage&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&const DeepCollectionEquality().equals(other.meta, meta)&&const DeepCollectionEquality().equals(other.membersMetioned, membersMetioned)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&(identical(other.repliedMessageId, repliedMessageId) || other.repliedMessageId == repliedMessageId)&&(identical(other.forwardedMessageId, forwardedMessageId) || other.forwardedMessageId == forwardedMessageId)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMessage&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.content, content) || other.content == content)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&const DeepCollectionEquality().equals(other.meta, meta)&&const DeepCollectionEquality().equals(other.membersMetioned, membersMetioned)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&(identical(other.repliedMessageId, repliedMessageId) || other.repliedMessageId == repliedMessageId)&&(identical(other.forwardedMessageId, forwardedMessageId) || other.forwardedMessageId == forwardedMessageId)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,content,nonce,const DeepCollectionEquality().hash(meta),const DeepCollectionEquality().hash(membersMetioned),editedAt,const DeepCollectionEquality().hash(attachments),const DeepCollectionEquality().hash(reactions),repliedMessageId,forwardedMessageId,senderId,sender,chatRoomId);
|
||||
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,type,content,nonce,const DeepCollectionEquality().hash(meta),const DeepCollectionEquality().hash(membersMetioned),editedAt,const DeepCollectionEquality().hash(attachments),const DeepCollectionEquality().hash(reactions),repliedMessageId,forwardedMessageId,senderId,sender,chatRoomId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnChatMessage(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, content: $content, nonce: $nonce, meta: $meta, membersMetioned: $membersMetioned, editedAt: $editedAt, attachments: $attachments, reactions: $reactions, repliedMessageId: $repliedMessageId, forwardedMessageId: $forwardedMessageId, senderId: $senderId, sender: $sender, chatRoomId: $chatRoomId)';
|
||||
return 'SnChatMessage(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, type: $type, content: $content, nonce: $nonce, meta: $meta, membersMetioned: $membersMetioned, editedAt: $editedAt, attachments: $attachments, reactions: $reactions, repliedMessageId: $repliedMessageId, forwardedMessageId: $forwardedMessageId, senderId: $senderId, sender: $sender, chatRoomId: $chatRoomId)';
|
||||
}
|
||||
|
||||
|
||||
@ -304,7 +304,7 @@ abstract mixin class $SnChatMessageCopyWith<$Res> {
|
||||
factory $SnChatMessageCopyWith(SnChatMessage value, $Res Function(SnChatMessage) _then) = _$SnChatMessageCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String? content, String? nonce, Map<String, dynamic> meta, List<String> membersMetioned, DateTime? editedAt, List<SnCloudFile> attachments, List<SnChatReaction> reactions, String? repliedMessageId, String? forwardedMessageId, String senderId, SnChatMember sender, String chatRoomId
|
||||
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String type, String? content, String? nonce, Map<String, dynamic> meta, List<String> membersMetioned, DateTime? editedAt, List<SnCloudFile> attachments, List<SnChatReaction> reactions, String? repliedMessageId, String? forwardedMessageId, String senderId, SnChatMember sender, String chatRoomId
|
||||
});
|
||||
|
||||
|
||||
@ -321,12 +321,13 @@ class _$SnChatMessageCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnChatMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? content = freezed,Object? nonce = freezed,Object? meta = null,Object? membersMetioned = null,Object? editedAt = freezed,Object? attachments = null,Object? reactions = null,Object? repliedMessageId = freezed,Object? forwardedMessageId = freezed,Object? senderId = null,Object? sender = null,Object? chatRoomId = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? type = null,Object? content = freezed,Object? nonce = freezed,Object? meta = null,Object? membersMetioned = null,Object? editedAt = freezed,Object? attachments = null,Object? reactions = null,Object? repliedMessageId = freezed,Object? forwardedMessageId = freezed,Object? senderId = null,Object? sender = null,Object? chatRoomId = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||
as String?,meta: null == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
@ -359,13 +360,14 @@ $SnChatMemberCopyWith<$Res> get sender {
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnChatMessage implements SnChatMessage {
|
||||
const _SnChatMessage({required this.createdAt, required this.updatedAt, this.deletedAt, required this.id, this.content, this.nonce, final Map<String, dynamic> meta = const {}, final List<String> membersMetioned = const [], this.editedAt, final List<SnCloudFile> attachments = const [], final List<SnChatReaction> reactions = const [], this.repliedMessageId, this.forwardedMessageId, required this.senderId, required this.sender, required this.chatRoomId}): _meta = meta,_membersMetioned = membersMetioned,_attachments = attachments,_reactions = reactions;
|
||||
const _SnChatMessage({required this.createdAt, required this.updatedAt, this.deletedAt, required this.id, this.type = 'text', this.content, this.nonce, final Map<String, dynamic> meta = const {}, final List<String> membersMetioned = const [], this.editedAt, final List<SnCloudFile> attachments = const [], final List<SnChatReaction> reactions = const [], this.repliedMessageId, this.forwardedMessageId, required this.senderId, required this.sender, required this.chatRoomId}): _meta = meta,_membersMetioned = membersMetioned,_attachments = attachments,_reactions = reactions;
|
||||
factory _SnChatMessage.fromJson(Map<String, dynamic> json) => _$SnChatMessageFromJson(json);
|
||||
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override final DateTime? deletedAt;
|
||||
@override final String id;
|
||||
@override@JsonKey() final String type;
|
||||
@override final String? content;
|
||||
@override final String? nonce;
|
||||
final Map<String, dynamic> _meta;
|
||||
@ -416,16 +418,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMessage&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&const DeepCollectionEquality().equals(other._meta, _meta)&&const DeepCollectionEquality().equals(other._membersMetioned, _membersMetioned)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&(identical(other.repliedMessageId, repliedMessageId) || other.repliedMessageId == repliedMessageId)&&(identical(other.forwardedMessageId, forwardedMessageId) || other.forwardedMessageId == forwardedMessageId)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMessage&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.content, content) || other.content == content)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&const DeepCollectionEquality().equals(other._meta, _meta)&&const DeepCollectionEquality().equals(other._membersMetioned, _membersMetioned)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&(identical(other.repliedMessageId, repliedMessageId) || other.repliedMessageId == repliedMessageId)&&(identical(other.forwardedMessageId, forwardedMessageId) || other.forwardedMessageId == forwardedMessageId)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,content,nonce,const DeepCollectionEquality().hash(_meta),const DeepCollectionEquality().hash(_membersMetioned),editedAt,const DeepCollectionEquality().hash(_attachments),const DeepCollectionEquality().hash(_reactions),repliedMessageId,forwardedMessageId,senderId,sender,chatRoomId);
|
||||
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,type,content,nonce,const DeepCollectionEquality().hash(_meta),const DeepCollectionEquality().hash(_membersMetioned),editedAt,const DeepCollectionEquality().hash(_attachments),const DeepCollectionEquality().hash(_reactions),repliedMessageId,forwardedMessageId,senderId,sender,chatRoomId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnChatMessage(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, content: $content, nonce: $nonce, meta: $meta, membersMetioned: $membersMetioned, editedAt: $editedAt, attachments: $attachments, reactions: $reactions, repliedMessageId: $repliedMessageId, forwardedMessageId: $forwardedMessageId, senderId: $senderId, sender: $sender, chatRoomId: $chatRoomId)';
|
||||
return 'SnChatMessage(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, type: $type, content: $content, nonce: $nonce, meta: $meta, membersMetioned: $membersMetioned, editedAt: $editedAt, attachments: $attachments, reactions: $reactions, repliedMessageId: $repliedMessageId, forwardedMessageId: $forwardedMessageId, senderId: $senderId, sender: $sender, chatRoomId: $chatRoomId)';
|
||||
}
|
||||
|
||||
|
||||
@ -436,7 +438,7 @@ abstract mixin class _$SnChatMessageCopyWith<$Res> implements $SnChatMessageCopy
|
||||
factory _$SnChatMessageCopyWith(_SnChatMessage value, $Res Function(_SnChatMessage) _then) = __$SnChatMessageCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String? content, String? nonce, Map<String, dynamic> meta, List<String> membersMetioned, DateTime? editedAt, List<SnCloudFile> attachments, List<SnChatReaction> reactions, String? repliedMessageId, String? forwardedMessageId, String senderId, SnChatMember sender, String chatRoomId
|
||||
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String type, String? content, String? nonce, Map<String, dynamic> meta, List<String> membersMetioned, DateTime? editedAt, List<SnCloudFile> attachments, List<SnChatReaction> reactions, String? repliedMessageId, String? forwardedMessageId, String senderId, SnChatMember sender, String chatRoomId
|
||||
});
|
||||
|
||||
|
||||
@ -453,12 +455,13 @@ class __$SnChatMessageCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnChatMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? content = freezed,Object? nonce = freezed,Object? meta = null,Object? membersMetioned = null,Object? editedAt = freezed,Object? attachments = null,Object? reactions = null,Object? repliedMessageId = freezed,Object? forwardedMessageId = freezed,Object? senderId = null,Object? sender = null,Object? chatRoomId = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? type = null,Object? content = freezed,Object? nonce = freezed,Object? meta = null,Object? membersMetioned = null,Object? editedAt = freezed,Object? attachments = null,Object? reactions = null,Object? repliedMessageId = freezed,Object? forwardedMessageId = freezed,Object? senderId = null,Object? sender = null,Object? chatRoomId = null,}) {
|
||||
return _then(_SnChatMessage(
|
||||
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||
as String?,meta: null == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
@ -1339,7 +1342,7 @@ as DateTime,
|
||||
/// @nodoc
|
||||
mixin _$ChatRealtimeJoinResponse {
|
||||
|
||||
String get token; Map<String, dynamic> get config;
|
||||
String get provider; String get endpoint; String get token; String get callId; String get roomName; bool get isAdmin; List<CallParticipant> get participants;
|
||||
/// Create a copy of ChatRealtimeJoinResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -1352,16 +1355,16 @@ $ChatRealtimeJoinResponseCopyWith<ChatRealtimeJoinResponse> get copyWith => _$Ch
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ChatRealtimeJoinResponse&&(identical(other.token, token) || other.token == token)&&const DeepCollectionEquality().equals(other.config, config));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ChatRealtimeJoinResponse&&(identical(other.provider, provider) || other.provider == provider)&&(identical(other.endpoint, endpoint) || other.endpoint == endpoint)&&(identical(other.token, token) || other.token == token)&&(identical(other.callId, callId) || other.callId == callId)&&(identical(other.roomName, roomName) || other.roomName == roomName)&&(identical(other.isAdmin, isAdmin) || other.isAdmin == isAdmin)&&const DeepCollectionEquality().equals(other.participants, participants));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,token,const DeepCollectionEquality().hash(config));
|
||||
int get hashCode => Object.hash(runtimeType,provider,endpoint,token,callId,roomName,isAdmin,const DeepCollectionEquality().hash(participants));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatRealtimeJoinResponse(token: $token, config: $config)';
|
||||
return 'ChatRealtimeJoinResponse(provider: $provider, endpoint: $endpoint, token: $token, callId: $callId, roomName: $roomName, isAdmin: $isAdmin, participants: $participants)';
|
||||
}
|
||||
|
||||
|
||||
@ -1372,7 +1375,7 @@ abstract mixin class $ChatRealtimeJoinResponseCopyWith<$Res> {
|
||||
factory $ChatRealtimeJoinResponseCopyWith(ChatRealtimeJoinResponse value, $Res Function(ChatRealtimeJoinResponse) _then) = _$ChatRealtimeJoinResponseCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String token, Map<String, dynamic> config
|
||||
String provider, String endpoint, String token, String callId, String roomName, bool isAdmin, List<CallParticipant> participants
|
||||
});
|
||||
|
||||
|
||||
@ -1389,11 +1392,16 @@ class _$ChatRealtimeJoinResponseCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ChatRealtimeJoinResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? token = null,Object? config = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? provider = null,Object? endpoint = null,Object? token = null,Object? callId = null,Object? roomName = null,Object? isAdmin = null,Object? participants = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
as String,config: null == config ? _self.config : config // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,
|
||||
provider: null == provider ? _self.provider : provider // ignore: cast_nullable_to_non_nullable
|
||||
as String,endpoint: null == endpoint ? _self.endpoint : endpoint // ignore: cast_nullable_to_non_nullable
|
||||
as String,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
as String,callId: null == callId ? _self.callId : callId // ignore: cast_nullable_to_non_nullable
|
||||
as String,roomName: null == roomName ? _self.roomName : roomName // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdmin: null == isAdmin ? _self.isAdmin : isAdmin // ignore: cast_nullable_to_non_nullable
|
||||
as bool,participants: null == participants ? _self.participants : participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<CallParticipant>,
|
||||
));
|
||||
}
|
||||
|
||||
@ -1404,15 +1412,20 @@ as Map<String, dynamic>,
|
||||
@JsonSerializable()
|
||||
|
||||
class _ChatRealtimeJoinResponse implements ChatRealtimeJoinResponse {
|
||||
const _ChatRealtimeJoinResponse({required this.token, required final Map<String, dynamic> config}): _config = config;
|
||||
const _ChatRealtimeJoinResponse({required this.provider, required this.endpoint, required this.token, required this.callId, required this.roomName, required this.isAdmin, required final List<CallParticipant> participants}): _participants = participants;
|
||||
factory _ChatRealtimeJoinResponse.fromJson(Map<String, dynamic> json) => _$ChatRealtimeJoinResponseFromJson(json);
|
||||
|
||||
@override final String provider;
|
||||
@override final String endpoint;
|
||||
@override final String token;
|
||||
final Map<String, dynamic> _config;
|
||||
@override Map<String, dynamic> get config {
|
||||
if (_config is EqualUnmodifiableMapView) return _config;
|
||||
@override final String callId;
|
||||
@override final String roomName;
|
||||
@override final bool isAdmin;
|
||||
final List<CallParticipant> _participants;
|
||||
@override List<CallParticipant> get participants {
|
||||
if (_participants is EqualUnmodifiableListView) return _participants;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_config);
|
||||
return EqualUnmodifiableListView(_participants);
|
||||
}
|
||||
|
||||
|
||||
@ -1429,16 +1442,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChatRealtimeJoinResponse&&(identical(other.token, token) || other.token == token)&&const DeepCollectionEquality().equals(other._config, _config));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChatRealtimeJoinResponse&&(identical(other.provider, provider) || other.provider == provider)&&(identical(other.endpoint, endpoint) || other.endpoint == endpoint)&&(identical(other.token, token) || other.token == token)&&(identical(other.callId, callId) || other.callId == callId)&&(identical(other.roomName, roomName) || other.roomName == roomName)&&(identical(other.isAdmin, isAdmin) || other.isAdmin == isAdmin)&&const DeepCollectionEquality().equals(other._participants, _participants));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,token,const DeepCollectionEquality().hash(_config));
|
||||
int get hashCode => Object.hash(runtimeType,provider,endpoint,token,callId,roomName,isAdmin,const DeepCollectionEquality().hash(_participants));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatRealtimeJoinResponse(token: $token, config: $config)';
|
||||
return 'ChatRealtimeJoinResponse(provider: $provider, endpoint: $endpoint, token: $token, callId: $callId, roomName: $roomName, isAdmin: $isAdmin, participants: $participants)';
|
||||
}
|
||||
|
||||
|
||||
@ -1449,7 +1462,7 @@ abstract mixin class _$ChatRealtimeJoinResponseCopyWith<$Res> implements $ChatRe
|
||||
factory _$ChatRealtimeJoinResponseCopyWith(_ChatRealtimeJoinResponse value, $Res Function(_ChatRealtimeJoinResponse) _then) = __$ChatRealtimeJoinResponseCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String token, Map<String, dynamic> config
|
||||
String provider, String endpoint, String token, String callId, String roomName, bool isAdmin, List<CallParticipant> participants
|
||||
});
|
||||
|
||||
|
||||
@ -1466,15 +1479,397 @@ class __$ChatRealtimeJoinResponseCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ChatRealtimeJoinResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? token = null,Object? config = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? provider = null,Object? endpoint = null,Object? token = null,Object? callId = null,Object? roomName = null,Object? isAdmin = null,Object? participants = null,}) {
|
||||
return _then(_ChatRealtimeJoinResponse(
|
||||
token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
as String,config: null == config ? _self._config : config // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,
|
||||
provider: null == provider ? _self.provider : provider // ignore: cast_nullable_to_non_nullable
|
||||
as String,endpoint: null == endpoint ? _self.endpoint : endpoint // ignore: cast_nullable_to_non_nullable
|
||||
as String,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable
|
||||
as String,callId: null == callId ? _self.callId : callId // ignore: cast_nullable_to_non_nullable
|
||||
as String,roomName: null == roomName ? _self.roomName : roomName // ignore: cast_nullable_to_non_nullable
|
||||
as String,isAdmin: null == isAdmin ? _self.isAdmin : isAdmin // ignore: cast_nullable_to_non_nullable
|
||||
as bool,participants: null == participants ? _self._participants : participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<CallParticipant>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CallParticipant {
|
||||
|
||||
String get identity; String get name; DateTime get joinedAt; String? get accountId; SnChatMember? get profile;
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallParticipantCopyWith<CallParticipant> get copyWith => _$CallParticipantCopyWithImpl<CallParticipant>(this as CallParticipant, _$identity);
|
||||
|
||||
/// Serializes this CallParticipant to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.profile, profile) || other.profile == profile));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,joinedAt,accountId,profile);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipant(identity: $identity, name: $name, joinedAt: $joinedAt, accountId: $accountId, profile: $profile)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $CallParticipantCopyWith<$Res> {
|
||||
factory $CallParticipantCopyWith(CallParticipant value, $Res Function(CallParticipant) _then) = _$CallParticipantCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String identity, String name, DateTime joinedAt, String? accountId, SnChatMember? profile
|
||||
});
|
||||
|
||||
|
||||
$SnChatMemberCopyWith<$Res>? get profile;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$CallParticipantCopyWithImpl<$Res>
|
||||
implements $CallParticipantCopyWith<$Res> {
|
||||
_$CallParticipantCopyWithImpl(this._self, this._then);
|
||||
|
||||
final CallParticipant _self;
|
||||
final $Res Function(CallParticipant) _then;
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? identity = null,Object? name = null,Object? joinedAt = null,Object? accountId = freezed,Object? profile = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
identity: null == identity ? _self.identity : identity // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,profile: freezed == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMember?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMemberCopyWith<$Res>? get profile {
|
||||
if (_self.profile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnChatMemberCopyWith<$Res>(_self.profile!, (value) {
|
||||
return _then(_self.copyWith(profile: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _CallParticipant implements CallParticipant {
|
||||
const _CallParticipant({required this.identity, required this.name, required this.joinedAt, required this.accountId, required this.profile});
|
||||
factory _CallParticipant.fromJson(Map<String, dynamic> json) => _$CallParticipantFromJson(json);
|
||||
|
||||
@override final String identity;
|
||||
@override final String name;
|
||||
@override final DateTime joinedAt;
|
||||
@override final String? accountId;
|
||||
@override final SnChatMember? profile;
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$CallParticipantCopyWith<_CallParticipant> get copyWith => __$CallParticipantCopyWithImpl<_CallParticipant>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$CallParticipantToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.profile, profile) || other.profile == profile));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,joinedAt,accountId,profile);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipant(identity: $identity, name: $name, joinedAt: $joinedAt, accountId: $accountId, profile: $profile)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$CallParticipantCopyWith<$Res> implements $CallParticipantCopyWith<$Res> {
|
||||
factory _$CallParticipantCopyWith(_CallParticipant value, $Res Function(_CallParticipant) _then) = __$CallParticipantCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String identity, String name, DateTime joinedAt, String? accountId, SnChatMember? profile
|
||||
});
|
||||
|
||||
|
||||
@override $SnChatMemberCopyWith<$Res>? get profile;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$CallParticipantCopyWithImpl<$Res>
|
||||
implements _$CallParticipantCopyWith<$Res> {
|
||||
__$CallParticipantCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _CallParticipant _self;
|
||||
final $Res Function(_CallParticipant) _then;
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? identity = null,Object? name = null,Object? joinedAt = null,Object? accountId = freezed,Object? profile = freezed,}) {
|
||||
return _then(_CallParticipant(
|
||||
identity: null == identity ? _self.identity : identity // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,profile: freezed == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMember?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMemberCopyWith<$Res>? get profile {
|
||||
if (_self.profile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnChatMemberCopyWith<$Res>(_self.profile!, (value) {
|
||||
return _then(_self.copyWith(profile: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SnRealtimeCall {
|
||||
|
||||
String get id; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; DateTime? get endedAt; String get senderId; SnChatMember get sender; String get roomId; SnChatRoom get room; Map<String, dynamic> get upstreamConfig; String? get providerName; String? get sessionId;
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnRealtimeCallCopyWith<SnRealtimeCall> get copyWith => _$SnRealtimeCallCopyWithImpl<SnRealtimeCall>(this as SnRealtimeCall, _$identity);
|
||||
|
||||
/// Serializes this SnRealtimeCall to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnRealtimeCall&&(identical(other.id, id) || other.id == id)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.endedAt, endedAt) || other.endedAt == endedAt)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.roomId, roomId) || other.roomId == roomId)&&(identical(other.room, room) || other.room == room)&&const DeepCollectionEquality().equals(other.upstreamConfig, upstreamConfig)&&(identical(other.providerName, providerName) || other.providerName == providerName)&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,createdAt,updatedAt,deletedAt,endedAt,senderId,sender,roomId,room,const DeepCollectionEquality().hash(upstreamConfig),providerName,sessionId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnRealtimeCall(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, endedAt: $endedAt, senderId: $senderId, sender: $sender, roomId: $roomId, room: $room, upstreamConfig: $upstreamConfig, providerName: $providerName, sessionId: $sessionId)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SnRealtimeCallCopyWith<$Res> {
|
||||
factory $SnRealtimeCallCopyWith(SnRealtimeCall value, $Res Function(SnRealtimeCall) _then) = _$SnRealtimeCallCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, DateTime? endedAt, String senderId, SnChatMember sender, String roomId, SnChatRoom room, Map<String, dynamic> upstreamConfig, String? providerName, String? sessionId
|
||||
});
|
||||
|
||||
|
||||
$SnChatMemberCopyWith<$Res> get sender;$SnChatRoomCopyWith<$Res> get room;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$SnRealtimeCallCopyWithImpl<$Res>
|
||||
implements $SnRealtimeCallCopyWith<$Res> {
|
||||
_$SnRealtimeCallCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SnRealtimeCall _self;
|
||||
final $Res Function(SnRealtimeCall) _then;
|
||||
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? endedAt = freezed,Object? senderId = null,Object? sender = null,Object? roomId = null,Object? room = null,Object? upstreamConfig = null,Object? providerName = freezed,Object? sessionId = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,endedAt: freezed == endedAt ? _self.endedAt : endedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,senderId: null == senderId ? _self.senderId : senderId // ignore: cast_nullable_to_non_nullable
|
||||
as String,sender: null == sender ? _self.sender : sender // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMember,roomId: null == roomId ? _self.roomId : roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String,room: null == room ? _self.room : room // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatRoom,upstreamConfig: null == upstreamConfig ? _self.upstreamConfig : upstreamConfig // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,providerName: freezed == providerName ? _self.providerName : providerName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,sessionId: freezed == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMemberCopyWith<$Res> get sender {
|
||||
|
||||
return $SnChatMemberCopyWith<$Res>(_self.sender, (value) {
|
||||
return _then(_self.copyWith(sender: value));
|
||||
});
|
||||
}/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatRoomCopyWith<$Res> get room {
|
||||
|
||||
return $SnChatRoomCopyWith<$Res>(_self.room, (value) {
|
||||
return _then(_self.copyWith(room: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnRealtimeCall implements SnRealtimeCall {
|
||||
const _SnRealtimeCall({required this.id, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.endedAt, required this.senderId, required this.sender, required this.roomId, required this.room, required final Map<String, dynamic> upstreamConfig, this.providerName, this.sessionId}): _upstreamConfig = upstreamConfig;
|
||||
factory _SnRealtimeCall.fromJson(Map<String, dynamic> json) => _$SnRealtimeCallFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override final DateTime? deletedAt;
|
||||
@override final DateTime? endedAt;
|
||||
@override final String senderId;
|
||||
@override final SnChatMember sender;
|
||||
@override final String roomId;
|
||||
@override final SnChatRoom room;
|
||||
final Map<String, dynamic> _upstreamConfig;
|
||||
@override Map<String, dynamic> get upstreamConfig {
|
||||
if (_upstreamConfig is EqualUnmodifiableMapView) return _upstreamConfig;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_upstreamConfig);
|
||||
}
|
||||
|
||||
@override final String? providerName;
|
||||
@override final String? sessionId;
|
||||
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SnRealtimeCallCopyWith<_SnRealtimeCall> get copyWith => __$SnRealtimeCallCopyWithImpl<_SnRealtimeCall>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$SnRealtimeCallToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnRealtimeCall&&(identical(other.id, id) || other.id == id)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.endedAt, endedAt) || other.endedAt == endedAt)&&(identical(other.senderId, senderId) || other.senderId == senderId)&&(identical(other.sender, sender) || other.sender == sender)&&(identical(other.roomId, roomId) || other.roomId == roomId)&&(identical(other.room, room) || other.room == room)&&const DeepCollectionEquality().equals(other._upstreamConfig, _upstreamConfig)&&(identical(other.providerName, providerName) || other.providerName == providerName)&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,createdAt,updatedAt,deletedAt,endedAt,senderId,sender,roomId,room,const DeepCollectionEquality().hash(_upstreamConfig),providerName,sessionId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnRealtimeCall(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, endedAt: $endedAt, senderId: $senderId, sender: $sender, roomId: $roomId, room: $room, upstreamConfig: $upstreamConfig, providerName: $providerName, sessionId: $sessionId)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SnRealtimeCallCopyWith<$Res> implements $SnRealtimeCallCopyWith<$Res> {
|
||||
factory _$SnRealtimeCallCopyWith(_SnRealtimeCall value, $Res Function(_SnRealtimeCall) _then) = __$SnRealtimeCallCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, DateTime? endedAt, String senderId, SnChatMember sender, String roomId, SnChatRoom room, Map<String, dynamic> upstreamConfig, String? providerName, String? sessionId
|
||||
});
|
||||
|
||||
|
||||
@override $SnChatMemberCopyWith<$Res> get sender;@override $SnChatRoomCopyWith<$Res> get room;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$SnRealtimeCallCopyWithImpl<$Res>
|
||||
implements _$SnRealtimeCallCopyWith<$Res> {
|
||||
__$SnRealtimeCallCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SnRealtimeCall _self;
|
||||
final $Res Function(_SnRealtimeCall) _then;
|
||||
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? endedAt = freezed,Object? senderId = null,Object? sender = null,Object? roomId = null,Object? room = null,Object? upstreamConfig = null,Object? providerName = freezed,Object? sessionId = freezed,}) {
|
||||
return _then(_SnRealtimeCall(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,endedAt: freezed == endedAt ? _self.endedAt : endedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,senderId: null == senderId ? _self.senderId : senderId // ignore: cast_nullable_to_non_nullable
|
||||
as String,sender: null == sender ? _self.sender : sender // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMember,roomId: null == roomId ? _self.roomId : roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String,room: null == room ? _self.room : room // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatRoom,upstreamConfig: null == upstreamConfig ? _self._upstreamConfig : upstreamConfig // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,providerName: freezed == providerName ? _self.providerName : providerName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,sessionId: freezed == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMemberCopyWith<$Res> get sender {
|
||||
|
||||
return $SnChatMemberCopyWith<$Res>(_self.sender, (value) {
|
||||
return _then(_self.copyWith(sender: value));
|
||||
});
|
||||
}/// Create a copy of SnRealtimeCall
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatRoomCopyWith<$Res> get room {
|
||||
|
||||
return $SnChatRoomCopyWith<$Res>(_self.room, (value) {
|
||||
return _then(_self.copyWith(room: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
@ -67,6 +67,7 @@ _SnChatMessage _$SnChatMessageFromJson(Map<String, dynamic> json) =>
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
id: json['id'] as String,
|
||||
type: json['type'] as String? ?? 'text',
|
||||
content: json['content'] as String?,
|
||||
nonce: json['nonce'] as String?,
|
||||
meta: json['meta'] as Map<String, dynamic>? ?? const {},
|
||||
@ -102,6 +103,7 @@ Map<String, dynamic> _$SnChatMessageToJson(_SnChatMessage instance) =>
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'id': instance.id,
|
||||
'type': instance.type,
|
||||
'content': instance.content,
|
||||
'nonce': instance.nonce,
|
||||
'meta': instance.meta,
|
||||
@ -241,10 +243,85 @@ Map<String, dynamic> _$MessageSyncResponseToJson(
|
||||
_ChatRealtimeJoinResponse _$ChatRealtimeJoinResponseFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _ChatRealtimeJoinResponse(
|
||||
provider: json['provider'] as String,
|
||||
endpoint: json['endpoint'] as String,
|
||||
token: json['token'] as String,
|
||||
config: json['config'] as Map<String, dynamic>,
|
||||
callId: json['call_id'] as String,
|
||||
roomName: json['room_name'] as String,
|
||||
isAdmin: json['is_admin'] as bool,
|
||||
participants:
|
||||
(json['participants'] as List<dynamic>)
|
||||
.map((e) => CallParticipant.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ChatRealtimeJoinResponseToJson(
|
||||
_ChatRealtimeJoinResponse instance,
|
||||
) => <String, dynamic>{'token': instance.token, 'config': instance.config};
|
||||
) => <String, dynamic>{
|
||||
'provider': instance.provider,
|
||||
'endpoint': instance.endpoint,
|
||||
'token': instance.token,
|
||||
'call_id': instance.callId,
|
||||
'room_name': instance.roomName,
|
||||
'is_admin': instance.isAdmin,
|
||||
'participants': instance.participants.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
_CallParticipant _$CallParticipantFromJson(Map<String, dynamic> json) =>
|
||||
_CallParticipant(
|
||||
identity: json['identity'] as String,
|
||||
name: json['name'] as String,
|
||||
joinedAt: DateTime.parse(json['joined_at'] as String),
|
||||
accountId: json['account_id'] as String?,
|
||||
profile:
|
||||
json['profile'] == null
|
||||
? null
|
||||
: SnChatMember.fromJson(json['profile'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CallParticipantToJson(_CallParticipant instance) =>
|
||||
<String, dynamic>{
|
||||
'identity': instance.identity,
|
||||
'name': instance.name,
|
||||
'joined_at': instance.joinedAt.toIso8601String(),
|
||||
'account_id': instance.accountId,
|
||||
'profile': instance.profile?.toJson(),
|
||||
};
|
||||
|
||||
_SnRealtimeCall _$SnRealtimeCallFromJson(Map<String, dynamic> json) =>
|
||||
_SnRealtimeCall(
|
||||
id: json['id'] as String,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt:
|
||||
json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
endedAt:
|
||||
json['ended_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['ended_at'] as String),
|
||||
senderId: json['sender_id'] as String,
|
||||
sender: SnChatMember.fromJson(json['sender'] as Map<String, dynamic>),
|
||||
roomId: json['room_id'] as String,
|
||||
room: SnChatRoom.fromJson(json['room'] as Map<String, dynamic>),
|
||||
upstreamConfig: json['upstream_config'] as Map<String, dynamic>,
|
||||
providerName: json['provider_name'] as String?,
|
||||
sessionId: json['session_id'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnRealtimeCallToJson(_SnRealtimeCall instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'ended_at': instance.endedAt?.toIso8601String(),
|
||||
'sender_id': instance.senderId,
|
||||
'sender': instance.sender.toJson(),
|
||||
'room_id': instance.roomId,
|
||||
'room': instance.room.toJson(),
|
||||
'upstream_config': instance.upstreamConfig,
|
||||
'provider_name': instance.providerName,
|
||||
'session_id': instance.sessionId,
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ part 'file.g.dart';
|
||||
enum UniversalFileType { image, video, audio, file }
|
||||
|
||||
@freezed
|
||||
abstract class UniversalFile with _$UniversalFile {
|
||||
sealed class UniversalFile with _$UniversalFile {
|
||||
const UniversalFile._();
|
||||
|
||||
const factory UniversalFile({
|
||||
@ -31,7 +31,7 @@ abstract class UniversalFile with _$UniversalFile {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnCloudFile with _$SnCloudFile {
|
||||
sealed class SnCloudFile with _$SnCloudFile {
|
||||
const factory SnCloudFile({
|
||||
required String id,
|
||||
required String name,
|
||||
|
@ -5,7 +5,7 @@ part 'post.freezed.dart';
|
||||
part 'post.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnPost with _$SnPost {
|
||||
sealed class SnPost with _$SnPost {
|
||||
const factory SnPost({
|
||||
required String id,
|
||||
required String? title,
|
||||
@ -43,7 +43,7 @@ abstract class SnPost with _$SnPost {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnPublisher with _$SnPublisher {
|
||||
sealed class SnPublisher with _$SnPublisher {
|
||||
const factory SnPublisher({
|
||||
required String id,
|
||||
required int type,
|
||||
@ -66,7 +66,7 @@ abstract class SnPublisher with _$SnPublisher {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnPublisherStats with _$SnPublisherStats {
|
||||
sealed class SnPublisherStats with _$SnPublisherStats {
|
||||
const factory SnPublisherStats({
|
||||
required int postsCreated,
|
||||
required int stickerPacksCreated,
|
||||
@ -80,7 +80,7 @@ abstract class SnPublisherStats with _$SnPublisherStats {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnSubscriptionStatus with _$SnSubscriptionStatus {
|
||||
sealed class SnSubscriptionStatus with _$SnSubscriptionStatus {
|
||||
const factory SnSubscriptionStatus({
|
||||
required bool isSubscribed,
|
||||
required int publisherId,
|
||||
@ -92,7 +92,7 @@ abstract class SnSubscriptionStatus with _$SnSubscriptionStatus {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ReactInfo with _$ReactInfo {
|
||||
sealed class ReactInfo with _$ReactInfo {
|
||||
const factory ReactInfo({required String icon, required int attitude}) =
|
||||
_ReactInfo;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ part 'realm.freezed.dart';
|
||||
part 'realm.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnRealm with _$SnRealm {
|
||||
sealed class SnRealm with _$SnRealm {
|
||||
const factory SnRealm({
|
||||
required String id,
|
||||
required String slug,
|
||||
@ -31,7 +31,7 @@ abstract class SnRealm with _$SnRealm {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnRealmMember with _$SnRealmMember {
|
||||
sealed class SnRealmMember with _$SnRealmMember {
|
||||
const factory SnRealmMember({
|
||||
required String realmId,
|
||||
required SnRealm? realm,
|
||||
|
@ -6,7 +6,7 @@ part 'relationship.freezed.dart';
|
||||
part 'relationship.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnRelationship with _$SnRelationship {
|
||||
sealed class SnRelationship with _$SnRelationship {
|
||||
const factory SnRelationship({
|
||||
required DateTime? createdAt,
|
||||
required DateTime? updatedAt,
|
||||
|
@ -6,7 +6,7 @@ part 'sticker.freezed.dart';
|
||||
part 'sticker.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnSticker with _$SnSticker {
|
||||
sealed class SnSticker with _$SnSticker {
|
||||
const factory SnSticker({
|
||||
required String id,
|
||||
required String slug,
|
||||
@ -24,7 +24,7 @@ abstract class SnSticker with _$SnSticker {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnStickerPack with _$SnStickerPack {
|
||||
sealed class SnStickerPack with _$SnStickerPack {
|
||||
const factory SnStickerPack({
|
||||
required String id,
|
||||
required String name,
|
||||
|
@ -5,7 +5,7 @@ part 'user.freezed.dart';
|
||||
part 'user.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnAccount with _$SnAccount {
|
||||
sealed class SnAccount with _$SnAccount {
|
||||
const factory SnAccount({
|
||||
required String id,
|
||||
required String name,
|
||||
@ -24,7 +24,7 @@ abstract class SnAccount with _$SnAccount {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnAccountProfile with _$SnAccountProfile {
|
||||
sealed class SnAccountProfile with _$SnAccountProfile {
|
||||
const factory SnAccountProfile({
|
||||
required String id,
|
||||
required String? firstName,
|
||||
@ -48,7 +48,7 @@ abstract class SnAccountProfile with _$SnAccountProfile {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnAccountStatus with _$SnAccountStatus {
|
||||
sealed class SnAccountStatus with _$SnAccountStatus {
|
||||
const factory SnAccountStatus({
|
||||
required String id,
|
||||
required int attitude,
|
||||
@ -69,7 +69,7 @@ abstract class SnAccountStatus with _$SnAccountStatus {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnAccountBadge with _$SnAccountBadge {
|
||||
sealed class SnAccountBadge with _$SnAccountBadge {
|
||||
const factory SnAccountBadge({
|
||||
required String id,
|
||||
required String type,
|
||||
@ -88,7 +88,7 @@ abstract class SnAccountBadge with _$SnAccountBadge {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnNotification with _$SnNotification {
|
||||
sealed class SnNotification with _$SnNotification {
|
||||
const factory SnNotification({
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
|
@ -5,7 +5,7 @@ part 'wallet.freezed.dart';
|
||||
part 'wallet.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class SnWallet with _$SnWallet {
|
||||
sealed class SnWallet with _$SnWallet {
|
||||
const factory SnWallet({
|
||||
required String id,
|
||||
required List<SnWalletPocket> pockets,
|
||||
@ -21,7 +21,7 @@ abstract class SnWallet with _$SnWallet {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnWalletPocket with _$SnWalletPocket {
|
||||
sealed class SnWalletPocket with _$SnWalletPocket {
|
||||
const factory SnWalletPocket({
|
||||
required String id,
|
||||
required String currency,
|
||||
@ -37,7 +37,7 @@ abstract class SnWalletPocket with _$SnWalletPocket {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SnTransaction with _$SnTransaction {
|
||||
sealed class SnTransaction with _$SnTransaction {
|
||||
const factory SnTransaction({
|
||||
required String id,
|
||||
required String currency,
|
||||
|
318
lib/pods/call.dart
Normal file
318
lib/pods/call.dart
Normal file
@ -0,0 +1,318 @@
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/screens/chat/chat.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/models/chat.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
|
||||
part 'call.g.dart';
|
||||
part 'call.freezed.dart';
|
||||
|
||||
@freezed
|
||||
sealed class CallState with _$CallState {
|
||||
const factory CallState({
|
||||
required bool isConnected,
|
||||
required bool isMicrophoneEnabled,
|
||||
required bool isCameraEnabled,
|
||||
required bool isScreenSharing,
|
||||
String? error,
|
||||
}) = _CallState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class CallParticipantLive with _$CallParticipantLive {
|
||||
const CallParticipantLive._();
|
||||
|
||||
const factory CallParticipantLive({
|
||||
required CallParticipant participant,
|
||||
required Participant remoteParticipant,
|
||||
}) = _CallParticipantLive;
|
||||
|
||||
bool get isSpeaking => remoteParticipant.isSpeaking;
|
||||
bool get isMuted => remoteParticipant.isMuted;
|
||||
bool get isScreenSharing => remoteParticipant.isScreenShareEnabled();
|
||||
bool get isScreenSharingWithAudio =>
|
||||
remoteParticipant.isScreenShareAudioEnabled();
|
||||
|
||||
bool get hasVideo => remoteParticipant.hasVideo;
|
||||
bool get hasAudio => remoteParticipant.hasAudio;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class CallNotifier extends _$CallNotifier {
|
||||
Room? _room;
|
||||
LocalParticipant? _localParticipant;
|
||||
List<CallParticipantLive> _participants = [];
|
||||
final Map<String, CallParticipant> _participantInfoByIdentity = {};
|
||||
StreamSubscription? _wsSubscription;
|
||||
EventsListener? _roomListener;
|
||||
|
||||
List<CallParticipantLive> get participants =>
|
||||
List.unmodifiable(_participants);
|
||||
LocalParticipant? get localParticipant => _localParticipant;
|
||||
|
||||
@override
|
||||
CallState build() {
|
||||
// Subscribe to websocket updates
|
||||
_subscribeToParticipantsUpdate();
|
||||
return const CallState(
|
||||
isConnected: false,
|
||||
isMicrophoneEnabled: true,
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
);
|
||||
}
|
||||
|
||||
void _subscribeToParticipantsUpdate() {
|
||||
// Only subscribe once
|
||||
if (_wsSubscription != null) return;
|
||||
final ws = ref.read(websocketProvider);
|
||||
_wsSubscription = ws.dataStream.listen((packet) {
|
||||
if (packet.type == 'call.participants.update' && packet.data != null) {
|
||||
final participantsData = packet.data!["participants"];
|
||||
if (participantsData is List) {
|
||||
final parsed =
|
||||
participantsData
|
||||
.map(
|
||||
(e) =>
|
||||
CallParticipant.fromJson(Map<String, dynamic>.from(e)),
|
||||
)
|
||||
.toList();
|
||||
_updateLiveParticipants(parsed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _initRoomListeners() {
|
||||
if (_room == null) return;
|
||||
_roomListener?.dispose();
|
||||
_roomListener = _room!.createListener();
|
||||
_room!.addListener(_onRoomChange);
|
||||
_roomListener!
|
||||
..on<ParticipantConnectedEvent>((e) {
|
||||
_refreshLiveParticipants();
|
||||
})
|
||||
..on<RoomDisconnectedEvent>((e) {
|
||||
_participants = [];
|
||||
state = state.copyWith();
|
||||
});
|
||||
}
|
||||
|
||||
void _onRoomChange() {
|
||||
_refreshLiveParticipants();
|
||||
}
|
||||
|
||||
void _refreshLiveParticipants() {
|
||||
if (_room == null) return;
|
||||
final remoteParticipants = _room!.remoteParticipants;
|
||||
_participants = [];
|
||||
// Add local participant first if available
|
||||
if (_localParticipant != null) {
|
||||
final localInfo = _buildParticipant();
|
||||
_participants.add(
|
||||
CallParticipantLive(
|
||||
participant: localInfo,
|
||||
remoteParticipant: _localParticipant!,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Add remote participants
|
||||
_participants.addAll(
|
||||
remoteParticipants.values.map((remote) {
|
||||
final match =
|
||||
_participantInfoByIdentity[remote.identity] ??
|
||||
CallParticipant(
|
||||
identity: remote.identity,
|
||||
name: remote.identity,
|
||||
joinedAt: DateTime.now(),
|
||||
accountId: null,
|
||||
profile: null,
|
||||
);
|
||||
return CallParticipantLive(
|
||||
participant: match,
|
||||
remoteParticipant: remote,
|
||||
);
|
||||
}),
|
||||
);
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
/// Builds the CallParticipant object for the local participant.
|
||||
/// Optionally, pass [participants] if you want to prioritize info from the latest list.
|
||||
CallParticipant _buildParticipant({List<CallParticipant>? participants}) {
|
||||
if (_localParticipant == null) {
|
||||
throw StateError('No local participant available');
|
||||
}
|
||||
// Prefer info from the latest participants list if available
|
||||
if (participants != null) {
|
||||
final idx = participants.indexWhere(
|
||||
(p) => p.identity == _localParticipant!.identity,
|
||||
);
|
||||
if (idx != -1) return participants[idx];
|
||||
}
|
||||
|
||||
final userInfo = ref.read(userInfoProvider);
|
||||
final roomIdentity = ref.read(chatroomIdentityProvider(_roomId));
|
||||
// Otherwise, use info from the identity map or fallback to minimal
|
||||
return _participantInfoByIdentity[_localParticipant!.identity] ??
|
||||
CallParticipant(
|
||||
identity: _localParticipant!.identity,
|
||||
name: _localParticipant!.identity,
|
||||
joinedAt: DateTime.now(),
|
||||
accountId: userInfo.value?.id,
|
||||
profile: roomIdentity.value,
|
||||
);
|
||||
}
|
||||
|
||||
void _updateLiveParticipants(List<CallParticipant> participants) {
|
||||
// Update the info map for lookup
|
||||
for (final p in participants) {
|
||||
_participantInfoByIdentity[p.identity] = p;
|
||||
}
|
||||
if (_room == null) {
|
||||
// Can't build live objects, just store empty
|
||||
_participants = [];
|
||||
state = state.copyWith();
|
||||
return;
|
||||
}
|
||||
final remoteParticipants = _room!.remoteParticipants;
|
||||
final remotes = remoteParticipants.values.toList();
|
||||
_participants = [];
|
||||
// Add local participant if present in the list
|
||||
if (_localParticipant != null) {
|
||||
final localInfo = _buildParticipant(participants: participants);
|
||||
_participants.add(
|
||||
CallParticipantLive(
|
||||
participant: localInfo,
|
||||
remoteParticipant: _localParticipant!,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Add remote participants
|
||||
_participants.addAll(
|
||||
participants.map((p) {
|
||||
RemoteParticipant? remote;
|
||||
for (final r in remotes) {
|
||||
if (r.identity == p.identity) {
|
||||
remote = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_localParticipant != null &&
|
||||
p.identity == _localParticipant!.identity) {
|
||||
return null; // Already added local
|
||||
}
|
||||
return remote != null
|
||||
? CallParticipantLive(participant: p, remoteParticipant: remote)
|
||||
: null;
|
||||
}).whereType<CallParticipantLive>(),
|
||||
);
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
String? _roomId;
|
||||
String? get roomId => _roomId;
|
||||
|
||||
Future<void> joinRoom(String roomId) async {
|
||||
_roomId = roomId;
|
||||
try {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final response = await apiClient.get('/chat/realtime/$roomId/join');
|
||||
if (response.statusCode == 200 && response.data != null) {
|
||||
final data = response.data;
|
||||
// Parse join response
|
||||
final joinResponse = ChatRealtimeJoinResponse.fromJson(data);
|
||||
final participants = joinResponse.participants;
|
||||
final String endpoint = joinResponse.endpoint;
|
||||
final String token = joinResponse.token;
|
||||
// Connect to LiveKit
|
||||
_room = Room();
|
||||
|
||||
await _room!.connect(
|
||||
endpoint,
|
||||
token,
|
||||
connectOptions: ConnectOptions(autoSubscribe: true),
|
||||
roomOptions: RoomOptions(adaptiveStream: true, dynacast: true),
|
||||
fastConnectOptions: FastConnectOptions(
|
||||
microphone: TrackOption(enabled: true),
|
||||
),
|
||||
);
|
||||
_localParticipant = _room!.localParticipant;
|
||||
|
||||
_initRoomListeners();
|
||||
_updateLiveParticipants(participants);
|
||||
|
||||
// Listen for connection updates
|
||||
_room!.addListener(() {
|
||||
state = state.copyWith(
|
||||
isConnected: _room!.connectionState == ConnectionState.connected,
|
||||
isMicrophoneEnabled: _localParticipant!.isMicrophoneEnabled(),
|
||||
isCameraEnabled: _localParticipant!.isCameraEnabled(),
|
||||
isScreenSharing: _localParticipant!.isScreenShareEnabled(),
|
||||
);
|
||||
});
|
||||
state = state.copyWith(isConnected: true);
|
||||
} else {
|
||||
state = state.copyWith(error: 'Failed to join room');
|
||||
}
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleMicrophone() async {
|
||||
if (_localParticipant != null) {
|
||||
const autostop = true;
|
||||
final target = !_localParticipant!.isMicrophoneEnabled();
|
||||
state = state.copyWith(isMicrophoneEnabled: target);
|
||||
if (target) {
|
||||
await _localParticipant!.audioTrackPublications.firstOrNull?.unmute(
|
||||
stopOnMute: autostop,
|
||||
);
|
||||
} else {
|
||||
await _localParticipant!.audioTrackPublications.firstOrNull?.mute(
|
||||
stopOnMute: autostop,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleCamera() async {
|
||||
if (_localParticipant != null) {
|
||||
final target = !_localParticipant!.isCameraEnabled();
|
||||
state = state.copyWith(isCameraEnabled: target);
|
||||
await _localParticipant!.setCameraEnabled(target);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleScreenShare() async {
|
||||
if (_localParticipant != null) {
|
||||
final target = !_localParticipant!.isScreenShareEnabled();
|
||||
state = state.copyWith(isScreenSharing: target);
|
||||
await _localParticipant!.setScreenShareEnabled(target);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> disconnect() async {
|
||||
if (_room != null) {
|
||||
await _room!.disconnect();
|
||||
state = state.copyWith(
|
||||
isConnected: false,
|
||||
isMicrophoneEnabled: false,
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_wsSubscription?.cancel();
|
||||
_roomListener?.dispose();
|
||||
_room?.removeListener(_onRoomChange);
|
||||
_room?.dispose();
|
||||
}
|
||||
}
|
302
lib/pods/call.freezed.dart
Normal file
302
lib/pods/call.freezed.dart
Normal file
@ -0,0 +1,302 @@
|
||||
// dart format width=80
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'call.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$CallState {
|
||||
|
||||
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; String? get error;
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>(this as CallState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,error);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $CallStateCopyWith<$Res> {
|
||||
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, String? error
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$CallStateCopyWithImpl<$Res>
|
||||
implements $CallStateCopyWith<$Res> {
|
||||
_$CallStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final CallState _self;
|
||||
final $Res Function(CallState) _then;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? error = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _CallState implements CallState {
|
||||
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, this.error});
|
||||
|
||||
|
||||
@override final bool isConnected;
|
||||
@override final bool isMicrophoneEnabled;
|
||||
@override final bool isCameraEnabled;
|
||||
@override final bool isScreenSharing;
|
||||
@override final String? error;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,error);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$CallStateCopyWith<$Res> implements $CallStateCopyWith<$Res> {
|
||||
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, String? error
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$CallStateCopyWithImpl<$Res>
|
||||
implements _$CallStateCopyWith<$Res> {
|
||||
__$CallStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _CallState _self;
|
||||
final $Res Function(_CallState) _then;
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? error = freezed,}) {
|
||||
return _then(_CallState(
|
||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCameraEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CallParticipantLive {
|
||||
|
||||
CallParticipant get participant; Participant get remoteParticipant;
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallParticipantLiveCopyWith<CallParticipantLive> get copyWith => _$CallParticipantLiveCopyWithImpl<CallParticipantLive>(this as CallParticipantLive, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallParticipantLive&&(identical(other.participant, participant) || other.participant == participant)&&(identical(other.remoteParticipant, remoteParticipant) || other.remoteParticipant == remoteParticipant));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $CallParticipantLiveCopyWith<$Res> {
|
||||
factory $CallParticipantLiveCopyWith(CallParticipantLive value, $Res Function(CallParticipantLive) _then) = _$CallParticipantLiveCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
CallParticipant participant, Participant remoteParticipant
|
||||
});
|
||||
|
||||
|
||||
$CallParticipantCopyWith<$Res> get participant;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$CallParticipantLiveCopyWithImpl<$Res>
|
||||
implements $CallParticipantLiveCopyWith<$Res> {
|
||||
_$CallParticipantLiveCopyWithImpl(this._self, this._then);
|
||||
|
||||
final CallParticipantLive _self;
|
||||
final $Res Function(CallParticipantLive) _then;
|
||||
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? participant = null,Object? remoteParticipant = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
participant: null == participant ? _self.participant : participant // ignore: cast_nullable_to_non_nullable
|
||||
as CallParticipant,remoteParticipant: null == remoteParticipant ? _self.remoteParticipant : remoteParticipant // ignore: cast_nullable_to_non_nullable
|
||||
as Participant,
|
||||
));
|
||||
}
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallParticipantCopyWith<$Res> get participant {
|
||||
|
||||
return $CallParticipantCopyWith<$Res>(_self.participant, (value) {
|
||||
return _then(_self.copyWith(participant: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _CallParticipantLive extends CallParticipantLive {
|
||||
const _CallParticipantLive({required this.participant, required this.remoteParticipant}): super._();
|
||||
|
||||
|
||||
@override final CallParticipant participant;
|
||||
@override final Participant remoteParticipant;
|
||||
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$CallParticipantLiveCopyWith<_CallParticipantLive> get copyWith => __$CallParticipantLiveCopyWithImpl<_CallParticipantLive>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallParticipantLive&&(identical(other.participant, participant) || other.participant == participant)&&(identical(other.remoteParticipant, remoteParticipant) || other.remoteParticipant == remoteParticipant));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,participant,remoteParticipant);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipantLive(participant: $participant, remoteParticipant: $remoteParticipant)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$CallParticipantLiveCopyWith<$Res> implements $CallParticipantLiveCopyWith<$Res> {
|
||||
factory _$CallParticipantLiveCopyWith(_CallParticipantLive value, $Res Function(_CallParticipantLive) _then) = __$CallParticipantLiveCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
CallParticipant participant, Participant remoteParticipant
|
||||
});
|
||||
|
||||
|
||||
@override $CallParticipantCopyWith<$Res> get participant;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$CallParticipantLiveCopyWithImpl<$Res>
|
||||
implements _$CallParticipantLiveCopyWith<$Res> {
|
||||
__$CallParticipantLiveCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _CallParticipantLive _self;
|
||||
final $Res Function(_CallParticipantLive) _then;
|
||||
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? participant = null,Object? remoteParticipant = null,}) {
|
||||
return _then(_CallParticipantLive(
|
||||
participant: null == participant ? _self.participant : participant // ignore: cast_nullable_to_non_nullable
|
||||
as CallParticipant,remoteParticipant: null == remoteParticipant ? _self.remoteParticipant : remoteParticipant // ignore: cast_nullable_to_non_nullable
|
||||
as Participant,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CallParticipantCopyWith<$Res> get participant {
|
||||
|
||||
return $CallParticipantCopyWith<$Res>(_self.participant, (value) {
|
||||
return _then(_self.copyWith(participant: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
27
lib/pods/call.g.dart
Normal file
27
lib/pods/call.g.dart
Normal file
@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'call.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$callNotifierHash() => r'5512070f943d98e999d97549c73e4d5f6e7b3ddd';
|
||||
|
||||
/// See also [CallNotifier].
|
||||
@ProviderFor(CallNotifier)
|
||||
final callNotifierProvider =
|
||||
AutoDisposeNotifierProvider<CallNotifier, CallState>.internal(
|
||||
CallNotifier.new,
|
||||
name: r'callNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$callNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$CallNotifier = AutoDisposeNotifier<CallState>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
@ -51,12 +51,9 @@ final serverUrlProvider = Provider<String>((ref) {
|
||||
});
|
||||
|
||||
@freezed
|
||||
abstract class AppSettings with _$AppSettings {
|
||||
sealed class AppSettings with _$AppSettings {
|
||||
const factory AppSettings({
|
||||
required bool realmCompactView,
|
||||
required bool mixedFeed,
|
||||
required bool autoTranslate,
|
||||
required bool hideBottomNav,
|
||||
required bool soundEffects,
|
||||
required bool aprilFoolFeatures,
|
||||
required bool enterToSend,
|
||||
@ -69,36 +66,18 @@ class AppSettingsNotifier extends StateNotifier<AppSettings> {
|
||||
AppSettingsNotifier(this.prefs)
|
||||
: super(
|
||||
AppSettings(
|
||||
realmCompactView: prefs.getBool(kAppRealmCompactView) ?? false,
|
||||
mixedFeed: prefs.getBool(kAppMixedFeed) ?? true,
|
||||
autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false,
|
||||
hideBottomNav: prefs.getBool(kAppHideBottomNav) ?? false,
|
||||
soundEffects: prefs.getBool(kAppSoundEffects) ?? true,
|
||||
aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true,
|
||||
enterToSend: prefs.getBool(kAppEnterToSend) ?? true,
|
||||
),
|
||||
);
|
||||
|
||||
void setRealmCompactView(bool value) {
|
||||
prefs.setBool(kAppRealmCompactView, value);
|
||||
state = state.copyWith(realmCompactView: value);
|
||||
}
|
||||
|
||||
void setMixedFeed(bool value) {
|
||||
prefs.setBool(kAppMixedFeed, value);
|
||||
state = state.copyWith(mixedFeed: value);
|
||||
}
|
||||
|
||||
void setAutoTranslate(bool value) {
|
||||
prefs.setBool(kAppAutoTranslate, value);
|
||||
state = state.copyWith(autoTranslate: value);
|
||||
}
|
||||
|
||||
void setHideBottomNav(bool value) {
|
||||
prefs.setBool(kAppHideBottomNav, value);
|
||||
state = state.copyWith(hideBottomNav: value);
|
||||
}
|
||||
|
||||
void setSoundEffects(bool value) {
|
||||
prefs.setBool(kAppSoundEffects, value);
|
||||
state = state.copyWith(soundEffects: value);
|
||||
|
@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$AppSettings {
|
||||
|
||||
bool get realmCompactView; bool get mixedFeed; bool get autoTranslate; bool get hideBottomNav; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend;
|
||||
bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend;
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -26,16 +26,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.realmCompactView, realmCompactView) || other.realmCompactView == realmCompactView)&&(identical(other.mixedFeed, mixedFeed) || other.mixedFeed == mixedFeed)&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.hideBottomNav, hideBottomNav) || other.hideBottomNav == hideBottomNav)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,realmCompactView,mixedFeed,autoTranslate,hideBottomNav,soundEffects,aprilFoolFeatures,enterToSend);
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(realmCompactView: $realmCompactView, mixedFeed: $mixedFeed, autoTranslate: $autoTranslate, hideBottomNav: $hideBottomNav, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)';
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)';
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool realmCompactView, bool mixedFeed, bool autoTranslate, bool hideBottomNav, bool soundEffects, bool aprilFoolFeatures, bool enterToSend
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend
|
||||
});
|
||||
|
||||
|
||||
@ -63,12 +63,9 @@ class _$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? realmCompactView = null,Object? mixedFeed = null,Object? autoTranslate = null,Object? hideBottomNav = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
realmCompactView: null == realmCompactView ? _self.realmCompactView : realmCompactView // ignore: cast_nullable_to_non_nullable
|
||||
as bool,mixedFeed: null == mixedFeed ? _self.mixedFeed : mixedFeed // ignore: cast_nullable_to_non_nullable
|
||||
as bool,autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,hideBottomNav: null == hideBottomNav ? _self.hideBottomNav : hideBottomNav // ignore: cast_nullable_to_non_nullable
|
||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
|
||||
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
|
||||
@ -83,13 +80,10 @@ as bool,
|
||||
|
||||
|
||||
class _AppSettings implements AppSettings {
|
||||
const _AppSettings({required this.realmCompactView, required this.mixedFeed, required this.autoTranslate, required this.hideBottomNav, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend});
|
||||
const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend});
|
||||
|
||||
|
||||
@override final bool realmCompactView;
|
||||
@override final bool mixedFeed;
|
||||
@override final bool autoTranslate;
|
||||
@override final bool hideBottomNav;
|
||||
@override final bool soundEffects;
|
||||
@override final bool aprilFoolFeatures;
|
||||
@override final bool enterToSend;
|
||||
@ -104,16 +98,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.realmCompactView, realmCompactView) || other.realmCompactView == realmCompactView)&&(identical(other.mixedFeed, mixedFeed) || other.mixedFeed == mixedFeed)&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.hideBottomNav, hideBottomNav) || other.hideBottomNav == hideBottomNav)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,realmCompactView,mixedFeed,autoTranslate,hideBottomNav,soundEffects,aprilFoolFeatures,enterToSend);
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(realmCompactView: $realmCompactView, mixedFeed: $mixedFeed, autoTranslate: $autoTranslate, hideBottomNav: $hideBottomNav, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)';
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)';
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +118,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool realmCompactView, bool mixedFeed, bool autoTranslate, bool hideBottomNav, bool soundEffects, bool aprilFoolFeatures, bool enterToSend
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend
|
||||
});
|
||||
|
||||
|
||||
@ -141,12 +135,9 @@ class __$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? realmCompactView = null,Object? mixedFeed = null,Object? autoTranslate = null,Object? hideBottomNav = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) {
|
||||
return _then(_AppSettings(
|
||||
realmCompactView: null == realmCompactView ? _self.realmCompactView : realmCompactView // ignore: cast_nullable_to_non_nullable
|
||||
as bool,mixedFeed: null == mixedFeed ? _self.mixedFeed : mixedFeed // ignore: cast_nullable_to_non_nullable
|
||||
as bool,autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,hideBottomNav: null == hideBottomNav ? _self.hideBottomNav : hideBottomNav // ignore: cast_nullable_to_non_nullable
|
||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
|
||||
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
|
||||
|
@ -14,7 +14,7 @@ part 'websocket.freezed.dart';
|
||||
part 'websocket.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class WebSocketState with _$WebSocketState {
|
||||
sealed class WebSocketState with _$WebSocketState {
|
||||
const factory WebSocketState.connected() = _Connected;
|
||||
const factory WebSocketState.connecting() = _Connecting;
|
||||
const factory WebSocketState.disconnected() = _Disconnected;
|
||||
@ -22,7 +22,7 @@ abstract class WebSocketState with _$WebSocketState {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class WebSocketPacket with _$WebSocketPacket {
|
||||
sealed class WebSocketPacket with _$WebSocketPacket {
|
||||
const factory WebSocketPacket({
|
||||
required String type,
|
||||
required Map<String, dynamic>? data,
|
||||
|
@ -8,15 +8,15 @@ class AppRouter extends RootStackRouter {
|
||||
|
||||
@override
|
||||
List<AutoRoute> get routes => [
|
||||
RedirectRoute(path: '/', redirectTo: '/explore'),
|
||||
AutoRoute(
|
||||
page: ExploreShellRoute.page,
|
||||
path: '/explore',
|
||||
path: '/',
|
||||
children: [
|
||||
AutoRoute(page: ExploreRoute.page, path: ''),
|
||||
AutoRoute(page: PostComposeRoute.page, path: 'posts/compose'),
|
||||
AutoRoute(page: PostDetailRoute.page, path: 'posts/:id'),
|
||||
AutoRoute(page: PostEditRoute.page, path: 'posts/:id/edit'),
|
||||
AutoRoute(page: PublisherProfileRoute.page, path: 'publishers/:name'),
|
||||
],
|
||||
),
|
||||
AutoRoute(
|
||||
@ -28,12 +28,11 @@ class AppRouter extends RootStackRouter {
|
||||
AutoRoute(page: WalletRoute.page, path: 'wallet'),
|
||||
AutoRoute(page: RelationshipRoute.page, path: 'relationships'),
|
||||
AutoRoute(page: AccountProfileRoute.page, path: ':name'),
|
||||
AutoRoute(page: PublisherProfileRoute.page, path: ':name/calendar'),
|
||||
AutoRoute(page: MyselfEventCalendarRoute.page, path: 'me/calendar'),
|
||||
AutoRoute(page: UpdateProfileRoute.page, path: 'me/update'),
|
||||
AutoRoute(page: AccountSettingsRoute.page, path: 'settings'),
|
||||
],
|
||||
),
|
||||
AutoRoute(page: EventCalanderRoute.page, path: '/account/:name/calendar'),
|
||||
AutoRoute(page: RealmListRoute.page, path: '/realms'),
|
||||
AutoRoute(
|
||||
page: ChatShellRoute.page,
|
||||
@ -41,6 +40,7 @@ class AppRouter extends RootStackRouter {
|
||||
children: [
|
||||
AutoRoute(page: ChatListRoute.page, path: ''),
|
||||
AutoRoute(page: ChatRoomRoute.page, path: ':id'),
|
||||
AutoRoute(page: CallRoute.page, path: ':id/call'),
|
||||
AutoRoute(page: NewChatRoute.page, path: 'new'),
|
||||
AutoRoute(page: EditChatRoute.page, path: ':id/edit'),
|
||||
AutoRoute(page: ChatDetailRoute.page, path: ':id/detail'),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,9 @@ import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activity.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/account/profile.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
@ -17,7 +19,7 @@ part 'event_calendar.g.dart';
|
||||
part 'event_calendar.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class EventCalendarQuery with _$EventCalendarQuery {
|
||||
sealed class EventCalendarQuery with _$EventCalendarQuery {
|
||||
const factory EventCalendarQuery({
|
||||
required String? uname,
|
||||
required int year,
|
||||
@ -39,8 +41,9 @@ Future<List<SnEventCalendarEntry>> accountEventCalendar(
|
||||
}
|
||||
|
||||
@RoutePage()
|
||||
class MyselfEventCalendarScreen extends HookConsumerWidget {
|
||||
const MyselfEventCalendarScreen({super.key});
|
||||
class EventCalanderScreen extends HookConsumerWidget {
|
||||
final String name;
|
||||
const EventCalanderScreen({super.key, @PathParam("name") required this.name});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -49,23 +52,18 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
|
||||
|
||||
final selectedDay = useState(DateTime.now());
|
||||
|
||||
final user = ref.watch(accountProvider(name));
|
||||
final events = ref.watch(
|
||||
accountEventCalendarProvider(
|
||||
EventCalendarQuery(
|
||||
uname: 'me',
|
||||
uname: name,
|
||||
year: selectedYear.value,
|
||||
month: selectedMonth.value,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
title: Text('eventCalander').tr(),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
final content = Column(
|
||||
children: [
|
||||
TableCalendar(
|
||||
locale: EasyLocalization.of(context)!.locale.toString(),
|
||||
@ -112,9 +110,7 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
|
||||
fontSize: 9,
|
||||
color:
|
||||
isSameDay(selectedDay.value, day)
|
||||
? Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimaryContainer
|
||||
? Theme.of(context).colorScheme.onPrimaryContainer
|
||||
: isSameDay(DateTime.now(), day)
|
||||
? Theme.of(
|
||||
context,
|
||||
@ -171,8 +167,7 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
|
||||
).padding(top: 4, right: 4),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(tip.title).bold(),
|
||||
Text(tip.content),
|
||||
@ -191,8 +186,46 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
if (name != 'me' && user.hasValue)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 1 / MediaQuery.of(context).devicePixelRatio,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
margin: EdgeInsets.all(16),
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
elevation: 0,
|
||||
color: Colors.transparent,
|
||||
child: ListTile(
|
||||
leading: ProfilePictureWidget(
|
||||
fileId: user.value!.profile.pictureId,
|
||||
),
|
||||
title: Text(user.value!.nick).bold(),
|
||||
subtitle: Text('@${user.value!.name}'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return AppScaffold(
|
||||
noBackground: false,
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
title: Text('eventCalander').tr(),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child:
|
||||
MediaQuery.of(context).size.width > 480
|
||||
? ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 480),
|
||||
child: Card(margin: EdgeInsets.all(16), child: content),
|
||||
).center()
|
||||
: content,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/user.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/widgets/account/badge.dart';
|
||||
import 'package:island/widgets/account/leveling_progress.dart';
|
||||
import 'package:island/widgets/account/status.dart';
|
||||
@ -17,6 +18,12 @@ part 'profile.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<SnAccount> account(Ref ref, String uname) async {
|
||||
if (uname == 'me') {
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
if (userInfo.hasValue && userInfo.value != null) {
|
||||
return userInfo.value!;
|
||||
}
|
||||
}
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/accounts/$uname");
|
||||
return SnAccount.fromJson(resp.data);
|
||||
|
@ -6,7 +6,7 @@ part of 'profile.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$accountHash() => r'39003ef3250181b9290e0562329c7801d4841941';
|
||||
String _$accountHash() => r'd2b0579617e6264452d98f47f695a9cdf45b24ec';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@ -96,8 +96,7 @@ class RelationshipListTile extends StatelessWidget {
|
||||
relationship.status == 0 && relationship.relatedId == currentUserId;
|
||||
final isWaiting =
|
||||
relationship.status == 0 && relationship.accountId == currentUserId;
|
||||
final isEstablished =
|
||||
relationship.status >= 100 || relationship.status <= -100;
|
||||
final isEstablished = relationship.status == 1 || relationship.status == 2;
|
||||
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.only(left: 16, right: 12),
|
||||
|
@ -75,6 +75,7 @@ class CreateAccountScreen extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
noBackground: false,
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
title: Text('createAccount').tr(),
|
||||
|
@ -41,6 +41,7 @@ class LoginScreen extends HookConsumerWidget {
|
||||
final factors = useState<List<SnAuthFactor>>([]);
|
||||
final factorPicked = useState<SnAuthFactor?>(null);
|
||||
return AppScaffold(
|
||||
noBackground: false,
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
title: Text('login').tr(),
|
||||
|
381
lib/screens/chat/call.dart
Normal file
381
lib/screens/chat/call.dart
Normal file
@ -0,0 +1,381 @@
|
||||
import 'package:auto_route/annotations.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/call.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/screens/chat/chat.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/chat/call_button.dart';
|
||||
import 'package:island/widgets/chat/call_participant_tile.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@RoutePage()
|
||||
class CallScreen extends HookConsumerWidget {
|
||||
final String roomId;
|
||||
const CallScreen({super.key, @PathParam('id') required this.roomId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final ongoingCall = ref.watch(ongoingCallProvider(roomId));
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
final chatRoom = ref.watch(chatroomProvider(roomId));
|
||||
final callState = ref.watch(callNotifierProvider);
|
||||
final callNotifier = ref.read(callNotifierProvider.notifier);
|
||||
|
||||
useEffect(() {
|
||||
callNotifier.joinRoom(roomId);
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
final actionButtonStyle = ButtonStyle(
|
||||
minimumSize: const MaterialStatePropertyAll(Size(24, 24)),
|
||||
);
|
||||
|
||||
final viewMode = useState<String>('grid');
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(
|
||||
leading: PageBackButton(
|
||||
onWillPop: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: const Text(
|
||||
'Do you want to leave the call or leave it in background?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('In Background'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await callNotifier.disconnect();
|
||||
callNotifier.dispose();
|
||||
},
|
||||
child: const Text('Leave'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
chatRoom.whenOrNull()?.name ?? 'loading'.tr(),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
callState.isConnected
|
||||
? Duration(
|
||||
milliseconds:
|
||||
(DateTime.now().millisecondsSinceEpoch -
|
||||
(ongoingCall
|
||||
.value
|
||||
?.createdAt
|
||||
.millisecondsSinceEpoch ??
|
||||
0)),
|
||||
).toString()
|
||||
: 'Connecting',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.grid_view),
|
||||
tooltip: 'Grid View',
|
||||
onPressed: () => viewMode.value = 'grid',
|
||||
color:
|
||||
viewMode.value == 'grid'
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.view_agenda),
|
||||
tooltip: 'Stage View',
|
||||
onPressed: () => viewMode.value = 'stage',
|
||||
color:
|
||||
viewMode.value == 'stage'
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
const Gap(8),
|
||||
],
|
||||
),
|
||||
body:
|
||||
callState.error != null
|
||||
? Center(
|
||||
child: Text(
|
||||
callState.error!,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
Card(
|
||||
margin: const EdgeInsets.only(left: 12, right: 12, top: 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Builder(
|
||||
builder: (context) {
|
||||
if (callNotifier.localParticipant == null) {
|
||||
return CircularProgressIndicator().center();
|
||||
}
|
||||
return SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child:
|
||||
SpeakingRippleAvatar(
|
||||
isSpeaking:
|
||||
callNotifier
|
||||
.localParticipant!
|
||||
.isSpeaking,
|
||||
audioLevel:
|
||||
callNotifier
|
||||
.localParticipant!
|
||||
.audioLevel,
|
||||
pictureId:
|
||||
userInfo.value?.profile.pictureId,
|
||||
size: 36,
|
||||
).center(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
callState.isMicrophoneEnabled
|
||||
? Icons.mic
|
||||
: Icons.mic_off,
|
||||
),
|
||||
onPressed: () {
|
||||
callNotifier.toggleMicrophone();
|
||||
},
|
||||
style: actionButtonStyle,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
callState.isCameraEnabled
|
||||
? Icons.videocam
|
||||
: Icons.videocam_off,
|
||||
),
|
||||
onPressed: () {
|
||||
callNotifier.toggleCamera();
|
||||
},
|
||||
style: actionButtonStyle,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
callState.isScreenSharing
|
||||
? Icons.stop_screen_share
|
||||
: Icons.screen_share,
|
||||
),
|
||||
onPressed: () {
|
||||
callNotifier.toggleScreenShare();
|
||||
},
|
||||
style: actionButtonStyle,
|
||||
),
|
||||
],
|
||||
).padding(all: 16),
|
||||
),
|
||||
Expanded(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if (!callState.isConnected) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
if (callNotifier.participants.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No participants in call'),
|
||||
);
|
||||
}
|
||||
final participants = callNotifier.participants;
|
||||
final allAudioOnly = participants.every(
|
||||
(p) =>
|
||||
!(p.hasVideo &&
|
||||
p.remoteParticipant.trackPublications.values
|
||||
.any(
|
||||
(pub) =>
|
||||
pub.track != null &&
|
||||
pub.kind == TrackType.VIDEO,
|
||||
)),
|
||||
);
|
||||
if (allAudioOnly) {
|
||||
// Audio-only: show avatars in a compact row
|
||||
return Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
for (final live in participants)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
),
|
||||
child: SpeakingRippleAvatar(
|
||||
isSpeaking: live.isSpeaking,
|
||||
audioLevel:
|
||||
live.remoteParticipant.audioLevel,
|
||||
pictureId:
|
||||
live
|
||||
.participant
|
||||
.profile
|
||||
?.account
|
||||
.profile
|
||||
.pictureId,
|
||||
size: 72,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (viewMode.value == 'stage') {
|
||||
// Stage view: show main speaker(s) large, others in row
|
||||
final mainSpeakers =
|
||||
participants
|
||||
.where(
|
||||
(p) => p
|
||||
.remoteParticipant
|
||||
.trackPublications
|
||||
.values
|
||||
.any(
|
||||
(pub) =>
|
||||
pub.track != null &&
|
||||
pub.kind == TrackType.VIDEO,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
if (mainSpeakers.isEmpty && participants.isNotEmpty) {
|
||||
mainSpeakers.add(participants.first);
|
||||
}
|
||||
final others =
|
||||
participants
|
||||
.where((p) => !mainSpeakers.contains(p))
|
||||
.toList();
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
for (final speaker in mainSpeakers)
|
||||
Expanded(
|
||||
child:
|
||||
AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.circular(8),
|
||||
child: Column(
|
||||
children: [
|
||||
CallParticipantTile(
|
||||
live: speaker,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
).center(),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 12),
|
||||
),
|
||||
if (others.isNotEmpty)
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
for (final other in others)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
),
|
||||
child: CallParticipantTile(
|
||||
live: other,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
// Default: grid view
|
||||
return GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount:
|
||||
isWidestScreen(context)
|
||||
? 4
|
||||
: isWiderScreen(context)
|
||||
? 3
|
||||
: 2,
|
||||
childAspectRatio: 16 / 9,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
),
|
||||
itemCount: participants.length,
|
||||
itemBuilder: (context, idx) {
|
||||
final live = participants[idx];
|
||||
return AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Column(
|
||||
children: [CallParticipantTile(live: live)],
|
||||
),
|
||||
),
|
||||
),
|
||||
).center();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -241,9 +241,33 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
bottom: TabBar(
|
||||
controller: tabController,
|
||||
tabs: [
|
||||
Tab(text: 'chatTabAll'.tr()),
|
||||
Tab(text: 'chatTabDirect'.tr()),
|
||||
Tab(text: 'chatTabGroup'.tr()),
|
||||
Tab(
|
||||
child: Text(
|
||||
'chatTabAll'.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Text(
|
||||
'chatTabDirect'.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Text(
|
||||
'chatTabGroup'.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@ -310,7 +334,19 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
},
|
||||
child: const Icon(Symbols.add),
|
||||
),
|
||||
body: chats.when(
|
||||
body: Column(
|
||||
children: [
|
||||
Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final summaryState = ref.watch(chatSummaryProvider);
|
||||
return summaryState.maybeWhen(
|
||||
loading: () => const LinearProgressIndicator(),
|
||||
orElse: () => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: chats.when(
|
||||
data:
|
||||
(items) => RefreshIndicator(
|
||||
onRefresh:
|
||||
@ -324,7 +360,8 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
.where(
|
||||
(item) =>
|
||||
selectedTab.value == 0 ||
|
||||
(selectedTab.value == 1 && item.type == 1) ||
|
||||
(selectedTab.value == 1 &&
|
||||
item.type == 1) ||
|
||||
(selectedTab.value == 2 && item.type != 1),
|
||||
)
|
||||
.length,
|
||||
@ -334,8 +371,10 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
.where(
|
||||
(item) =>
|
||||
selectedTab.value == 0 ||
|
||||
(selectedTab.value == 1 && item.type == 1) ||
|
||||
(selectedTab.value == 2 && item.type != 1),
|
||||
(selectedTab.value == 1 &&
|
||||
item.type == 1) ||
|
||||
(selectedTab.value == 2 &&
|
||||
item.type != 1),
|
||||
)
|
||||
.toList();
|
||||
final item = filteredItems[index];
|
||||
@ -343,8 +382,11 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
room: item,
|
||||
isDirect: item.type == 1,
|
||||
onTap: () {
|
||||
if (context.router.topRoute.name == ChatRoomRoute.name) {
|
||||
context.router.replace(ChatRoomRoute(id: item.id));
|
||||
if (context.router.topRoute.name ==
|
||||
ChatRoomRoute.name) {
|
||||
context.router.replace(
|
||||
ChatRoomRoute(id: item.id),
|
||||
);
|
||||
} else {
|
||||
context.router.push(ChatRoomRoute(id: item.id));
|
||||
}
|
||||
@ -362,6 +404,9 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:super_clipboard/super_clipboard.dart';
|
||||
import 'chat.dart';
|
||||
import 'package:island/widgets/chat/call_button.dart';
|
||||
|
||||
part 'room.g.dart';
|
||||
|
||||
@ -514,12 +515,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.video_call),
|
||||
onPressed: () {
|
||||
showInfoAlert('Oops', 'Not implemented yet...');
|
||||
},
|
||||
),
|
||||
AudioCallButton(roomId: id),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onPressed: () {
|
||||
|
@ -229,7 +229,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ChatRoomMemberState with _$ChatRoomMemberState {
|
||||
sealed class ChatRoomMemberState with _$ChatRoomMemberState {
|
||||
const factory ChatRoomMemberState({
|
||||
required List<SnChatMember> members,
|
||||
required bool isLoading,
|
||||
|
@ -310,7 +310,7 @@ class _StickerPackActionMenu extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class StickerWithPackQuery with _$StickerWithPackQuery {
|
||||
sealed class StickerWithPackQuery with _$StickerWithPackQuery {
|
||||
const factory StickerWithPackQuery({
|
||||
required String packId,
|
||||
required String id,
|
||||
|
@ -64,7 +64,12 @@ class PostDetailScreen extends HookConsumerWidget {
|
||||
child: Material(
|
||||
elevation: 2,
|
||||
color: Colors.transparent,
|
||||
child: PostQuickReply(parent: post).padding(
|
||||
child: PostQuickReply(
|
||||
parent: post,
|
||||
onPosted: () {
|
||||
ref.invalidate(postRepliesNotifierProvider(id));
|
||||
},
|
||||
).padding(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||
top: 16,
|
||||
horizontal: 16,
|
||||
|
@ -176,32 +176,6 @@ class SettingsScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsRealmCompactView').tr(),
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||
leading: const Icon(Symbols.view_compact),
|
||||
trailing: Switch(
|
||||
value: settings.realmCompactView,
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(appSettingsProvider.notifier)
|
||||
.setRealmCompactView(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsMixedFeed').tr(),
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||
leading: const Icon(Symbols.merge),
|
||||
trailing: Switch(
|
||||
value: settings.mixedFeed,
|
||||
onChanged: (value) {
|
||||
ref.read(appSettingsProvider.notifier).setMixedFeed(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsAutoTranslate').tr(),
|
||||
@ -216,20 +190,6 @@ class SettingsScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsHideBottomNav').tr(),
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||
leading: const Icon(Symbols.navigation),
|
||||
trailing: Switch(
|
||||
value: settings.hideBottomNav,
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(appSettingsProvider.notifier)
|
||||
.setHideBottomNav(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsSoundEffects').tr(),
|
||||
|
@ -16,7 +16,7 @@ const List<Tour> kAllTours = [
|
||||
];
|
||||
|
||||
@freezed
|
||||
abstract class Tour with _$Tour {
|
||||
sealed class Tour with _$Tour {
|
||||
const Tour._();
|
||||
|
||||
const factory Tour({required String id, required bool isStartup}) = _Tour;
|
||||
|
@ -13,6 +13,8 @@ import 'package:island/services/responsive.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/widgets/chat/call_overlay.dart';
|
||||
import 'package:island/pods/call.dart';
|
||||
|
||||
class WindowScaffold extends HookConsumerWidget {
|
||||
final Widget child;
|
||||
@ -150,12 +152,22 @@ class AppScaffold extends StatelessWidget {
|
||||
noBackground
|
||||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
body: SizedBox.expand(
|
||||
body: Stack(
|
||||
children: [
|
||||
SizedBox.expand(
|
||||
child:
|
||||
noBackground
|
||||
? content
|
||||
: AppBackground(isRoot: true, child: content),
|
||||
),
|
||||
Positioned(
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 8,
|
||||
child: const _GlobalCallOverlay(),
|
||||
),
|
||||
],
|
||||
),
|
||||
appBar: appBar,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
bottomSheet: bottomSheet,
|
||||
@ -172,12 +184,14 @@ class AppScaffold extends StatelessWidget {
|
||||
|
||||
class PageBackButton extends StatelessWidget {
|
||||
final List<Shadow>? shadows;
|
||||
const PageBackButton({super.key, this.shadows});
|
||||
final VoidCallback? onWillPop;
|
||||
const PageBackButton({super.key, this.shadows, this.onWillPop});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
onWillPop?.call();
|
||||
context.router.maybePop();
|
||||
},
|
||||
icon: Icon(
|
||||
@ -192,6 +206,23 @@ class PageBackButton extends StatelessWidget {
|
||||
|
||||
const kAppBackgroundImagePath = 'island_app_background';
|
||||
|
||||
/// Global call overlay bar (appears when in a call but not on the call screen)
|
||||
class _GlobalCallOverlay extends HookConsumerWidget {
|
||||
const _GlobalCallOverlay();
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final callState = ref.watch(callNotifierProvider);
|
||||
// Find current route name
|
||||
final modalRoute = ModalRoute.of(context);
|
||||
final isOnCallScreen = modalRoute?.settings.name?.contains('call') ?? false;
|
||||
// You may want to store roomId in callState for more robust navigation
|
||||
if (callState.isConnected && !isOnCallScreen) {
|
||||
return CallOverlayBar();
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
final backgroundImageFileProvider = FutureProvider<File?>((ref) async {
|
||||
if (kIsWeb) return null;
|
||||
final dir = await getApplicationSupportDirectory();
|
||||
|
112
lib/widgets/chat/call_button.dart
Normal file
112
lib/widgets/chat/call_button.dart
Normal file
@ -0,0 +1,112 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/chat.dart';
|
||||
import 'package:island/pods/call.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'call_button.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<SnRealtimeCall?> ongoingCall(Ref ref, String roomId) async {
|
||||
try {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get('/chat/realtime/$roomId');
|
||||
return SnRealtimeCall.fromJson(resp.data);
|
||||
} catch (e) {
|
||||
if (e is DioException && e.response?.statusCode == 404) {
|
||||
return null;
|
||||
}
|
||||
showErrorAlert(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class AudioCallButton extends HookConsumerWidget {
|
||||
final String roomId;
|
||||
const AudioCallButton({super.key, required this.roomId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final ongoingCall = ref.watch(ongoingCallProvider(roomId));
|
||||
final callState = ref.watch(callNotifierProvider);
|
||||
final callNotifier = ref.read(callNotifierProvider.notifier);
|
||||
final isLoading = useState(false);
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
|
||||
Future<void> handleJoin() async {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
await apiClient.post('/chat/realtime/$roomId');
|
||||
if (context.mounted) {
|
||||
context.router.push(CallRoute(roomId: roomId));
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorAlert(e);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleEnd() async {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
await apiClient.delete('/chat/realtime/$roomId');
|
||||
callNotifier.dispose(); // Clean up call resources
|
||||
} catch (e) {
|
||||
showErrorAlert(e);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoading.value) {
|
||||
return IconButton(
|
||||
icon: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
padding: EdgeInsets.all(4),
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
);
|
||||
}
|
||||
|
||||
if (callState.isConnected) {
|
||||
// Show end call button if in call
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.call_end),
|
||||
tooltip: 'End Call',
|
||||
onPressed: handleEnd,
|
||||
);
|
||||
}
|
||||
|
||||
if (ongoingCall.value != null) {
|
||||
// There is an ongoing call, offer to join it directly
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.call),
|
||||
tooltip: 'Join Ongoing Call',
|
||||
onPressed: () {
|
||||
if (context.mounted) {
|
||||
context.router.push(CallRoute(roomId: roomId));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Show join/start call button
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.call),
|
||||
tooltip: 'Start/Join Call',
|
||||
onPressed: handleJoin,
|
||||
);
|
||||
}
|
||||
}
|
151
lib/widgets/chat/call_button.g.dart
Normal file
151
lib/widgets/chat/call_button.g.dart
Normal file
@ -0,0 +1,151 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'call_button.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$ongoingCallHash() => r'd8a942e6695a7da702daeaa452464c16761ef6e7';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [ongoingCall].
|
||||
@ProviderFor(ongoingCall)
|
||||
const ongoingCallProvider = OngoingCallFamily();
|
||||
|
||||
/// See also [ongoingCall].
|
||||
class OngoingCallFamily extends Family<AsyncValue<SnRealtimeCall?>> {
|
||||
/// See also [ongoingCall].
|
||||
const OngoingCallFamily();
|
||||
|
||||
/// See also [ongoingCall].
|
||||
OngoingCallProvider call(String roomId) {
|
||||
return OngoingCallProvider(roomId);
|
||||
}
|
||||
|
||||
@override
|
||||
OngoingCallProvider getProviderOverride(
|
||||
covariant OngoingCallProvider provider,
|
||||
) {
|
||||
return call(provider.roomId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'ongoingCallProvider';
|
||||
}
|
||||
|
||||
/// See also [ongoingCall].
|
||||
class OngoingCallProvider extends AutoDisposeFutureProvider<SnRealtimeCall?> {
|
||||
/// See also [ongoingCall].
|
||||
OngoingCallProvider(String roomId)
|
||||
: this._internal(
|
||||
(ref) => ongoingCall(ref as OngoingCallRef, roomId),
|
||||
from: ongoingCallProvider,
|
||||
name: r'ongoingCallProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$ongoingCallHash,
|
||||
dependencies: OngoingCallFamily._dependencies,
|
||||
allTransitiveDependencies: OngoingCallFamily._allTransitiveDependencies,
|
||||
roomId: roomId,
|
||||
);
|
||||
|
||||
OngoingCallProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.roomId,
|
||||
}) : super.internal();
|
||||
|
||||
final String roomId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<SnRealtimeCall?> Function(OngoingCallRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: OngoingCallProvider._internal(
|
||||
(ref) => create(ref as OngoingCallRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
roomId: roomId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<SnRealtimeCall?> createElement() {
|
||||
return _OngoingCallProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is OngoingCallProvider && other.roomId == roomId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, roomId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin OngoingCallRef on AutoDisposeFutureProviderRef<SnRealtimeCall?> {
|
||||
/// The parameter `roomId` of this provider.
|
||||
String get roomId;
|
||||
}
|
||||
|
||||
class _OngoingCallProviderElement
|
||||
extends AutoDisposeFutureProviderElement<SnRealtimeCall?>
|
||||
with OngoingCallRef {
|
||||
_OngoingCallProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get roomId => (origin as OngoingCallProvider).roomId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
62
lib/widgets/chat/call_overlay.dart
Normal file
62
lib/widgets/chat/call_overlay.dart
Normal file
@ -0,0 +1,62 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/call.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
|
||||
/// A floating bar that appears when user is in a call but not on the call screen.
|
||||
class CallOverlayBar extends HookConsumerWidget {
|
||||
const CallOverlayBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final callState = ref.watch(callNotifierProvider);
|
||||
final callNotifier = ref.read(callNotifierProvider.notifier);
|
||||
// Only show if connected and not on the call screen
|
||||
if (!callState.isConnected) return const SizedBox.shrink();
|
||||
|
||||
return Positioned(
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 32,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (callNotifier.roomId == null) return;
|
||||
context.router.push(CallRoute(roomId: callNotifier.roomId!));
|
||||
},
|
||||
child: Material(
|
||||
elevation: 8,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.call, color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
const Text(
|
||||
'In call',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: Colors.white,
|
||||
size: 18,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
114
lib/widgets/chat/call_participant_tile.dart
Normal file
114
lib/widgets/chat/call_participant_tile.dart
Normal file
@ -0,0 +1,114 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:island/pods/call.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
|
||||
class SpeakingRippleAvatar extends StatelessWidget {
|
||||
final bool isSpeaking;
|
||||
final double audioLevel;
|
||||
final String? pictureId;
|
||||
final double size;
|
||||
|
||||
const SpeakingRippleAvatar({
|
||||
super.key,
|
||||
required this.isSpeaking,
|
||||
required this.audioLevel,
|
||||
required this.pictureId,
|
||||
this.size = 96,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final avatarRadius = size / 2;
|
||||
final clampedLevel = audioLevel.clamp(0.0, 1.0);
|
||||
final rippleRadius = avatarRadius + clampedLevel * (size * 0.333);
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(
|
||||
begin: avatarRadius,
|
||||
end: isSpeaking ? rippleRadius : avatarRadius,
|
||||
),
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOut,
|
||||
builder: (context, animatedRadius, child) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
if (isSpeaking)
|
||||
Container(
|
||||
width: animatedRadius * 2,
|
||||
height: animatedRadius * 2,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.green.withOpacity(0.75 + 0.25 * clampedLevel),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: size,
|
||||
height: size,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(shape: BoxShape.circle),
|
||||
child: ProfilePictureWidget(fileId: pictureId, radius: size / 2),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CallParticipantTile extends StatelessWidget {
|
||||
final CallParticipantLive live;
|
||||
|
||||
const CallParticipantTile({super.key, required this.live});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hasVideo =
|
||||
live.hasVideo &&
|
||||
live.remoteParticipant.trackPublications.values
|
||||
.where((pub) => pub.track != null && pub.kind == TrackType.VIDEO)
|
||||
.isNotEmpty;
|
||||
final audioLevel = live.remoteParticipant.audioLevel;
|
||||
|
||||
if (hasVideo) {
|
||||
return Stack(
|
||||
fit: StackFit.loose,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: VideoTrackRenderer(
|
||||
live.remoteParticipant.trackPublications.values
|
||||
.where((track) => track.kind == TrackType.VIDEO)
|
||||
.first
|
||||
.track
|
||||
as VideoTrack,
|
||||
renderMode: VideoRenderMode.platformView,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 8,
|
||||
right: 8,
|
||||
bottom: 8,
|
||||
child: Text(
|
||||
live.participant.profile?.account.nick ??
|
||||
'${'unknown'.tr()}\'s video',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return SpeakingRippleAvatar(
|
||||
isSpeaking: live.isSpeaking,
|
||||
audioLevel: audioLevel,
|
||||
pictureId: live.participant.profile?.account.profile.pictureId,
|
||||
size: 84,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -46,10 +46,6 @@ class MessageItem extends HookConsumerWidget {
|
||||
isCurrentUser
|
||||
? Theme.of(context).colorScheme.primaryContainer.withOpacity(0.5)
|
||||
: Theme.of(context).colorScheme.surfaceContainer;
|
||||
final linkColor = Color.alphaBlend(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
containerColor,
|
||||
);
|
||||
|
||||
final hasBackground =
|
||||
ref.watch(backgroundImageFileProvider).valueOrNull != null;
|
||||
@ -196,16 +192,8 @@ class MessageItem extends HookConsumerWidget {
|
||||
textColor: textColor,
|
||||
isReply: false,
|
||||
).padding(vertical: 4),
|
||||
if (remoteMessage.content?.isNotEmpty ?? false)
|
||||
MarkdownTextContent(
|
||||
content: remoteMessage.content!,
|
||||
isSelectable: true,
|
||||
linkStyle: TextStyle(color: linkColor),
|
||||
textStyle: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
if (_MessageItemContent.hasContent(remoteMessage))
|
||||
_MessageItemContent(item: remoteMessage),
|
||||
if (remoteMessage.attachments.isNotEmpty)
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
@ -360,7 +348,10 @@ class MessageQuoteWidget extends HookConsumerWidget {
|
||||
: message.toRemoteMessage().forwardedMessageId!,
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final remoteMessage =
|
||||
snapshot.hasData ? snapshot.data!.toRemoteMessage() : null;
|
||||
|
||||
if (remoteMessage != null) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
child: Container(
|
||||
@ -378,7 +369,7 @@ class MessageQuoteWidget extends HookConsumerWidget {
|
||||
children: [
|
||||
Icon(Symbols.reply, size: 16, color: textColor),
|
||||
Text(
|
||||
'Replying to ${snapshot.data!.toRemoteMessage().sender.account.nick}',
|
||||
'Replying to ${remoteMessage.sender.account.nick}',
|
||||
).textColor(textColor).bold(),
|
||||
],
|
||||
).padding(right: 8)
|
||||
@ -389,16 +380,12 @@ class MessageQuoteWidget extends HookConsumerWidget {
|
||||
children: [
|
||||
Icon(Symbols.forward, size: 16, color: textColor),
|
||||
Text(
|
||||
'Forwarded from ${snapshot.data!.toRemoteMessage().sender.account.nick}',
|
||||
'Forwarded from ${remoteMessage.sender.account.nick}',
|
||||
).textColor(textColor).bold(),
|
||||
],
|
||||
).padding(right: 8),
|
||||
if (snapshot.data!.toRemoteMessage().content?.isNotEmpty ??
|
||||
false)
|
||||
Text(
|
||||
snapshot.data!.toRemoteMessage().content!,
|
||||
style: TextStyle(color: textColor),
|
||||
),
|
||||
if (_MessageItemContent.hasContent(remoteMessage))
|
||||
_MessageItemContent(item: remoteMessage),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -410,3 +397,62 @@ class MessageQuoteWidget extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MessageItemContent extends StatelessWidget {
|
||||
final SnChatMessage item;
|
||||
const _MessageItemContent({required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (item.type) {
|
||||
case 'call.start':
|
||||
case 'call.ended':
|
||||
return _MessageContentCall(
|
||||
isEnded: item.type == 'call.ended',
|
||||
duration: item.meta['duration']?.toDouble(),
|
||||
);
|
||||
case 'text':
|
||||
default:
|
||||
return MarkdownTextContent(content: item.content!);
|
||||
}
|
||||
}
|
||||
|
||||
static bool hasContent(SnChatMessage item) {
|
||||
return item.type != 'text' || (item.content?.isNotEmpty ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
class _MessageContentCall extends StatelessWidget {
|
||||
final bool isEnded;
|
||||
final double? duration;
|
||||
const _MessageContentCall({required this.isEnded, this.duration});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String formatDuration(Duration duration) {
|
||||
final hours = duration.inHours;
|
||||
final minutes = duration.inMinutes.remainder(60);
|
||||
final seconds = duration.inSeconds.remainder(60);
|
||||
return '${hours == 0 ? '' : '$hours hours '}'
|
||||
'${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
isEnded ? Symbols.call_end : Symbols.phone_in_talk,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
Gap(4),
|
||||
Text(
|
||||
isEnded
|
||||
? 'Call ended after ${formatDuration(Duration(seconds: duration!.toInt()))}'
|
||||
: 'Call started',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -42,11 +42,16 @@ class CheckInWidget extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final todayResult = ref.watch(checkInResultTodayProvider);
|
||||
|
||||
Future<void> checkIn() async {
|
||||
Future<void> checkIn({String? captchatTk}) async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
try {
|
||||
await client.post('/accounts/me/check-in');
|
||||
await client.post(
|
||||
'/accounts/me/check-in',
|
||||
data: captchatTk == null ? null : jsonEncode(captchatTk),
|
||||
);
|
||||
ref.invalidate(checkInResultTodayProvider);
|
||||
final userNotifier = ref.read(userInfoProvider.notifier);
|
||||
userNotifier.fetchUser();
|
||||
} catch (err) {
|
||||
if (err is DioException) {
|
||||
if (err.response?.statusCode == 423 && context.mounted) {
|
||||
@ -54,14 +59,7 @@ class CheckInWidget extends HookConsumerWidget {
|
||||
context,
|
||||
).push(MaterialPageRoute(builder: (context) => CaptchaScreen()));
|
||||
if (captchaTk == null) return;
|
||||
await client.post(
|
||||
'/accounts/me/check-in',
|
||||
data: jsonEncode(captchaTk),
|
||||
);
|
||||
ref.invalidate(checkInResultTodayProvider);
|
||||
final userNotifier = ref.read(userInfoProvider.notifier);
|
||||
userNotifier.fetchUser();
|
||||
return;
|
||||
return await checkIn(captchatTk: captchaTk);
|
||||
}
|
||||
}
|
||||
showErrorAlert(err);
|
||||
@ -139,7 +137,7 @@ class CheckInWidget extends HookConsumerWidget {
|
||||
if (todayResult.valueOrNull == null) {
|
||||
checkIn();
|
||||
} else {
|
||||
context.router.push(MyselfEventCalendarRoute());
|
||||
context.router.push(EventCalanderRoute(name: 'me'));
|
||||
}
|
||||
},
|
||||
icon: AnimatedSwitcher(
|
||||
|
@ -14,12 +14,13 @@ class PostListNotifier extends _$PostListNotifier
|
||||
with CursorPagingNotifierMixin<SnPost> {
|
||||
static const int _pageSize = 20;
|
||||
|
||||
PostListNotifier({this.pubName});
|
||||
|
||||
final String? pubName;
|
||||
String? pubName;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPost>> build() => fetch(cursor: null);
|
||||
Future<CursorPagingData<SnPost>> build(String? pubName) {
|
||||
this.pubName = pubName;
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPost>> fetch({required String? cursor}) async {
|
||||
@ -55,9 +56,9 @@ class SliverPostList extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return PagingHelperSliverView(
|
||||
provider: postListNotifierProvider,
|
||||
futureRefreshable: postListNotifierProvider.future,
|
||||
notifierRefreshable: postListNotifierProvider.notifier,
|
||||
provider: postListNotifierProvider(pubName),
|
||||
futureRefreshable: postListNotifierProvider(pubName).future,
|
||||
notifierRefreshable: postListNotifierProvider(pubName).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
|
@ -6,24 +6,174 @@ part of 'post_list.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$postListNotifierHash() => r'88aab109f36c7489c336fea522bffafa10869253';
|
||||
String _$postListNotifierHash() => r'6568b7a5afad71551009d9bc7af26afb4b07c9e5';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$PostListNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPost>> {
|
||||
late final String? pubName;
|
||||
|
||||
FutureOr<CursorPagingData<SnPost>> build(String? pubName);
|
||||
}
|
||||
|
||||
/// See also [PostListNotifier].
|
||||
@ProviderFor(PostListNotifier)
|
||||
final postListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
||||
const postListNotifierProvider = PostListNotifierFamily();
|
||||
|
||||
/// See also [PostListNotifier].
|
||||
class PostListNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnPost>>> {
|
||||
/// See also [PostListNotifier].
|
||||
const PostListNotifierFamily();
|
||||
|
||||
/// See also [PostListNotifier].
|
||||
PostListNotifierProvider call(String? pubName) {
|
||||
return PostListNotifierProvider(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
PostListNotifierProvider getProviderOverride(
|
||||
covariant PostListNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.pubName);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'postListNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [PostListNotifier].
|
||||
class PostListNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
PostListNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
>.internal(
|
||||
PostListNotifier.new,
|
||||
> {
|
||||
/// See also [PostListNotifier].
|
||||
PostListNotifierProvider(String? pubName)
|
||||
: this._internal(
|
||||
() => PostListNotifier()..pubName = pubName,
|
||||
from: postListNotifierProvider,
|
||||
name: r'postListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$postListNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
dependencies: PostListNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PostListNotifierFamily._allTransitiveDependencies,
|
||||
pubName: pubName,
|
||||
);
|
||||
|
||||
typedef _$PostListNotifier = AutoDisposeAsyncNotifier<CursorPagingData<SnPost>>;
|
||||
PostListNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.pubName,
|
||||
}) : super.internal();
|
||||
|
||||
final String? pubName;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnPost>> runNotifierBuild(
|
||||
covariant PostListNotifier notifier,
|
||||
) {
|
||||
return notifier.build(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(PostListNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: PostListNotifierProvider._internal(
|
||||
() => create()..pubName = pubName,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
pubName: pubName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PostListNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
>
|
||||
createElement() {
|
||||
return _PostListNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PostListNotifierProvider && other.pubName == pubName;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, pubName.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin PostListNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnPost>> {
|
||||
/// The parameter `pubName` of this provider.
|
||||
String? get pubName;
|
||||
}
|
||||
|
||||
class _PostListNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PostListNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
>
|
||||
with PostListNotifierRef {
|
||||
_PostListNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get pubName => (origin as PostListNotifierProvider).pubName;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
@ -1,13 +1,59 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/content/paging_helper_ext.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||
|
||||
part 'post_replies.g.dart';
|
||||
|
||||
@riverpod
|
||||
class PostRepliesNotifier extends _$PostRepliesNotifier
|
||||
with CursorPagingNotifierMixin<SnPost> {
|
||||
static const int _pageSize = 20;
|
||||
|
||||
PostRepliesNotifier();
|
||||
|
||||
String? _postId;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPost>> build(String postId) {
|
||||
_postId = postId;
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPost>> fetch({required String? cursor}) async {
|
||||
if (_postId == null) {
|
||||
throw StateError('PostRepliesNotifier must be initialized with postId');
|
||||
}
|
||||
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final response = await client.get(
|
||||
'/posts/$_postId/replies',
|
||||
queryParameters: {'offset': offset, 'take': _pageSize},
|
||||
);
|
||||
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final posts = data.map((json) => SnPost.fromJson(json)).toList();
|
||||
|
||||
final hasMore = offset + posts.length < total;
|
||||
final nextCursor = hasMore ? (offset + posts.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: posts,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PostRepliesList extends HookConsumerWidget {
|
||||
final String postId;
|
||||
@ -15,25 +61,14 @@ class PostRepliesList extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final postAsync = ref.watch(postRepliesProvider(postId));
|
||||
final isWide = isWideScreen(context);
|
||||
|
||||
return postAsync.when(
|
||||
data:
|
||||
(controller) => SliverInfiniteList(
|
||||
itemCount: controller.posts.length,
|
||||
isLoading: controller.isLoading,
|
||||
hasReachedMax: controller.hasReachedMax,
|
||||
onFetchData: controller.fetchMore,
|
||||
itemBuilder: (context, index) {
|
||||
final post = controller.posts[index];
|
||||
return PostItem(
|
||||
item: post,
|
||||
backgroundColor: isWide ? Colors.transparent : null,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) => const Divider(height: 1),
|
||||
emptyBuilder: (context) {
|
||||
return PagingHelperSliverView(
|
||||
provider: postRepliesNotifierProvider(postId),
|
||||
futureRefreshable: postRepliesNotifierProvider(postId).future,
|
||||
notifierRefreshable: postRepliesNotifierProvider(postId).notifier,
|
||||
contentBuilder: (data, widgetCount, endItemView) {
|
||||
if (data.items.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
@ -41,70 +76,31 @@ class PostRepliesList extends HookConsumerWidget {
|
||||
'No replies',
|
||||
textAlign: TextAlign.center,
|
||||
).fontSize(18).bold(),
|
||||
Text('Why not start a discussion?'),
|
||||
const Text('Why not start a discussion?'),
|
||||
],
|
||||
).padding(vertical: 16),
|
||||
);
|
||||
}
|
||||
|
||||
return SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
PostItem(
|
||||
item: data.items[index],
|
||||
backgroundColor: isWide ? Colors.transparent : null,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
loading:
|
||||
() => SliverFillRemaining(
|
||||
child: const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
error:
|
||||
(e, _) => SliverFillRemaining(
|
||||
child: ResponseErrorWidget(
|
||||
error: e,
|
||||
onRetry: () {
|
||||
ref.invalidate(postRepliesProvider(postId));
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final postRepliesProvider =
|
||||
FutureProviderFamily<_PostRepliesController, String>((ref, postId) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final controller = _PostRepliesController(client, postId);
|
||||
await controller.fetchMore();
|
||||
return controller;
|
||||
});
|
||||
|
||||
class _PostRepliesController {
|
||||
_PostRepliesController(this._dio, this.parentId);
|
||||
|
||||
final Dio _dio;
|
||||
final String parentId;
|
||||
final List<SnPost> posts = [];
|
||||
bool isLoading = false;
|
||||
bool hasReachedMax = false;
|
||||
int offset = 0;
|
||||
final int take = 20;
|
||||
int total = 0;
|
||||
|
||||
Future<void> fetchMore() async {
|
||||
if (isLoading || hasReachedMax) return;
|
||||
isLoading = true;
|
||||
|
||||
final response = await _dio.get(
|
||||
'/posts/$parentId/replies',
|
||||
queryParameters: {'offset': offset, 'take': take},
|
||||
);
|
||||
|
||||
final List<SnPost> fetched =
|
||||
(response.data as List)
|
||||
.map((e) => SnPost.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
final headerTotal = int.tryParse(response.headers['x-total']?.first ?? '');
|
||||
if (headerTotal != null) total = headerTotal;
|
||||
|
||||
posts.addAll(fetched);
|
||||
offset += fetched.length;
|
||||
if (posts.length >= total) hasReachedMax = true;
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
180
lib/widgets/post/post_replies.g.dart
Normal file
180
lib/widgets/post/post_replies.g.dart
Normal file
@ -0,0 +1,180 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'post_replies.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$postRepliesNotifierHash() =>
|
||||
r'49c178102ec0a4136974a0e9a8f090f511abd542';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$PostRepliesNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPost>> {
|
||||
late final String postId;
|
||||
|
||||
FutureOr<CursorPagingData<SnPost>> build(String postId);
|
||||
}
|
||||
|
||||
/// See also [PostRepliesNotifier].
|
||||
@ProviderFor(PostRepliesNotifier)
|
||||
const postRepliesNotifierProvider = PostRepliesNotifierFamily();
|
||||
|
||||
/// See also [PostRepliesNotifier].
|
||||
class PostRepliesNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnPost>>> {
|
||||
/// See also [PostRepliesNotifier].
|
||||
const PostRepliesNotifierFamily();
|
||||
|
||||
/// See also [PostRepliesNotifier].
|
||||
PostRepliesNotifierProvider call(String postId) {
|
||||
return PostRepliesNotifierProvider(postId);
|
||||
}
|
||||
|
||||
@override
|
||||
PostRepliesNotifierProvider getProviderOverride(
|
||||
covariant PostRepliesNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.postId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'postRepliesNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [PostRepliesNotifier].
|
||||
class PostRepliesNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
PostRepliesNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
> {
|
||||
/// See also [PostRepliesNotifier].
|
||||
PostRepliesNotifierProvider(String postId)
|
||||
: this._internal(
|
||||
() => PostRepliesNotifier()..postId = postId,
|
||||
from: postRepliesNotifierProvider,
|
||||
name: r'postRepliesNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$postRepliesNotifierHash,
|
||||
dependencies: PostRepliesNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PostRepliesNotifierFamily._allTransitiveDependencies,
|
||||
postId: postId,
|
||||
);
|
||||
|
||||
PostRepliesNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.postId,
|
||||
}) : super.internal();
|
||||
|
||||
final String postId;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnPost>> runNotifierBuild(
|
||||
covariant PostRepliesNotifier notifier,
|
||||
) {
|
||||
return notifier.build(postId);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(PostRepliesNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: PostRepliesNotifierProvider._internal(
|
||||
() => create()..postId = postId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
postId: postId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PostRepliesNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
>
|
||||
createElement() {
|
||||
return _PostRepliesNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PostRepliesNotifierProvider && other.postId == postId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, postId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin PostRepliesNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnPost>> {
|
||||
/// The parameter `postId` of this provider.
|
||||
String get postId;
|
||||
}
|
||||
|
||||
class _PostRepliesNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PostRepliesNotifier,
|
||||
CursorPagingData<SnPost>
|
||||
>
|
||||
with PostRepliesNotifierRef {
|
||||
_PostRepliesNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get postId => (origin as PostRepliesNotifierProvider).postId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
@ -10,12 +10,14 @@
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_platform_alert/flutter_platform_alert_plugin.h>
|
||||
#include <flutter_udid/flutter_udid_plugin.h>
|
||||
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
|
||||
#include <irondash_engine_context/irondash_engine_context_plugin.h>
|
||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
||||
#include <media_kit_video/media_kit_video_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <super_native_extensions/super_native_extensions_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <volume_controller/volume_controller_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
||||
@ -30,6 +32,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_udid_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterUdidPlugin");
|
||||
flutter_udid_plugin_register_with_registrar(flutter_udid_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin");
|
||||
flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar);
|
||||
g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin");
|
||||
irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar);
|
||||
@ -48,4 +53,7 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) volume_controller_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "VolumeControllerPlugin");
|
||||
volume_controller_plugin_register_with_registrar(volume_controller_registrar);
|
||||
}
|
||||
|
@ -7,12 +7,14 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
flutter_platform_alert
|
||||
flutter_udid
|
||||
flutter_webrtc
|
||||
irondash_engine_context
|
||||
media_kit_libs_linux
|
||||
media_kit_video
|
||||
sqlite3_flutter_libs
|
||||
super_native_extensions
|
||||
url_launcher_linux
|
||||
volume_controller
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import bitsdojo_window_macos
|
||||
import connectivity_plus
|
||||
import device_info_plus
|
||||
import file_picker
|
||||
import file_selector_macos
|
||||
@ -14,7 +15,9 @@ import firebase_messaging
|
||||
import flutter_inappwebview_macos
|
||||
import flutter_platform_alert
|
||||
import flutter_udid
|
||||
import flutter_webrtc
|
||||
import irondash_engine_context
|
||||
import livekit_client
|
||||
import media_kit_libs_macos_video
|
||||
import media_kit_video
|
||||
import package_info_plus
|
||||
@ -29,6 +32,7 @@ import wakelock_plus
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
@ -37,7 +41,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
FlutterPlatformAlertPlugin.register(with: registry.registrar(forPlugin: "FlutterPlatformAlertPlugin"))
|
||||
FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin"))
|
||||
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
|
||||
IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin"))
|
||||
LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin"))
|
||||
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
|
||||
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
|
@ -1,6 +1,8 @@
|
||||
PODS:
|
||||
- bitsdojo_window_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- croppy (0.0.1):
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
@ -50,6 +52,9 @@ PODS:
|
||||
- flutter_udid (0.0.1):
|
||||
- FlutterMacOS
|
||||
- SAMKeychain
|
||||
- flutter_webrtc (0.14.0):
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (= 125.6422.07)
|
||||
- FlutterMacOS (1.0.0)
|
||||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
@ -80,6 +85,10 @@ PODS:
|
||||
- GoogleUtilities/Privacy
|
||||
- irondash_engine_context (0.0.1):
|
||||
- FlutterMacOS
|
||||
- livekit_client (2.4.7):
|
||||
- flutter_webrtc
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (= 125.6422.07)
|
||||
- media_kit_libs_macos_video (1.0.4):
|
||||
- FlutterMacOS
|
||||
- media_kit_video (0.0.1):
|
||||
@ -133,9 +142,11 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- wakelock_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (125.6422.07)
|
||||
|
||||
DEPENDENCIES:
|
||||
- bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`)
|
||||
- connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`)
|
||||
- croppy (from `Flutter/ephemeral/.symlinks/plugins/croppy/macos`)
|
||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
||||
@ -145,8 +156,10 @@ DEPENDENCIES:
|
||||
- flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`)
|
||||
- flutter_platform_alert (from `Flutter/ephemeral/.symlinks/plugins/flutter_platform_alert/macos`)
|
||||
- flutter_udid (from `Flutter/ephemeral/.symlinks/plugins/flutter_udid/macos`)
|
||||
- flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`)
|
||||
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
|
||||
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
|
||||
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
@ -173,10 +186,13 @@ SPEC REPOS:
|
||||
- PromisesObjC
|
||||
- SAMKeychain
|
||||
- sqlite3
|
||||
- WebRTC-SDK
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
bitsdojo_window_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos
|
||||
connectivity_plus:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos
|
||||
croppy:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/croppy/macos
|
||||
device_info_plus:
|
||||
@ -195,10 +211,14 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_platform_alert/macos
|
||||
flutter_udid:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_udid/macos
|
||||
flutter_webrtc:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
irondash_engine_context:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos
|
||||
livekit_client:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/livekit_client/macos
|
||||
media_kit_libs_macos_video:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
|
||||
media_kit_video:
|
||||
@ -224,6 +244,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9
|
||||
connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e
|
||||
croppy: d9bfc8c02f3cd1851f669a421df298a474b78f43
|
||||
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
|
||||
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
||||
@ -238,10 +259,12 @@ SPEC CHECKSUMS:
|
||||
flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d
|
||||
flutter_platform_alert: 8fa7a7c21f95b26d08b4a3891936ca27e375f284
|
||||
flutter_udid: d26e455e8c06174e6aff476e147defc6cae38495
|
||||
flutter_webrtc: a7eeb54859e672228c28f4b48b1fb61561976ea3
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba
|
||||
livekit_client: c5fc13c397f17de76534280744ddd8c232915057
|
||||
media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65
|
||||
media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
@ -258,6 +281,7 @@ SPEC CHECKSUMS:
|
||||
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||
volume_controller: 5c068e6d085c80dadd33fc2c918d2114b775b3dd
|
||||
wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497
|
||||
WebRTC-SDK: dff00a3892bc570b6014e046297782084071657e
|
||||
|
||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||
|
||||
|
@ -263,7 +263,6 @@
|
||||
33CC10EC2044A3C60003C045 = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
enabled = 1;
|
||||
@ -583,9 +582,13 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
@ -716,9 +719,13 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
@ -737,9 +744,13 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
|
@ -8,6 +8,8 @@
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.downloads.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
|
@ -26,6 +26,8 @@
|
||||
<string>$(PRODUCT_COPYRIGHT)</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.social-networking</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
|
@ -4,5 +4,17 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.downloads.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
138
pubspec.lock
138
pubspec.lock
@ -18,7 +18,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.3.55"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e"
|
||||
@ -26,13 +26,13 @@ packages:
|
||||
source: hosted
|
||||
version: "7.3.0"
|
||||
analyzer_plugin:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: analyzer_plugin
|
||||
sha256: b3075265c5ab222f8b3188342dcb50b476286394a40323e85d1fa725035d40a4
|
||||
sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.0"
|
||||
version: "0.12.0"
|
||||
animations:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -69,26 +69,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
auto_route:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: auto_route
|
||||
sha256: "89bc5d17d8c575399891194b8cd02b39f52a8512c730052f17ebe443cdcb9109"
|
||||
sha256: eae18fcd3e3762eb6074a3560c0f411d1e36bd9f8d3eed9c15ed1c577e8d1815
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.1"
|
||||
version: "10.1.0"
|
||||
auto_route_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: auto_route_generator
|
||||
sha256: "8e622d26dc6be4bf496d47969e3e9ba555c3abcf2290da6abfa43cbd4f57fa52"
|
||||
sha256: "9e3846fcbeacba5c362557328dd8c8fbc953b6a0cbc3395365e8d8f92eea29c4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.1"
|
||||
version: "10.1.0"
|
||||
avatar_stack:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -313,6 +313,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
connectivity_plus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: "051849e2bd7c7b3bc5844ea0d096609ddc3a859890ec3a9ac4a65a2620cc1f99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: connectivity_plus_platform_interface
|
||||
sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -386,7 +402,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.7.5"
|
||||
custom_lint_visitor:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: custom_lint_visitor
|
||||
sha256: "36282d85714af494ee2d7da8c8913630aa6694da99f104fb2ed4afcf8fc857d8"
|
||||
@ -401,6 +417,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
dart_webrtc:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_webrtc
|
||||
sha256: "5b76fd85ac95d6f5dee3e7d7de8d4b51bfbec1dc73804647c6aebb52d6297116"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.3+hotfix.2"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -525,10 +549,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -845,6 +869,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_webrtc:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_webrtc
|
||||
sha256: dd47ca103b5b6217771e6277882674276d9621bbf9eb23da3c03898b507844e3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.14.1"
|
||||
font_awesome_flutter:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1041,10 +1073,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
version: "0.20.2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1097,10 +1129,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1133,6 +1165,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
livekit_client:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: livekit_client
|
||||
sha256: dc8fe8295353a6f4c96915a49faece4ede2334d2b2bdf5ed4b985e07507bdf09
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.7"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1185,10 +1225,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: material_symbols_icons
|
||||
sha256: d45b6c36c3effa8cb51b1afb8698107d5ff1f88fa4631428f34a8a01abc295d7
|
||||
sha256: "7c50901b39d1ad645ee25d920aed008061e1fd541a897b4ebf2c01d966dbf16b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2815.0"
|
||||
version: "4.2815.1"
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1269,6 +1309,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
mime_type:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime_type
|
||||
sha256: d652b613e84dac1af28030a9fba82c0999be05b98163f9e18a0849c6e63838bb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
modal_bottom_sheet:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1285,6 +1333,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
nm:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nm
|
||||
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1437,6 +1493,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
protobuf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: protobuf
|
||||
sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1565,6 +1629,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
sdp_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sdp_transform
|
||||
sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1734,10 +1806,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
|
||||
sha256: c0503c69b44d5714e6abbf4c1f51a3c3cc42b75ce785f44404765e4635481d38
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.5"
|
||||
version: "2.7.6"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1854,10 +1926,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: table_calendar
|
||||
sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63
|
||||
sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
version: "3.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -2023,10 +2095,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
|
||||
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.16"
|
||||
version: "1.1.17"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -2055,18 +2127,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.0"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: volume_controller
|
||||
sha256: e82fd689bb8e1fe8e64be3fa5946ff8699058f8cf9f4c1679acdba20cda7f5bd
|
||||
sha256: d75039e69c0d90e7810bfd47e3eedf29ff8543ea7a10392792e81f9bded7edf5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.3"
|
||||
version: "3.4.0"
|
||||
wakelock_plus:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -2115,6 +2187,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
webrtc_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webrtc_interface
|
||||
sha256: "86fe3afc81a08481dfb25cf14a5a94e27062ecef25544783f352c914e0bbc1ca"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2+hotfix.2"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
11
pubspec.yaml
11
pubspec.yaml
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 3.0.0+93
|
||||
version: 3.0.0+94
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.2
|
||||
@ -101,6 +101,8 @@ dependencies:
|
||||
dismissible_page: ^1.0.2
|
||||
super_sliver_list: ^0.4.1
|
||||
super_clipboard: ^0.9.0-dev.6
|
||||
flutter_webrtc: ^0.14.1
|
||||
livekit_client: ^2.4.7
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -122,6 +124,13 @@ dev_dependencies:
|
||||
drift_dev: ^2.26.0
|
||||
flutter_launcher_icons: ^0.14.3
|
||||
|
||||
dependency_overrides:
|
||||
# https://github.com/dart-lang/sdk/issues/60784#issuecomment-2904784415
|
||||
analyzer: 7.3.0
|
||||
analyzer_plugin: 0.12.0
|
||||
# https://github.com/dart-lang/sdk/issues/60784#issuecomment-2906872272
|
||||
custom_lint_visitor: 1.0.0+7.3.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "island",
|
||||
"short_name": "island",
|
||||
"name": "Solian",
|
||||
"short_name": "Solian",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
|
@ -4,7 +4,7 @@ project(island LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "island")
|
||||
set(BINARY_NAME "Solian")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
|
@ -7,12 +7,15 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
||||
#include <flutter_platform_alert/flutter_platform_alert_plugin.h>
|
||||
#include <flutter_udid/flutter_udid_plugin_c_api.h>
|
||||
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
|
||||
#include <irondash_engine_context/irondash_engine_context_plugin_c_api.h>
|
||||
#include <livekit_client/live_kit_plugin.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 <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
@ -23,6 +26,8 @@
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
BitsdojoWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||
@ -33,8 +38,12 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("FlutterPlatformAlertPlugin"));
|
||||
FlutterUdidPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterUdidPluginCApi"));
|
||||
FlutterWebRTCPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterWebRTCPlugin"));
|
||||
IrondashEngineContextPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi"));
|
||||
LiveKitPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("LiveKitPlugin"));
|
||||
MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
|
||||
MediaKitVideoPluginCApiRegisterWithRegistrar(
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
bitsdojo_window_windows
|
||||
connectivity_plus
|
||||
file_selector_windows
|
||||
firebase_core
|
||||
flutter_inappwebview_windows
|
||||
flutter_platform_alert
|
||||
flutter_udid
|
||||
flutter_webrtc
|
||||
irondash_engine_context
|
||||
livekit_client
|
||||
media_kit_libs_windows_video
|
||||
media_kit_video
|
||||
sqlite3_flutter_libs
|
||||
|
@ -90,12 +90,12 @@ BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "com.example" "\0"
|
||||
VALUE "FileDescription", "island" "\0"
|
||||
VALUE "FileDescription", "Solian" "\0"
|
||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||
VALUE "InternalName", "island" "\0"
|
||||
VALUE "InternalName", "Solian" "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0"
|
||||
VALUE "OriginalFilename", "island.exe" "\0"
|
||||
VALUE "ProductName", "island" "\0"
|
||||
VALUE "OriginalFilename", "Solian.exe" "\0"
|
||||
VALUE "ProductName", "Solian" "\0"
|
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||
END
|
||||
END
|
||||
|
@ -30,7 +30,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.Create(L"island", origin, size)) {
|
||||
if (!window.Create(L"Solian", origin, size)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
window.SetQuitOnClose(true);
|
||||
|
Reference in New Issue
Block a user