Compare commits
17 Commits
3.5.0+150
...
29574ada88
| Author | SHA1 | Date | |
|---|---|---|---|
|
29574ada88
|
|||
|
7369f5d88c
|
|||
|
5b3c138ebe
|
|||
|
562bdf62e9
|
|||
|
a73672925e
|
|||
|
c585522c35
|
|||
|
6aba84e506
|
|||
|
c6f104afc7
|
|||
|
4181fd0090
|
|||
|
84bca9601a
|
|||
|
31b83b2d27
|
|||
|
dfcb089c69
|
|||
|
fe365e8c6d
|
|||
|
b5262137ad
|
|||
|
11e93314c7
|
|||
|
c8658bc0ca
|
|||
|
b2f689693b
|
@@ -1020,6 +1020,8 @@
|
|||||||
"uploadFile": "Upload File",
|
"uploadFile": "Upload File",
|
||||||
"authDeviceChallenges": "Device Usage",
|
"authDeviceChallenges": "Device Usage",
|
||||||
"authDeviceHint": "Swipe left to edit label, swipe right to logout device.",
|
"authDeviceHint": "Swipe left to edit label, swipe right to logout device.",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
"settingsMessageDisplayStyle": "Message Display Style",
|
"settingsMessageDisplayStyle": "Message Display Style",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"manual": "Manual",
|
"manual": "Manual",
|
||||||
@@ -1489,5 +1491,7 @@
|
|||||||
"accountActivationAlert": "Remember to activate your account",
|
"accountActivationAlert": "Remember to activate your account",
|
||||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
"accountActivationResend": "Resend"
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,9 +268,9 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- record_ios (1.1.0):
|
- record_ios (1.1.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SDWebImage (5.21.3):
|
- SDWebImage (5.21.5):
|
||||||
- SDWebImage/Core (= 5.21.3)
|
- SDWebImage/Core (= 5.21.5)
|
||||||
- SDWebImage/Core (5.21.3)
|
- SDWebImage/Core (5.21.5)
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
@@ -281,25 +281,25 @@ PODS:
|
|||||||
- sqflite_darwin (0.0.4):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- sqlite3 (3.50.4):
|
- sqlite3 (3.51.1):
|
||||||
- sqlite3/common (= 3.50.4)
|
- sqlite3/common (= 3.51.1)
|
||||||
- sqlite3/common (3.50.4)
|
- sqlite3/common (3.51.1)
|
||||||
- sqlite3/dbstatvtab (3.50.4):
|
- sqlite3/dbstatvtab (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/fts5 (3.50.4):
|
- sqlite3/fts5 (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/math (3.50.4):
|
- sqlite3/math (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/perf-threadsafe (3.50.4):
|
- sqlite3/perf-threadsafe (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/rtree (3.50.4):
|
- sqlite3/rtree (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/session (3.50.4):
|
- sqlite3/session (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3_flutter_libs (0.0.1):
|
- sqlite3_flutter_libs (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- sqlite3 (~> 3.50.4)
|
- sqlite3 (~> 3.51.1)
|
||||||
- sqlite3/dbstatvtab
|
- sqlite3/dbstatvtab
|
||||||
- sqlite3/fts5
|
- sqlite3/fts5
|
||||||
- sqlite3/math
|
- sqlite3/math
|
||||||
@@ -545,13 +545,13 @@ SPEC CHECKSUMS:
|
|||||||
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||||
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
|
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
|
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
||||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41
|
||||||
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
|
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
|
||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
||||||
|
|||||||
@@ -358,8 +358,12 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveChatRooms(List<SnChatRoom> rooms) async {
|
Future<void> saveChatRooms(
|
||||||
|
List<SnChatRoom> rooms, {
|
||||||
|
bool override = false,
|
||||||
|
}) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
|
if (override) {
|
||||||
// 1. Identify rooms to remove
|
// 1. Identify rooms to remove
|
||||||
final remoteRoomIds = rooms.map((r) => r.id).toSet();
|
final remoteRoomIds = rooms.map((r) => r.id).toSet();
|
||||||
final currentRooms = await select(chatRooms).get();
|
final currentRooms = await select(chatRooms).get();
|
||||||
@@ -369,13 +373,15 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
if (idsToRemove.isNotEmpty) {
|
if (idsToRemove.isNotEmpty) {
|
||||||
final idsList = idsToRemove.toList();
|
final idsList = idsToRemove.toList();
|
||||||
// Remove messages
|
// Remove messages
|
||||||
await (delete(chatMessages)..where((t) => t.roomId.isIn(idsList))).go();
|
await (delete(chatMessages)
|
||||||
|
..where((t) => t.roomId.isIn(idsList))).go();
|
||||||
// Remove members
|
// Remove members
|
||||||
await (delete(chatMembers)
|
await (delete(chatMembers)
|
||||||
..where((t) => t.chatRoomId.isIn(idsList))).go();
|
..where((t) => t.chatRoomId.isIn(idsList))).go();
|
||||||
// Remove rooms
|
// Remove rooms
|
||||||
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
|
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Upsert remote rooms
|
// 2. Upsert remote rooms
|
||||||
await batch((batch) {
|
await batch((batch) {
|
||||||
|
|||||||
@@ -216,20 +216,20 @@ sealed class SnAuthDevice with _$SnAuthDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge {
|
sealed class SnAuthDeviceWithSession with _$SnAuthDeviceWithSession {
|
||||||
const factory SnAuthDeviceWithChallenge({
|
const factory SnAuthDeviceWithSession({
|
||||||
required String id,
|
required String id,
|
||||||
required String deviceId,
|
required String deviceId,
|
||||||
required String deviceName,
|
required String deviceName,
|
||||||
required String? deviceLabel,
|
required String? deviceLabel,
|
||||||
required String accountId,
|
required String accountId,
|
||||||
required int platform,
|
required int platform,
|
||||||
required List<SnAuthChallenge> challenges,
|
required List<SnAuthSession> sessions,
|
||||||
@Default(false) bool isCurrent,
|
@Default(false) bool isCurrent,
|
||||||
}) = _SnAuthDeviceWithChallengee;
|
}) = _SnAuthDeviceWithSessione;
|
||||||
|
|
||||||
factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) =>
|
factory SnAuthDeviceWithSession.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SnAuthDeviceWithChallengeFromJson(json);
|
_$SnAuthDeviceWithSessionFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
|||||||
@@ -3068,51 +3068,51 @@ as bool,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SnAuthDeviceWithChallenge _$SnAuthDeviceWithChallengeFromJson(
|
SnAuthDeviceWithSession _$SnAuthDeviceWithSessionFromJson(
|
||||||
Map<String, dynamic> json
|
Map<String, dynamic> json
|
||||||
) {
|
) {
|
||||||
return _SnAuthDeviceWithChallengee.fromJson(
|
return _SnAuthDeviceWithSessione.fromJson(
|
||||||
json
|
json
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnAuthDeviceWithChallenge {
|
mixin _$SnAuthDeviceWithSession {
|
||||||
|
|
||||||
String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; List<SnAuthChallenge> get challenges; bool get isCurrent;
|
String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; List<SnAuthSession> get sessions; bool get isCurrent;
|
||||||
/// Create a copy of SnAuthDeviceWithChallenge
|
/// Create a copy of SnAuthDeviceWithSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnAuthDeviceWithChallengeCopyWith<SnAuthDeviceWithChallenge> get copyWith => _$SnAuthDeviceWithChallengeCopyWithImpl<SnAuthDeviceWithChallenge>(this as SnAuthDeviceWithChallenge, _$identity);
|
$SnAuthDeviceWithSessionCopyWith<SnAuthDeviceWithSession> get copyWith => _$SnAuthDeviceWithSessionCopyWithImpl<SnAuthDeviceWithSession>(this as SnAuthDeviceWithSession, _$identity);
|
||||||
|
|
||||||
/// Serializes this SnAuthDeviceWithChallenge to a JSON map.
|
/// Serializes this SnAuthDeviceWithSession to a JSON map.
|
||||||
Map<String, dynamic> toJson();
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDeviceWithChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.challenges, challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDeviceWithSession&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.sessions, sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(challenges),isCurrent);
|
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(sessions),isCurrent);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)';
|
return 'SnAuthDeviceWithSession(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract mixin class $SnAuthDeviceWithChallengeCopyWith<$Res> {
|
abstract mixin class $SnAuthDeviceWithSessionCopyWith<$Res> {
|
||||||
factory $SnAuthDeviceWithChallengeCopyWith(SnAuthDeviceWithChallenge value, $Res Function(SnAuthDeviceWithChallenge) _then) = _$SnAuthDeviceWithChallengeCopyWithImpl;
|
factory $SnAuthDeviceWithSessionCopyWith(SnAuthDeviceWithSession value, $Res Function(SnAuthDeviceWithSession) _then) = _$SnAuthDeviceWithSessionCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent
|
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthSession> sessions, bool isCurrent
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -3120,16 +3120,16 @@ $Res call({
|
|||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class _$SnAuthDeviceWithChallengeCopyWithImpl<$Res>
|
class _$SnAuthDeviceWithSessionCopyWithImpl<$Res>
|
||||||
implements $SnAuthDeviceWithChallengeCopyWith<$Res> {
|
implements $SnAuthDeviceWithSessionCopyWith<$Res> {
|
||||||
_$SnAuthDeviceWithChallengeCopyWithImpl(this._self, this._then);
|
_$SnAuthDeviceWithSessionCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
final SnAuthDeviceWithChallenge _self;
|
final SnAuthDeviceWithSession _self;
|
||||||
final $Res Function(SnAuthDeviceWithChallenge) _then;
|
final $Res Function(SnAuthDeviceWithSession) _then;
|
||||||
|
|
||||||
/// Create a copy of SnAuthDeviceWithChallenge
|
/// Create a copy of SnAuthDeviceWithSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -3137,8 +3137,8 @@ as String,deviceName: null == deviceName ? _self.deviceName : deviceName // igno
|
|||||||
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
|
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
as int,challenges: null == challenges ? _self.challenges : challenges // ignore: cast_nullable_to_non_nullable
|
as int,sessions: null == sessions ? _self.sessions : sessions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<SnAuthChallenge>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -3146,8 +3146,8 @@ as bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Adds pattern-matching-related methods to [SnAuthDeviceWithChallenge].
|
/// Adds pattern-matching-related methods to [SnAuthDeviceWithSession].
|
||||||
extension SnAuthDeviceWithChallengePatterns on SnAuthDeviceWithChallenge {
|
extension SnAuthDeviceWithSessionPatterns on SnAuthDeviceWithSession {
|
||||||
/// A variant of `map` that fallback to returning `orElse`.
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
///
|
///
|
||||||
/// It is equivalent to doing:
|
/// It is equivalent to doing:
|
||||||
@@ -3160,10 +3160,10 @@ extension SnAuthDeviceWithChallengePatterns on SnAuthDeviceWithChallenge {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnAuthDeviceWithChallengee value)? $default,{required TResult orElse(),}){
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnAuthDeviceWithSessione value)? $default,{required TResult orElse(),}){
|
||||||
final _that = this;
|
final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee() when $default != null:
|
case _SnAuthDeviceWithSessione() when $default != null:
|
||||||
return $default(_that);case _:
|
return $default(_that);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
@@ -3182,10 +3182,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnAuthDeviceWithChallengee value) $default,){
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnAuthDeviceWithSessione value) $default,){
|
||||||
final _that = this;
|
final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee():
|
case _SnAuthDeviceWithSessione():
|
||||||
return $default(_that);}
|
return $default(_that);}
|
||||||
}
|
}
|
||||||
/// A variant of `map` that fallback to returning `null`.
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
@@ -3200,10 +3200,10 @@ return $default(_that);}
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnAuthDeviceWithChallengee value)? $default,){
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnAuthDeviceWithSessione value)? $default,){
|
||||||
final _that = this;
|
final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee() when $default != null:
|
case _SnAuthDeviceWithSessione() when $default != null:
|
||||||
return $default(_that);case _:
|
return $default(_that);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -3221,10 +3221,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthSession> sessions, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee() when $default != null:
|
case _SnAuthDeviceWithSessione() when $default != null:
|
||||||
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _:
|
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3242,10 +3242,10 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthSession> sessions, bool isCurrent) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee():
|
case _SnAuthDeviceWithSessione():
|
||||||
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);}
|
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -3259,10 +3259,10 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthSession> sessions, bool isCurrent)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthDeviceWithChallengee() when $default != null:
|
case _SnAuthDeviceWithSessione() when $default != null:
|
||||||
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _:
|
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3273,9 +3273,9 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnAuthDeviceWithChallengee implements SnAuthDeviceWithChallenge {
|
class _SnAuthDeviceWithSessione implements SnAuthDeviceWithSession {
|
||||||
const _SnAuthDeviceWithChallengee({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, required final List<SnAuthChallenge> challenges, this.isCurrent = false}): _challenges = challenges;
|
const _SnAuthDeviceWithSessione({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, required final List<SnAuthSession> sessions, this.isCurrent = false}): _sessions = sessions;
|
||||||
factory _SnAuthDeviceWithChallengee.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceWithChallengeeFromJson(json);
|
factory _SnAuthDeviceWithSessione.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceWithSessioneFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@override final String deviceId;
|
@override final String deviceId;
|
||||||
@@ -3283,49 +3283,49 @@ class _SnAuthDeviceWithChallengee implements SnAuthDeviceWithChallenge {
|
|||||||
@override final String? deviceLabel;
|
@override final String? deviceLabel;
|
||||||
@override final String accountId;
|
@override final String accountId;
|
||||||
@override final int platform;
|
@override final int platform;
|
||||||
final List<SnAuthChallenge> _challenges;
|
final List<SnAuthSession> _sessions;
|
||||||
@override List<SnAuthChallenge> get challenges {
|
@override List<SnAuthSession> get sessions {
|
||||||
if (_challenges is EqualUnmodifiableListView) return _challenges;
|
if (_sessions is EqualUnmodifiableListView) return _sessions;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_challenges);
|
return EqualUnmodifiableListView(_sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override@JsonKey() final bool isCurrent;
|
@override@JsonKey() final bool isCurrent;
|
||||||
|
|
||||||
/// Create a copy of SnAuthDeviceWithChallenge
|
/// Create a copy of SnAuthDeviceWithSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$SnAuthDeviceWithChallengeeCopyWith<_SnAuthDeviceWithChallengee> get copyWith => __$SnAuthDeviceWithChallengeeCopyWithImpl<_SnAuthDeviceWithChallengee>(this, _$identity);
|
_$SnAuthDeviceWithSessioneCopyWith<_SnAuthDeviceWithSessione> get copyWith => __$SnAuthDeviceWithSessioneCopyWithImpl<_SnAuthDeviceWithSessione>(this, _$identity);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return _$SnAuthDeviceWithChallengeeToJson(this, );
|
return _$SnAuthDeviceWithSessioneToJson(this, );
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDeviceWithChallengee&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._challenges, _challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDeviceWithSessione&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._sessions, _sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(_challenges),isCurrent);
|
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(_sessions),isCurrent);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)';
|
return 'SnAuthDeviceWithSession(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract mixin class _$SnAuthDeviceWithChallengeeCopyWith<$Res> implements $SnAuthDeviceWithChallengeCopyWith<$Res> {
|
abstract mixin class _$SnAuthDeviceWithSessioneCopyWith<$Res> implements $SnAuthDeviceWithSessionCopyWith<$Res> {
|
||||||
factory _$SnAuthDeviceWithChallengeeCopyWith(_SnAuthDeviceWithChallengee value, $Res Function(_SnAuthDeviceWithChallengee) _then) = __$SnAuthDeviceWithChallengeeCopyWithImpl;
|
factory _$SnAuthDeviceWithSessioneCopyWith(_SnAuthDeviceWithSessione value, $Res Function(_SnAuthDeviceWithSessione) _then) = __$SnAuthDeviceWithSessioneCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent
|
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthSession> sessions, bool isCurrent
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -3333,25 +3333,25 @@ $Res call({
|
|||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class __$SnAuthDeviceWithChallengeeCopyWithImpl<$Res>
|
class __$SnAuthDeviceWithSessioneCopyWithImpl<$Res>
|
||||||
implements _$SnAuthDeviceWithChallengeeCopyWith<$Res> {
|
implements _$SnAuthDeviceWithSessioneCopyWith<$Res> {
|
||||||
__$SnAuthDeviceWithChallengeeCopyWithImpl(this._self, this._then);
|
__$SnAuthDeviceWithSessioneCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
final _SnAuthDeviceWithChallengee _self;
|
final _SnAuthDeviceWithSessione _self;
|
||||||
final $Res Function(_SnAuthDeviceWithChallengee) _then;
|
final $Res Function(_SnAuthDeviceWithSessione) _then;
|
||||||
|
|
||||||
/// Create a copy of SnAuthDeviceWithChallenge
|
/// Create a copy of SnAuthDeviceWithSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
|
||||||
return _then(_SnAuthDeviceWithChallengee(
|
return _then(_SnAuthDeviceWithSessione(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
|
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
|
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
as int,challenges: null == challenges ? _self._challenges : challenges // ignore: cast_nullable_to_non_nullable
|
as int,sessions: null == sessions ? _self._sessions : sessions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<SnAuthChallenge>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,24 +367,24 @@ Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) =>
|
|||||||
'is_current': instance.isCurrent,
|
'is_current': instance.isCurrent,
|
||||||
};
|
};
|
||||||
|
|
||||||
_SnAuthDeviceWithChallengee _$SnAuthDeviceWithChallengeeFromJson(
|
_SnAuthDeviceWithSessione _$SnAuthDeviceWithSessioneFromJson(
|
||||||
Map<String, dynamic> json,
|
Map<String, dynamic> json,
|
||||||
) => _SnAuthDeviceWithChallengee(
|
) => _SnAuthDeviceWithSessione(
|
||||||
id: json['id'] as String,
|
id: json['id'] as String,
|
||||||
deviceId: json['device_id'] as String,
|
deviceId: json['device_id'] as String,
|
||||||
deviceName: json['device_name'] as String,
|
deviceName: json['device_name'] as String,
|
||||||
deviceLabel: json['device_label'] as String?,
|
deviceLabel: json['device_label'] as String?,
|
||||||
accountId: json['account_id'] as String,
|
accountId: json['account_id'] as String,
|
||||||
platform: (json['platform'] as num).toInt(),
|
platform: (json['platform'] as num).toInt(),
|
||||||
challenges:
|
sessions:
|
||||||
(json['challenges'] as List<dynamic>)
|
(json['sessions'] as List<dynamic>)
|
||||||
.map((e) => SnAuthChallenge.fromJson(e as Map<String, dynamic>))
|
.map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
isCurrent: json['is_current'] as bool? ?? false,
|
isCurrent: json['is_current'] as bool? ?? false,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson(
|
Map<String, dynamic> _$SnAuthDeviceWithSessioneToJson(
|
||||||
_SnAuthDeviceWithChallengee instance,
|
_SnAuthDeviceWithSessione instance,
|
||||||
) => <String, dynamic>{
|
) => <String, dynamic>{
|
||||||
'id': instance.id,
|
'id': instance.id,
|
||||||
'device_id': instance.deviceId,
|
'device_id': instance.deviceId,
|
||||||
@@ -392,7 +392,7 @@ Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson(
|
|||||||
'device_label': instance.deviceLabel,
|
'device_label': instance.deviceLabel,
|
||||||
'account_id': instance.accountId,
|
'account_id': instance.accountId,
|
||||||
'platform': instance.platform,
|
'platform': instance.platform,
|
||||||
'challenges': instance.challenges.map((e) => e.toJson()).toList(),
|
'sessions': instance.sessions.map((e) => e.toJson()).toList(),
|
||||||
'is_current': instance.isCurrent,
|
'is_current': instance.isCurrent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -59,8 +59,9 @@ sealed class SnAuthSession with _$SnAuthSession {
|
|||||||
required DateTime? expiredAt,
|
required DateTime? expiredAt,
|
||||||
required List<dynamic> audiences,
|
required List<dynamic> audiences,
|
||||||
required List<dynamic> scopes,
|
required List<dynamic> scopes,
|
||||||
required String ipAddress,
|
required String? ipAddress,
|
||||||
required String userAgent,
|
required String? userAgent,
|
||||||
|
required GeoIpLocation? location,
|
||||||
required int type,
|
required int type,
|
||||||
required String accountId,
|
required String accountId,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ $GeoIpLocationCopyWith<$Res>? get location {
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnAuthSession {
|
mixin _$SnAuthSession {
|
||||||
|
|
||||||
String get id; String? get label; DateTime get lastGrantedAt; DateTime? get expiredAt; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; int get type; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
String get id; String? get label; DateTime get lastGrantedAt; DateTime? get expiredAt; List<dynamic> get audiences; List<dynamic> get scopes; String? get ipAddress; String? get userAgent; GeoIpLocation? get location; int get type; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||||
/// Create a copy of SnAuthSession
|
/// Create a copy of SnAuthSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -898,16 +898,16 @@ $SnAuthSessionCopyWith<SnAuthSession> get copyWith => _$SnAuthSessionCopyWithImp
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.location, location) || other.location == location)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,type,accountId,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,location,type,accountId,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, location: $location, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -918,11 +918,11 @@ abstract mixin class $SnAuthSessionCopyWith<$Res> {
|
|||||||
factory $SnAuthSessionCopyWith(SnAuthSession value, $Res Function(SnAuthSession) _then) = _$SnAuthSessionCopyWithImpl;
|
factory $SnAuthSessionCopyWith(SnAuthSession value, $Res Function(SnAuthSession) _then) = _$SnAuthSessionCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$GeoIpLocationCopyWith<$Res>? get location;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -935,7 +935,7 @@ class _$SnAuthSessionCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAuthSession
|
/// Create a copy of SnAuthSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = freezed,Object? userAgent = freezed,Object? location = freezed,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -943,9 +943,10 @@ as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGran
|
|||||||
as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable
|
as DateTime?,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,ipAddress: freezed == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
||||||
as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
as String?,userAgent: freezed == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GeoIpLocation?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // 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,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -953,7 +954,19 @@ as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ign
|
|||||||
as DateTime?,
|
as DateTime?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
/// Create a copy of SnAuthSession
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GeoIpLocationCopyWith<$Res>? get location {
|
||||||
|
if (_self.location == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) {
|
||||||
|
return _then(_self.copyWith(location: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1032,10 +1045,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthSession() when $default != null:
|
case _SnAuthSession() when $default != null:
|
||||||
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1053,10 +1066,10 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthSession():
|
case _SnAuthSession():
|
||||||
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -1070,10 +1083,10 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAuthSession() when $default != null:
|
case _SnAuthSession() when $default != null:
|
||||||
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1098,7 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnAuthSession implements SnAuthSession {
|
class _SnAuthSession implements SnAuthSession {
|
||||||
const _SnAuthSession({required this.id, required this.label, required this.lastGrantedAt, required this.expiredAt, required final List<dynamic> audiences, required final List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.type, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _audiences = audiences,_scopes = scopes;
|
const _SnAuthSession({required this.id, required this.label, required this.lastGrantedAt, required this.expiredAt, required final List<dynamic> audiences, required final List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.location, required this.type, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _audiences = audiences,_scopes = scopes;
|
||||||
factory _SnAuthSession.fromJson(Map<String, dynamic> json) => _$SnAuthSessionFromJson(json);
|
factory _SnAuthSession.fromJson(Map<String, dynamic> json) => _$SnAuthSessionFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@@ -1106,8 +1119,9 @@ class _SnAuthSession implements SnAuthSession {
|
|||||||
return EqualUnmodifiableListView(_scopes);
|
return EqualUnmodifiableListView(_scopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override final String ipAddress;
|
@override final String? ipAddress;
|
||||||
@override final String userAgent;
|
@override final String? userAgent;
|
||||||
|
@override final GeoIpLocation? location;
|
||||||
@override final int type;
|
@override final int type;
|
||||||
@override final String accountId;
|
@override final String accountId;
|
||||||
@override final DateTime createdAt;
|
@override final DateTime createdAt;
|
||||||
@@ -1127,16 +1141,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.location, location) || other.location == location)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,type,accountId,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,location,type,accountId,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, location: $location, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1147,11 +1161,11 @@ abstract mixin class _$SnAuthSessionCopyWith<$Res> implements $SnAuthSessionCopy
|
|||||||
factory _$SnAuthSessionCopyWith(_SnAuthSession value, $Res Function(_SnAuthSession) _then) = __$SnAuthSessionCopyWithImpl;
|
factory _$SnAuthSessionCopyWith(_SnAuthSession value, $Res Function(_SnAuthSession) _then) = __$SnAuthSessionCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List<dynamic> audiences, List<dynamic> scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $GeoIpLocationCopyWith<$Res>? get location;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -1164,7 +1178,7 @@ class __$SnAuthSessionCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAuthSession
|
/// Create a copy of SnAuthSession
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = freezed,Object? userAgent = freezed,Object? location = freezed,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_SnAuthSession(
|
return _then(_SnAuthSession(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -1172,9 +1186,10 @@ as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGran
|
|||||||
as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable
|
as DateTime?,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,ipAddress: freezed == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
||||||
as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
as String?,userAgent: freezed == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GeoIpLocation?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // 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,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -1183,7 +1198,19 @@ as DateTime?,
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthSession
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GeoIpLocationCopyWith<$Res>? get location {
|
||||||
|
if (_self.location == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) {
|
||||||
|
return _then(_self.copyWith(location: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,8 +96,14 @@ _SnAuthSession _$SnAuthSessionFromJson(Map<String, dynamic> json) =>
|
|||||||
: DateTime.parse(json['expired_at'] as String),
|
: DateTime.parse(json['expired_at'] as String),
|
||||||
audiences: json['audiences'] as List<dynamic>,
|
audiences: json['audiences'] as List<dynamic>,
|
||||||
scopes: json['scopes'] as List<dynamic>,
|
scopes: json['scopes'] as List<dynamic>,
|
||||||
ipAddress: json['ip_address'] as String,
|
ipAddress: json['ip_address'] as String?,
|
||||||
userAgent: json['user_agent'] as String,
|
userAgent: json['user_agent'] as String?,
|
||||||
|
location:
|
||||||
|
json['location'] == null
|
||||||
|
? null
|
||||||
|
: GeoIpLocation.fromJson(
|
||||||
|
json['location'] as Map<String, dynamic>,
|
||||||
|
),
|
||||||
type: (json['type'] as num).toInt(),
|
type: (json['type'] as num).toInt(),
|
||||||
accountId: json['account_id'] as String,
|
accountId: json['account_id'] as String,
|
||||||
createdAt: DateTime.parse(json['created_at'] as String),
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
@@ -118,6 +124,7 @@ Map<String, dynamic> _$SnAuthSessionToJson(_SnAuthSession instance) =>
|
|||||||
'scopes': instance.scopes,
|
'scopes': instance.scopes,
|
||||||
'ip_address': instance.ipAddress,
|
'ip_address': instance.ipAddress,
|
||||||
'user_agent': instance.userAgent,
|
'user_agent': instance.userAgent,
|
||||||
|
'location': instance.location?.toJson(),
|
||||||
'type': instance.type,
|
'type': instance.type,
|
||||||
'account_id': instance.accountId,
|
'account_id': instance.accountId,
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ sealed class SnStickerPack with _$SnStickerPack {
|
|||||||
required String description,
|
required String description,
|
||||||
required String prefix,
|
required String prefix,
|
||||||
required String publisherId,
|
required String publisherId,
|
||||||
|
required SnCloudFile? icon,
|
||||||
required SnPublisher? publisher,
|
required SnPublisher? publisher,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required DateTime updatedAt,
|
required DateTime updatedAt,
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ $SnStickerPackCopyWith<$Res>? get pack {
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnStickerPack {
|
mixin _$SnStickerPack {
|
||||||
|
|
||||||
String get id; String get name; String get description; String get prefix; String get publisherId; SnPublisher? get publisher; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; List<SnSticker> get stickers;
|
String get id; String get name; String get description; String get prefix; String get publisherId; SnCloudFile? get icon; SnPublisher? get publisher; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; List<SnSticker> get stickers;
|
||||||
/// Create a copy of SnStickerPack
|
/// Create a copy of SnStickerPack
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -348,16 +348,16 @@ $SnStickerPackCopyWith<SnStickerPack> get copyWith => _$SnStickerPackCopyWithImp
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnStickerPack&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other.stickers, stickers));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnStickerPack&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other.stickers, stickers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,description,prefix,publisherId,publisher,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(stickers));
|
int get hashCode => Object.hash(runtimeType,id,name,description,prefix,publisherId,icon,publisher,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(stickers));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnStickerPack(id: $id, name: $name, description: $description, prefix: $prefix, publisherId: $publisherId, publisher: $publisher, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, stickers: $stickers)';
|
return 'SnStickerPack(id: $id, name: $name, description: $description, prefix: $prefix, publisherId: $publisherId, icon: $icon, publisher: $publisher, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, stickers: $stickers)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -368,11 +368,11 @@ abstract mixin class $SnStickerPackCopyWith<$Res> {
|
|||||||
factory $SnStickerPackCopyWith(SnStickerPack value, $Res Function(SnStickerPack) _then) = _$SnStickerPackCopyWithImpl;
|
factory $SnStickerPackCopyWith(SnStickerPack value, $Res Function(SnStickerPack) _then) = _$SnStickerPackCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, String description, String prefix, String publisherId, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers
|
String id, String name, String description, String prefix, String publisherId, SnCloudFile? icon, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$SnPublisherCopyWith<$Res>? get publisher;
|
$SnCloudFileCopyWith<$Res>? get icon;$SnPublisherCopyWith<$Res>? get publisher;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -385,14 +385,15 @@ class _$SnStickerPackCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnStickerPack
|
/// Create a copy of SnStickerPack
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = null,Object? prefix = null,Object? publisherId = null,Object? publisher = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? stickers = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = null,Object? prefix = null,Object? publisherId = null,Object? icon = freezed,Object? publisher = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? stickers = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
as String,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable
|
as String,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable
|
||||||
as String,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
as String,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
as String,icon: freezed == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnCloudFile?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPublisher?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as SnPublisher?,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,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -404,6 +405,18 @@ as List<SnSticker>,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnCloudFileCopyWith<$Res>? get icon {
|
||||||
|
if (_self.icon == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnCloudFileCopyWith<$Res>(_self.icon!, (value) {
|
||||||
|
return _then(_self.copyWith(icon: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnStickerPack
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
$SnPublisherCopyWith<$Res>? get publisher {
|
$SnPublisherCopyWith<$Res>? get publisher {
|
||||||
if (_self.publisher == null) {
|
if (_self.publisher == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -491,10 +504,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String description, String prefix, String publisherId, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String description, String prefix, String publisherId, SnCloudFile? icon, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnStickerPack() when $default != null:
|
case _SnStickerPack() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);case _:
|
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.icon,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -512,10 +525,10 @@ return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publish
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String description, String prefix, String publisherId, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String description, String prefix, String publisherId, SnCloudFile? icon, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnStickerPack():
|
case _SnStickerPack():
|
||||||
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);}
|
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.icon,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -529,10 +542,10 @@ return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publish
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String description, String prefix, String publisherId, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String description, String prefix, String publisherId, SnCloudFile? icon, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnStickerPack() when $default != null:
|
case _SnStickerPack() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);case _:
|
return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publisherId,_that.icon,_that.publisher,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.stickers);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -544,7 +557,7 @@ return $default(_that.id,_that.name,_that.description,_that.prefix,_that.publish
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnStickerPack implements SnStickerPack {
|
class _SnStickerPack implements SnStickerPack {
|
||||||
const _SnStickerPack({required this.id, required this.name, required this.description, required this.prefix, required this.publisherId, required this.publisher, required this.createdAt, required this.updatedAt, required this.deletedAt, final List<SnSticker> stickers = const []}): _stickers = stickers;
|
const _SnStickerPack({required this.id, required this.name, required this.description, required this.prefix, required this.publisherId, required this.icon, required this.publisher, required this.createdAt, required this.updatedAt, required this.deletedAt, final List<SnSticker> stickers = const []}): _stickers = stickers;
|
||||||
factory _SnStickerPack.fromJson(Map<String, dynamic> json) => _$SnStickerPackFromJson(json);
|
factory _SnStickerPack.fromJson(Map<String, dynamic> json) => _$SnStickerPackFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@@ -552,6 +565,7 @@ class _SnStickerPack implements SnStickerPack {
|
|||||||
@override final String description;
|
@override final String description;
|
||||||
@override final String prefix;
|
@override final String prefix;
|
||||||
@override final String publisherId;
|
@override final String publisherId;
|
||||||
|
@override final SnCloudFile? icon;
|
||||||
@override final SnPublisher? publisher;
|
@override final SnPublisher? publisher;
|
||||||
@override final DateTime createdAt;
|
@override final DateTime createdAt;
|
||||||
@override final DateTime updatedAt;
|
@override final DateTime updatedAt;
|
||||||
@@ -577,16 +591,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnStickerPack&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other._stickers, _stickers));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnStickerPack&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&const DeepCollectionEquality().equals(other._stickers, _stickers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,description,prefix,publisherId,publisher,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(_stickers));
|
int get hashCode => Object.hash(runtimeType,id,name,description,prefix,publisherId,icon,publisher,createdAt,updatedAt,deletedAt,const DeepCollectionEquality().hash(_stickers));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnStickerPack(id: $id, name: $name, description: $description, prefix: $prefix, publisherId: $publisherId, publisher: $publisher, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, stickers: $stickers)';
|
return 'SnStickerPack(id: $id, name: $name, description: $description, prefix: $prefix, publisherId: $publisherId, icon: $icon, publisher: $publisher, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, stickers: $stickers)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -597,11 +611,11 @@ abstract mixin class _$SnStickerPackCopyWith<$Res> implements $SnStickerPackCopy
|
|||||||
factory _$SnStickerPackCopyWith(_SnStickerPack value, $Res Function(_SnStickerPack) _then) = __$SnStickerPackCopyWithImpl;
|
factory _$SnStickerPackCopyWith(_SnStickerPack value, $Res Function(_SnStickerPack) _then) = __$SnStickerPackCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, String description, String prefix, String publisherId, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers
|
String id, String name, String description, String prefix, String publisherId, SnCloudFile? icon, SnPublisher? publisher, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, List<SnSticker> stickers
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@override $SnPublisherCopyWith<$Res>? get publisher;
|
@override $SnCloudFileCopyWith<$Res>? get icon;@override $SnPublisherCopyWith<$Res>? get publisher;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -614,14 +628,15 @@ class __$SnStickerPackCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnStickerPack
|
/// Create a copy of SnStickerPack
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = null,Object? prefix = null,Object? publisherId = null,Object? publisher = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? stickers = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = null,Object? prefix = null,Object? publisherId = null,Object? icon = freezed,Object? publisher = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? stickers = null,}) {
|
||||||
return _then(_SnStickerPack(
|
return _then(_SnStickerPack(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
as String,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable
|
as String,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable
|
||||||
as String,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
as String,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
as String,icon: freezed == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnCloudFile?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPublisher?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as SnPublisher?,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,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -634,6 +649,18 @@ as List<SnSticker>,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnCloudFileCopyWith<$Res>? get icon {
|
||||||
|
if (_self.icon == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnCloudFileCopyWith<$Res>(_self.icon!, (value) {
|
||||||
|
return _then(_self.copyWith(icon: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnStickerPack
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
$SnPublisherCopyWith<$Res>? get publisher {
|
$SnPublisherCopyWith<$Res>? get publisher {
|
||||||
if (_self.publisher == null) {
|
if (_self.publisher == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ _SnStickerPack _$SnStickerPackFromJson(Map<String, dynamic> json) =>
|
|||||||
description: json['description'] as String,
|
description: json['description'] as String,
|
||||||
prefix: json['prefix'] as String,
|
prefix: json['prefix'] as String,
|
||||||
publisherId: json['publisher_id'] as String,
|
publisherId: json['publisher_id'] as String,
|
||||||
|
icon:
|
||||||
|
json['icon'] == null
|
||||||
|
? null
|
||||||
|
: SnCloudFile.fromJson(json['icon'] as Map<String, dynamic>),
|
||||||
publisher:
|
publisher:
|
||||||
json['publisher'] == null
|
json['publisher'] == null
|
||||||
? null
|
? null
|
||||||
@@ -66,6 +70,7 @@ Map<String, dynamic> _$SnStickerPackToJson(_SnStickerPack instance) =>
|
|||||||
'description': instance.description,
|
'description': instance.description,
|
||||||
'prefix': instance.prefix,
|
'prefix': instance.prefix,
|
||||||
'publisher_id': instance.publisherId,
|
'publisher_id': instance.publisherId,
|
||||||
|
'icon': instance.icon?.toJson(),
|
||||||
'publisher': instance.publisher?.toJson(),
|
'publisher': instance.publisher?.toJson(),
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
|
|||||||
373
lib/pods/chat/chat_room.dart
Normal file
373
lib/pods/chat/chat_room.dart
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/database/drift_db.dart';
|
||||||
|
import 'package:island/models/account.dart';
|
||||||
|
import 'package:island/models/chat.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
|
import 'package:island/pods/database.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/userinfo.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'chat_room.g.dart';
|
||||||
|
|
||||||
|
final isSyncingProvider = StateProvider.autoDispose<bool>((ref) => false);
|
||||||
|
|
||||||
|
final flashingMessagesProvider = StateProvider<Set<String>>((ref) => {});
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
||||||
|
@override
|
||||||
|
Future<List<SnChatRoom>> build() async {
|
||||||
|
final db = ref.watch(databaseProvider);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final localRoomsData = await db.select(db.chatRooms).get();
|
||||||
|
if (localRoomsData.isNotEmpty) {
|
||||||
|
final localRooms = await Future.wait(
|
||||||
|
localRoomsData.map((row) async {
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(row.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
return SnChatRoom(
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
description: row.description,
|
||||||
|
type: row.type,
|
||||||
|
isPublic: row.isPublic!,
|
||||||
|
isCommunity: row.isCommunity!,
|
||||||
|
picture:
|
||||||
|
row.picture != null
|
||||||
|
? SnCloudFile.fromJson(row.picture!)
|
||||||
|
: null,
|
||||||
|
background:
|
||||||
|
row.background != null
|
||||||
|
? SnCloudFile.fromJson(row.background!)
|
||||||
|
: null,
|
||||||
|
realmId: row.realmId,
|
||||||
|
accountId: row.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: row.createdAt,
|
||||||
|
updatedAt: row.updatedAt,
|
||||||
|
deletedAt: row.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat');
|
||||||
|
final remoteRooms =
|
||||||
|
resp.data
|
||||||
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
|
.cast<SnChatRoom>()
|
||||||
|
.toList();
|
||||||
|
await db.saveChatRooms(remoteRooms, override: true);
|
||||||
|
// Update state with fresh data
|
||||||
|
state = AsyncData(await _buildRoomsFromDb(db));
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localRooms;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat');
|
||||||
|
final rooms =
|
||||||
|
resp.data
|
||||||
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
|
.cast<SnChatRoom>()
|
||||||
|
.toList();
|
||||||
|
await db.saveChatRooms(rooms, override: true);
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SnChatRoom>> _buildRoomsFromDb(AppDatabase db) async {
|
||||||
|
final localRoomsData = await db.select(db.chatRooms).get();
|
||||||
|
return Future.wait(
|
||||||
|
localRoomsData.map((row) async {
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(row.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
return SnChatRoom(
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
description: row.description,
|
||||||
|
type: row.type,
|
||||||
|
isPublic: row.isPublic!,
|
||||||
|
isCommunity: row.isCommunity!,
|
||||||
|
picture:
|
||||||
|
row.picture != null ? SnCloudFile.fromJson(row.picture!) : null,
|
||||||
|
background:
|
||||||
|
row.background != null
|
||||||
|
? SnCloudFile.fromJson(row.background!)
|
||||||
|
: null,
|
||||||
|
realmId: row.realmId,
|
||||||
|
accountId: row.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: row.createdAt,
|
||||||
|
updatedAt: row.updatedAt,
|
||||||
|
deletedAt: row.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class ChatRoomNotifier extends _$ChatRoomNotifier {
|
||||||
|
@override
|
||||||
|
Future<SnChatRoom?> build(String? identifier) async {
|
||||||
|
if (identifier == null) return null;
|
||||||
|
final db = ref.watch(databaseProvider);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to get from local database first
|
||||||
|
final localRoomData =
|
||||||
|
await (db.select(db.chatRooms)
|
||||||
|
..where((r) => r.id.equals(identifier))).getSingleOrNull();
|
||||||
|
|
||||||
|
if (localRoomData != null) {
|
||||||
|
// Fetch members for this room
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(localRoomData.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final localRoom = SnChatRoom(
|
||||||
|
id: localRoomData.id,
|
||||||
|
name: localRoomData.name,
|
||||||
|
description: localRoomData.description,
|
||||||
|
type: localRoomData.type,
|
||||||
|
isPublic: localRoomData.isPublic!,
|
||||||
|
isCommunity: localRoomData.isCommunity!,
|
||||||
|
picture:
|
||||||
|
localRoomData.picture != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.picture!)
|
||||||
|
: null,
|
||||||
|
background:
|
||||||
|
localRoomData.background != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.background!)
|
||||||
|
: null,
|
||||||
|
realmId: localRoomData.realmId,
|
||||||
|
accountId: localRoomData.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: localRoomData.createdAt,
|
||||||
|
updatedAt: localRoomData.updatedAt,
|
||||||
|
deletedAt: localRoomData.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat/$identifier');
|
||||||
|
final remoteRoom = SnChatRoom.fromJson(resp.data);
|
||||||
|
// Update state with fresh data directly without saving to DB
|
||||||
|
// DB will be updated by ChatRoomJoinedNotifier's full sync
|
||||||
|
state = AsyncData(remoteRoom);
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localRoom;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
|
try {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat/$identifier');
|
||||||
|
final room = SnChatRoom.fromJson(resp.data);
|
||||||
|
await db.saveChatRooms([room]);
|
||||||
|
return room;
|
||||||
|
} catch (err) {
|
||||||
|
if (err is DioException && err.response?.statusCode == 404) {
|
||||||
|
return null; // Chat room not found
|
||||||
|
}
|
||||||
|
rethrow; // Rethrow other errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
||||||
|
@override
|
||||||
|
Future<SnChatMember?> build(String? identifier) async {
|
||||||
|
if (identifier == null) return null;
|
||||||
|
final db = ref.watch(databaseProvider);
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to get from local database first
|
||||||
|
if (userInfo.value != null) {
|
||||||
|
final localMemberData =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(identifier))
|
||||||
|
..where((m) => m.accountId.equals(userInfo.value!.id)))
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (localMemberData != null) {
|
||||||
|
final account = SnAccount.fromJson(localMemberData.account);
|
||||||
|
final localMember = SnChatMember(
|
||||||
|
id: localMemberData.id,
|
||||||
|
chatRoomId: localMemberData.chatRoomId,
|
||||||
|
accountId: localMemberData.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: localMemberData.nick,
|
||||||
|
notify: localMemberData.notify,
|
||||||
|
joinedAt: localMemberData.joinedAt,
|
||||||
|
breakUntil: localMemberData.breakUntil,
|
||||||
|
timeoutUntil: localMemberData.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: localMemberData.createdAt,
|
||||||
|
updatedAt: localMemberData.updatedAt,
|
||||||
|
deletedAt: localMemberData.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get(
|
||||||
|
'/sphere/chat/$identifier/members/me',
|
||||||
|
);
|
||||||
|
final remoteMember = SnChatMember.fromJson(resp.data);
|
||||||
|
await db.saveMember(remoteMember);
|
||||||
|
// Update state with fresh data
|
||||||
|
if (userInfo.value != null) {
|
||||||
|
state = AsyncData(
|
||||||
|
await _buildMemberFromDb(db, identifier, userInfo.value!.id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localMember;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
|
try {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
||||||
|
final member = SnChatMember.fromJson(resp.data);
|
||||||
|
await db.saveMember(member);
|
||||||
|
return member;
|
||||||
|
} catch (err) {
|
||||||
|
if (err is DioException && err.response?.statusCode == 404) {
|
||||||
|
return null; // Chat member not found
|
||||||
|
}
|
||||||
|
rethrow; // Rethrow other errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SnChatMember?> _buildMemberFromDb(
|
||||||
|
AppDatabase db,
|
||||||
|
String identifier,
|
||||||
|
String accountId,
|
||||||
|
) async {
|
||||||
|
final localMemberData =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(identifier))
|
||||||
|
..where((m) => m.accountId.equals(accountId)))
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (localMemberData == null) return null;
|
||||||
|
|
||||||
|
final account = SnAccount.fromJson(localMemberData.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: localMemberData.id,
|
||||||
|
chatRoomId: localMemberData.chatRoomId,
|
||||||
|
accountId: localMemberData.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: localMemberData.nick,
|
||||||
|
notify: localMemberData.notify,
|
||||||
|
joinedAt: localMemberData.joinedAt,
|
||||||
|
breakUntil: localMemberData.breakUntil,
|
||||||
|
timeoutUntil: localMemberData.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: localMemberData.createdAt,
|
||||||
|
updatedAt: localMemberData.updatedAt,
|
||||||
|
deletedAt: localMemberData.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat/invites');
|
||||||
|
return resp.data
|
||||||
|
.map((e) => SnChatMember.fromJson(e))
|
||||||
|
.cast<SnChatMember>()
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
355
lib/pods/chat/chat_room.g.dart
Normal file
355
lib/pods/chat/chat_room.g.dart
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'chat_room.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
||||||
|
|
||||||
|
/// See also [chatroomInvites].
|
||||||
|
@ProviderFor(chatroomInvites)
|
||||||
|
final chatroomInvitesProvider =
|
||||||
|
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
|
||||||
|
chatroomInvites,
|
||||||
|
name: r'chatroomInvitesProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatroomInvitesHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef ChatroomInvitesRef = AutoDisposeFutureProviderRef<List<SnChatMember>>;
|
||||||
|
String _$chatRoomJoinedNotifierHash() =>
|
||||||
|
r'c8092225ba0d9c08b2b5bca6f800f1877303b4ff';
|
||||||
|
|
||||||
|
/// See also [ChatRoomJoinedNotifier].
|
||||||
|
@ProviderFor(ChatRoomJoinedNotifier)
|
||||||
|
final chatRoomJoinedNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
||||||
|
ChatRoomJoinedNotifier,
|
||||||
|
List<SnChatRoom>
|
||||||
|
>.internal(
|
||||||
|
ChatRoomJoinedNotifier.new,
|
||||||
|
name: r'chatRoomJoinedNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatRoomJoinedNotifierHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$ChatRoomJoinedNotifier = AutoDisposeAsyncNotifier<List<SnChatRoom>>;
|
||||||
|
String _$chatRoomNotifierHash() => r'1e6391e2ab4eeb114fa001aaa6b06ab2bd646f38';
|
||||||
|
|
||||||
|
/// 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 _$ChatRoomNotifier
|
||||||
|
extends BuildlessAutoDisposeAsyncNotifier<SnChatRoom?> {
|
||||||
|
late final String? identifier;
|
||||||
|
|
||||||
|
FutureOr<SnChatRoom?> build(String? identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
@ProviderFor(ChatRoomNotifier)
|
||||||
|
const chatRoomNotifierProvider = ChatRoomNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
class ChatRoomNotifierFamily extends Family<AsyncValue<SnChatRoom?>> {
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
const ChatRoomNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
ChatRoomNotifierProvider call(String? identifier) {
|
||||||
|
return ChatRoomNotifierProvider(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChatRoomNotifierProvider getProviderOverride(
|
||||||
|
covariant ChatRoomNotifierProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'chatRoomNotifierProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
class ChatRoomNotifierProvider
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderImpl<ChatRoomNotifier, SnChatRoom?> {
|
||||||
|
/// See also [ChatRoomNotifier].
|
||||||
|
ChatRoomNotifierProvider(String? identifier)
|
||||||
|
: this._internal(
|
||||||
|
() => ChatRoomNotifier()..identifier = identifier,
|
||||||
|
from: chatRoomNotifierProvider,
|
||||||
|
name: r'chatRoomNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatRoomNotifierHash,
|
||||||
|
dependencies: ChatRoomNotifierFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
ChatRoomNotifierFamily._allTransitiveDependencies,
|
||||||
|
identifier: identifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
ChatRoomNotifierProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.identifier,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String? identifier;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<SnChatRoom?> runNotifierBuild(covariant ChatRoomNotifier notifier) {
|
||||||
|
return notifier.build(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(ChatRoomNotifier Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: ChatRoomNotifierProvider._internal(
|
||||||
|
() => create()..identifier = identifier,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
identifier: identifier,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
|
||||||
|
createElement() {
|
||||||
|
return _ChatRoomNotifierProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is ChatRoomNotifierProvider && other.identifier == identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, identifier.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin ChatRoomNotifierRef on AutoDisposeAsyncNotifierProviderRef<SnChatRoom?> {
|
||||||
|
/// The parameter `identifier` of this provider.
|
||||||
|
String? get identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatRoomNotifierProviderElement
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
|
||||||
|
with ChatRoomNotifierRef {
|
||||||
|
_ChatRoomNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get identifier => (origin as ChatRoomNotifierProvider).identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$chatRoomIdentityNotifierHash() =>
|
||||||
|
r'27c17d55366d39be81d7209837e5c01f80a68a24';
|
||||||
|
|
||||||
|
abstract class _$ChatRoomIdentityNotifier
|
||||||
|
extends BuildlessAutoDisposeAsyncNotifier<SnChatMember?> {
|
||||||
|
late final String? identifier;
|
||||||
|
|
||||||
|
FutureOr<SnChatMember?> build(String? identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
@ProviderFor(ChatRoomIdentityNotifier)
|
||||||
|
const chatRoomIdentityNotifierProvider = ChatRoomIdentityNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
class ChatRoomIdentityNotifierFamily extends Family<AsyncValue<SnChatMember?>> {
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
const ChatRoomIdentityNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
ChatRoomIdentityNotifierProvider call(String? identifier) {
|
||||||
|
return ChatRoomIdentityNotifierProvider(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChatRoomIdentityNotifierProvider getProviderOverride(
|
||||||
|
covariant ChatRoomIdentityNotifierProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'chatRoomIdentityNotifierProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
class ChatRoomIdentityNotifierProvider
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderImpl<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
> {
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
ChatRoomIdentityNotifierProvider(String? identifier)
|
||||||
|
: this._internal(
|
||||||
|
() => ChatRoomIdentityNotifier()..identifier = identifier,
|
||||||
|
from: chatRoomIdentityNotifierProvider,
|
||||||
|
name: r'chatRoomIdentityNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatRoomIdentityNotifierHash,
|
||||||
|
dependencies: ChatRoomIdentityNotifierFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
ChatRoomIdentityNotifierFamily._allTransitiveDependencies,
|
||||||
|
identifier: identifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
ChatRoomIdentityNotifierProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.identifier,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String? identifier;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<SnChatMember?> runNotifierBuild(
|
||||||
|
covariant ChatRoomIdentityNotifier notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(ChatRoomIdentityNotifier Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: ChatRoomIdentityNotifierProvider._internal(
|
||||||
|
() => create()..identifier = identifier,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
identifier: identifier,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
>
|
||||||
|
createElement() {
|
||||||
|
return _ChatRoomIdentityNotifierProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is ChatRoomIdentityNotifierProvider &&
|
||||||
|
other.identifier == identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, identifier.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin ChatRoomIdentityNotifierRef
|
||||||
|
on AutoDisposeAsyncNotifierProviderRef<SnChatMember?> {
|
||||||
|
/// The parameter `identifier` of this provider.
|
||||||
|
String? get identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatRoomIdentityNotifierProviderElement
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
>
|
||||||
|
with ChatRoomIdentityNotifierRef {
|
||||||
|
_ChatRoomIdentityNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get identifier =>
|
||||||
|
(origin as ChatRoomIdentityNotifierProvider).identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,5 +0,0 @@
|
|||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
|
||||||
|
|
||||||
final isSyncingProvider = StateProvider.autoDispose<bool>((ref) => false);
|
|
||||||
|
|
||||||
final flashingMessagesProvider = StateProvider<Set<String>>((ref) => {});
|
|
||||||
@@ -3,10 +3,10 @@ import "dart:convert";
|
|||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:island/models/chat.dart";
|
import "package:island/models/chat.dart";
|
||||||
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/pods/lifecycle.dart";
|
import "package:island/pods/lifecycle.dart";
|
||||||
import "package:island/pods/chat/messages_notifier.dart";
|
import "package:island/pods/chat/messages_notifier.dart";
|
||||||
import "package:island/pods/websocket.dart";
|
import "package:island/pods/websocket.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
|
||||||
import "package:island/widgets/chat/call_button.dart";
|
import "package:island/widgets/chat/call_button.dart";
|
||||||
import "package:riverpod_annotation/riverpod_annotation.dart";
|
import "package:riverpod_annotation/riverpod_annotation.dart";
|
||||||
|
|
||||||
@@ -16,10 +16,9 @@ final currentSubscribedChatIdProvider = StateProvider<String?>((ref) => null);
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||||
late final String _roomId;
|
late SnChatRoom _chatRoom;
|
||||||
late final SnChatRoom _chatRoom;
|
late SnChatMember _chatIdentity;
|
||||||
late final SnChatMember _chatIdentity;
|
late MessagesNotifier _messagesNotifier;
|
||||||
late final MessagesNotifier _messagesNotifier;
|
|
||||||
|
|
||||||
final List<SnChatMember> _typingStatuses = [];
|
final List<SnChatMember> _typingStatuses = [];
|
||||||
Timer? _typingCleanupTimer;
|
Timer? _typingCleanupTimer;
|
||||||
@@ -29,10 +28,11 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<SnChatMember> build(String roomId) {
|
List<SnChatMember> build(String roomId) {
|
||||||
_roomId = roomId;
|
|
||||||
final ws = ref.watch(websocketProvider);
|
final ws = ref.watch(websocketProvider);
|
||||||
final chatRoomAsync = ref.watch(chatroomProvider(roomId));
|
final chatRoomAsync = ref.watch(ChatRoomNotifierProvider(roomId));
|
||||||
final chatIdentityAsync = ref.watch(chatroomIdentityProvider(roomId));
|
final chatIdentityAsync = ref.watch(
|
||||||
|
ChatRoomIdentityNotifierProvider(roomId),
|
||||||
|
);
|
||||||
_messagesNotifier = ref.watch(messagesNotifierProvider(roomId).notifier);
|
_messagesNotifier = ref.watch(messagesNotifierProvider(roomId).notifier);
|
||||||
|
|
||||||
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
||||||
@@ -199,7 +199,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.read',
|
type: 'messages.read',
|
||||||
data: {'chat_room_id': _roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'sphere',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -216,7 +216,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.typing',
|
type: 'messages.typing',
|
||||||
data: {'chat_room_id': _roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'sphere',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'chat_subscribe.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatSubscribeNotifierHash() =>
|
String _$chatSubscribeNotifierHash() =>
|
||||||
r'c605e0c9c45df64e5ba7b65f8de9b47bde8e2b3b';
|
r'beec1ddf2e13f6d5af8a08c2c81eff740ae9b986';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class ChatUnreadCountNotifier extends _$ChatUnreadCountNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@Riverpod(keepAlive: true)
|
||||||
class ChatSummary extends _$ChatSummary {
|
class ChatSummary extends _$ChatSummary {
|
||||||
@override
|
@override
|
||||||
Future<Map<String, SnChatSummary>> build() async {
|
Future<Map<String, SnChatSummary>> build() async {
|
||||||
|
|||||||
@@ -24,22 +24,22 @@ final chatUnreadCountNotifierProvider =
|
|||||||
);
|
);
|
||||||
|
|
||||||
typedef _$ChatUnreadCountNotifier = AutoDisposeAsyncNotifier<int>;
|
typedef _$ChatUnreadCountNotifier = AutoDisposeAsyncNotifier<int>;
|
||||||
String _$chatSummaryHash() => r'8479ef53cfb0b698b800d0117d04774b6f78b3cc';
|
String _$chatSummaryHash() => r'78d927d40cded9d7adbc20bd6f457fdf3c852632';
|
||||||
|
|
||||||
/// See also [ChatSummary].
|
/// See also [ChatSummary].
|
||||||
@ProviderFor(ChatSummary)
|
@ProviderFor(ChatSummary)
|
||||||
final chatSummaryProvider = AutoDisposeAsyncNotifierProvider<
|
final chatSummaryProvider =
|
||||||
ChatSummary,
|
AsyncNotifierProvider<ChatSummary, Map<String, SnChatSummary>>.internal(
|
||||||
Map<String, SnChatSummary>
|
|
||||||
>.internal(
|
|
||||||
ChatSummary.new,
|
ChatSummary.new,
|
||||||
name: r'chatSummaryProvider',
|
name: r'chatSummaryProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product') ? null : _$chatSummaryHash,
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatSummaryHash,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$ChatSummary = AutoDisposeAsyncNotifier<Map<String, SnChatSummary>>;
|
typedef _$ChatSummary = AsyncNotifier<Map<String, SnChatSummary>>;
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import "package:island/models/chat.dart";
|
|||||||
import "package:island/models/file.dart";
|
import "package:island/models/file.dart";
|
||||||
import "package:island/models/poll.dart";
|
import "package:island/models/poll.dart";
|
||||||
import "package:island/models/wallet.dart";
|
import "package:island/models/wallet.dart";
|
||||||
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/pods/database.dart";
|
import "package:island/pods/database.dart";
|
||||||
import "package:island/pods/lifecycle.dart";
|
import "package:island/pods/lifecycle.dart";
|
||||||
import "package:island/pods/network.dart";
|
import "package:island/pods/network.dart";
|
||||||
@@ -19,18 +20,16 @@ import "package:island/talker.dart";
|
|||||||
import "package:island/widgets/alert.dart";
|
import "package:island/widgets/alert.dart";
|
||||||
import "package:riverpod_annotation/riverpod_annotation.dart";
|
import "package:riverpod_annotation/riverpod_annotation.dart";
|
||||||
import "package:uuid/uuid.dart";
|
import "package:uuid/uuid.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
|
||||||
import "package:island/pods/chat/chat_rooms.dart";
|
|
||||||
import "package:island/screens/account/profile.dart";
|
import "package:island/screens/account/profile.dart";
|
||||||
|
|
||||||
part 'messages_notifier.g.dart';
|
part 'messages_notifier.g.dart';
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class MessagesNotifier extends _$MessagesNotifier {
|
class MessagesNotifier extends _$MessagesNotifier {
|
||||||
late final Dio _apiClient;
|
late Dio _apiClient;
|
||||||
late final AppDatabase _database;
|
late AppDatabase _database;
|
||||||
late final SnChatRoom _room;
|
late SnChatRoom _room;
|
||||||
late final SnChatMember _identity;
|
late SnChatMember _identity;
|
||||||
|
|
||||||
final Map<String, LocalChatMessage> _pendingMessages = {};
|
final Map<String, LocalChatMessage> _pendingMessages = {};
|
||||||
final Map<String, Map<int, double?>> _fileUploadProgress = {};
|
final Map<String, Map<int, double?>> _fileUploadProgress = {};
|
||||||
@@ -39,7 +38,6 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
bool? _withLinks;
|
bool? _withLinks;
|
||||||
bool? _withAttachments;
|
bool? _withAttachments;
|
||||||
|
|
||||||
late final String _roomId;
|
|
||||||
static const int _pageSize = 20;
|
static const int _pageSize = 20;
|
||||||
bool _hasMore = true;
|
bool _hasMore = true;
|
||||||
bool _isSyncing = false;
|
bool _isSyncing = false;
|
||||||
@@ -48,15 +46,16 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
bool _allRemoteMessagesFetched = false;
|
bool _allRemoteMessagesFetched = false;
|
||||||
DateTime? _lastPauseTime;
|
DateTime? _lastPauseTime;
|
||||||
|
|
||||||
late final Future<SnAccount?> Function(String) _fetchAccount;
|
late Future<SnAccount?> Function(String) _fetchAccount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<List<LocalChatMessage>> build(String roomId) async {
|
FutureOr<List<LocalChatMessage>> build(String roomId) async {
|
||||||
_roomId = roomId;
|
|
||||||
_apiClient = ref.watch(apiClientProvider);
|
_apiClient = ref.watch(apiClientProvider);
|
||||||
_database = ref.watch(databaseProvider);
|
_database = ref.watch(databaseProvider);
|
||||||
final room = await ref.watch(chatroomProvider(roomId).future);
|
final room = await ref.watch(ChatRoomNotifierProvider(roomId).future);
|
||||||
final identity = await ref.watch(chatroomIdentityProvider(roomId).future);
|
final identity = await ref.watch(
|
||||||
|
ChatRoomIdentityNotifierProvider(roomId).future,
|
||||||
|
);
|
||||||
|
|
||||||
// Initialize fetch account method for corrupted data recovery
|
// Initialize fetch account method for corrupted data recovery
|
||||||
_fetchAccount = (String accountId) async {
|
_fetchAccount = (String accountId) async {
|
||||||
@@ -144,14 +143,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (searchQuery != null && searchQuery.isNotEmpty) {
|
if (searchQuery != null && searchQuery.isNotEmpty) {
|
||||||
dbMessages = await _database.searchMessages(
|
dbMessages = await _database.searchMessages(
|
||||||
_roomId,
|
roomId,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
withAttachments: withAttachments,
|
withAttachments: withAttachments,
|
||||||
fetchAccount: _fetchAccount,
|
fetchAccount: _fetchAccount,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
||||||
_roomId,
|
roomId,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: take,
|
limit: take,
|
||||||
);
|
);
|
||||||
@@ -194,9 +193,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom =
|
||||||
_pendingMessages.values
|
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||||
.where((msg) => msg.roomId == _roomId)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages); // Use the helper function
|
_sortMessages(allMessages); // Use the helper function
|
||||||
@@ -221,7 +218,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}) async {
|
}) async {
|
||||||
talker.log('Getting all messages for jump from offset $offset, take $take');
|
talker.log('Getting all messages for jump from offset $offset, take $take');
|
||||||
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
||||||
_roomId,
|
roomId,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: take,
|
limit: take,
|
||||||
);
|
);
|
||||||
@@ -245,9 +242,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom =
|
||||||
_pendingMessages.values
|
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||||
.where((msg) => msg.roomId == _roomId)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages);
|
_sortMessages(allMessages);
|
||||||
@@ -272,7 +267,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
talker.log('Fetching messages from API, offset $offset, take $take');
|
talker.log('Fetching messages from API, offset $offset, take $take');
|
||||||
if (_totalCount == null) {
|
if (_totalCount == null) {
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages',
|
'/sphere/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': 0, 'take': 1},
|
queryParameters: {'offset': 0, 'take': 1},
|
||||||
);
|
);
|
||||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||||
@@ -284,7 +279,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages',
|
'/sphere/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': offset, 'take': take},
|
queryParameters: {'offset': offset, 'take': take},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -546,7 +541,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final mockMessage = SnChatMessage(
|
final mockMessage = SnChatMessage(
|
||||||
id: 'pending_$nonce',
|
id: 'pending_$nonce',
|
||||||
chatRoomId: _roomId,
|
chatRoomId: roomId,
|
||||||
senderId: _identity.id,
|
senderId: _identity.id,
|
||||||
content: content,
|
content: content,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
@@ -590,8 +585,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final response = await _apiClient.request(
|
final response = await _apiClient.request(
|
||||||
editingTo == null
|
editingTo == null
|
||||||
? '/sphere/chat/$_roomId/messages'
|
? '/sphere/chat/$roomId/messages'
|
||||||
: '/sphere/chat/$_roomId/messages/${editingTo.id}',
|
: '/sphere/chat/$roomId/messages/${editingTo.id}',
|
||||||
data: {
|
data: {
|
||||||
'content': content,
|
'content': content,
|
||||||
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
||||||
@@ -731,7 +726,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> receiveMessage(SnChatMessage remoteMessage) async {
|
Future<void> receiveMessage(SnChatMessage remoteMessage) async {
|
||||||
if (remoteMessage.chatRoomId != _roomId) return;
|
if (remoteMessage.chatRoomId != roomId) return;
|
||||||
|
|
||||||
// Block message receiving during jumps to prevent list resets
|
// Block message receiving during jumps to prevent list resets
|
||||||
if (_isJumping) {
|
if (_isJumping) {
|
||||||
@@ -783,7 +778,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> receiveMessageUpdate(SnChatMessage remoteMessage) async {
|
Future<void> receiveMessageUpdate(SnChatMessage remoteMessage) async {
|
||||||
if (remoteMessage.chatRoomId != _roomId) return;
|
if (remoteMessage.chatRoomId != roomId) return;
|
||||||
|
|
||||||
// Block message updates during jumps to prevent list resets
|
// Block message updates during jumps to prevent list resets
|
||||||
if (_isJumping) {
|
if (_isJumping) {
|
||||||
@@ -883,7 +878,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _apiClient.delete('/sphere/chat/$_roomId/messages/$messageId');
|
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
|
||||||
await receiveMessageDeletion(messageId);
|
await receiveMessageDeletion(messageId);
|
||||||
} catch (err, stackTrace) {
|
} catch (err, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
@@ -991,7 +986,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages/$messageId',
|
'/sphere/chat/$roomId/messages/$messageId',
|
||||||
);
|
);
|
||||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||||
final message = LocalChatMessage.fromRemoteMessage(
|
final message = LocalChatMessage.fromRemoteMessage(
|
||||||
@@ -1048,7 +1043,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
final query = _database.customSelect(
|
final query = _database.customSelect(
|
||||||
'SELECT COUNT(*) as count FROM chat_messages WHERE room_id = ? AND created_at > ?',
|
'SELECT COUNT(*) as count FROM chat_messages WHERE room_id = ? AND created_at > ?',
|
||||||
variables: [
|
variables: [
|
||||||
Variable.withString(_roomId),
|
Variable.withString(roomId),
|
||||||
Variable.withDateTime(message.createdAt),
|
Variable.withDateTime(message.createdAt),
|
||||||
],
|
],
|
||||||
readsFrom: {_database.chatMessages},
|
readsFrom: {_database.chatMessages},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'messages_notifier.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$messagesNotifierHash() => r'27ce32c54e317a04e1d554ed4a70a24e4503fdd1';
|
String _$messagesNotifierHash() => r'd76d799494b06fac2adc42d94b7ecd7b8d68c352';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|||||||
@@ -2,14 +2,24 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/file_list_item.dart';
|
import 'package:island/models/file_list_item.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
|
||||||
|
|
||||||
part 'file_list.g.dart';
|
part 'file_list.g.dart';
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class CloudFileListNotifier extends _$CloudFileListNotifier
|
Future<Map<String, dynamic>?> billingUsage(Ref ref) async {
|
||||||
with CursorPagingNotifierMixin<FileListItem> {
|
final client = ref.read(apiClientProvider);
|
||||||
|
final response = await client.get('/drive/billing/usage');
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
final indexedCloudFileListNotifierProvider = AsyncNotifierProvider(
|
||||||
|
IndexedCloudFileListNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
|
class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||||
|
with AsyncPaginationController<FileListItem> {
|
||||||
String _currentPath = '/';
|
String _currentPath = '/';
|
||||||
String? _poolId;
|
String? _poolId;
|
||||||
String? _query;
|
String? _query;
|
||||||
@@ -42,12 +52,7 @@ class CloudFileListNotifier extends _$CloudFileListNotifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<FileListItem>> build() => fetch(cursor: null);
|
Future<List<FileListItem>> fetch() async {
|
||||||
|
|
||||||
@override
|
|
||||||
Future<CursorPagingData<FileListItem>> fetch({
|
|
||||||
required String? cursor,
|
|
||||||
}) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
|
|
||||||
final queryParameters = <String, String>{'path': _currentPath};
|
final queryParameters = <String, String>{'path': _currentPath};
|
||||||
@@ -83,21 +88,16 @@ class CloudFileListNotifier extends _$CloudFileListNotifier
|
|||||||
...files.map((file) => FileListItem.file(file)),
|
...files.map((file) => FileListItem.file(file)),
|
||||||
];
|
];
|
||||||
|
|
||||||
// The new API returns all files in the path, no pagination
|
return items;
|
||||||
return CursorPagingData(items: items, hasMore: false, nextCursor: null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
final unindexedFileListNotifierProvider = AsyncNotifierProvider(
|
||||||
Future<Map<String, dynamic>?> billingUsage(Ref ref) async {
|
UnindexedFileListNotifier.new,
|
||||||
final client = ref.read(apiClientProvider);
|
);
|
||||||
final response = await client.get('/drive/billing/usage');
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@riverpod
|
class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||||
class UnindexedFileListNotifier extends _$UnindexedFileListNotifier
|
with AsyncPaginationController<FileListItem> {
|
||||||
with CursorPagingNotifierMixin<FileListItem> {
|
|
||||||
String? _poolId;
|
String? _poolId;
|
||||||
bool _recycled = false;
|
bool _recycled = false;
|
||||||
String? _query;
|
String? _query;
|
||||||
@@ -129,21 +129,15 @@ class UnindexedFileListNotifier extends _$UnindexedFileListNotifier
|
|||||||
ref.invalidateSelf();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
static const int pageSize = 20;
|
||||||
Future<CursorPagingData<FileListItem>> build() => fetch(cursor: null);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<FileListItem>> fetch({
|
Future<List<FileListItem>> fetch() async {
|
||||||
required String? cursor,
|
|
||||||
}) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
|
|
||||||
final offset = cursor != null ? int.tryParse(cursor) ?? 0 : 0;
|
|
||||||
const take = 50; // Default page size
|
|
||||||
|
|
||||||
final queryParameters = <String, String>{
|
final queryParameters = <String, String>{
|
||||||
'take': take.toString(),
|
'take': pageSize.toString(),
|
||||||
'offset': offset.toString(),
|
'offset': fetchedCount.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_poolId != null) {
|
if (_poolId != null) {
|
||||||
@@ -169,7 +163,7 @@ class UnindexedFileListNotifier extends _$UnindexedFileListNotifier
|
|||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
);
|
);
|
||||||
|
|
||||||
final total = int.tryParse(response.headers.value('x-total') ?? '0') ?? 0;
|
totalCount = int.tryParse(response.headers.value('x-total') ?? '0') ?? 0;
|
||||||
|
|
||||||
final List<SnCloudFile> files =
|
final List<SnCloudFile> files =
|
||||||
(response.data as List)
|
(response.data as List)
|
||||||
@@ -179,14 +173,7 @@ class UnindexedFileListNotifier extends _$UnindexedFileListNotifier
|
|||||||
final List<FileListItem> items =
|
final List<FileListItem> items =
|
||||||
files.map((file) => FileListItem.unindexedFile(file)).toList();
|
files.map((file) => FileListItem.unindexedFile(file)).toList();
|
||||||
|
|
||||||
final hasMore = offset + take < total;
|
return items;
|
||||||
final nextCursor = hasMore ? (offset + take).toString() : null;
|
|
||||||
|
|
||||||
return CursorPagingData(
|
|
||||||
items: items,
|
|
||||||
hasMore: hasMore,
|
|
||||||
nextCursor: nextCursor,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,47 +44,5 @@ final billingQuotaProvider =
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>;
|
typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>;
|
||||||
String _$cloudFileListNotifierHash() =>
|
|
||||||
r'533dfa86f920b60cf7491fb4aeb95ece19e428af';
|
|
||||||
|
|
||||||
/// See also [CloudFileListNotifier].
|
|
||||||
@ProviderFor(CloudFileListNotifier)
|
|
||||||
final cloudFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
|
||||||
CloudFileListNotifier,
|
|
||||||
CursorPagingData<FileListItem>
|
|
||||||
>.internal(
|
|
||||||
CloudFileListNotifier.new,
|
|
||||||
name: r'cloudFileListNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$cloudFileListNotifierHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$CloudFileListNotifier =
|
|
||||||
AutoDisposeAsyncNotifier<CursorPagingData<FileListItem>>;
|
|
||||||
String _$unindexedFileListNotifierHash() =>
|
|
||||||
r'afa487d7b956b71b21ca1b073a01364a34ede1d5';
|
|
||||||
|
|
||||||
/// See also [UnindexedFileListNotifier].
|
|
||||||
@ProviderFor(UnindexedFileListNotifier)
|
|
||||||
final unindexedFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
|
||||||
UnindexedFileListNotifier,
|
|
||||||
CursorPagingData<FileListItem>
|
|
||||||
>.internal(
|
|
||||||
UnindexedFileListNotifier.new,
|
|
||||||
name: r'unindexedFileListNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$unindexedFileListNotifierHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$UnindexedFileListNotifier =
|
|
||||||
AutoDisposeAsyncNotifier<CursorPagingData<FileListItem>>;
|
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|||||||
84
lib/pods/paging.dart
Normal file
84
lib/pods/paging.dart
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
abstract class PaginationController<T> {
|
||||||
|
int? get totalCount;
|
||||||
|
int get fetchedCount;
|
||||||
|
|
||||||
|
bool get fetchedAll;
|
||||||
|
|
||||||
|
FutureOr<List<T>> fetch();
|
||||||
|
|
||||||
|
Future<void> refresh();
|
||||||
|
|
||||||
|
Future<void> fetchFurther();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PaginationFiltered<F> {
|
||||||
|
late F currentFilter;
|
||||||
|
|
||||||
|
Future<void> applyFilter(F filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin AsyncPaginationController<T> on AsyncNotifier<List<T>>
|
||||||
|
implements PaginationController<T> {
|
||||||
|
@override
|
||||||
|
int? totalCount;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int fetchedCount = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get fetchedAll => totalCount != null && fetchedCount >= totalCount!;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<List<T>> build() async => fetch();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> refresh() async {
|
||||||
|
totalCount = null;
|
||||||
|
fetchedCount = 0;
|
||||||
|
state = AsyncData<List<T>>([]);
|
||||||
|
|
||||||
|
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||||
|
return await fetch();
|
||||||
|
});
|
||||||
|
state = newState;
|
||||||
|
fetchedCount = newState.value?.length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> fetchFurther() async {
|
||||||
|
if (fetchedAll) return;
|
||||||
|
|
||||||
|
state = AsyncLoading<List<T>>();
|
||||||
|
|
||||||
|
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||||
|
final elements = await fetch();
|
||||||
|
return [...?state.valueOrNull, ...elements];
|
||||||
|
});
|
||||||
|
|
||||||
|
state = newState;
|
||||||
|
fetchedCount = newState.value?.length ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin AsyncPaginationFilter<F, T> on AsyncPaginationController<T>
|
||||||
|
implements PaginationFiltered<F> {
|
||||||
|
@override
|
||||||
|
Future<void> applyFilter(F filter) async {
|
||||||
|
if (currentFilter == filter) return;
|
||||||
|
// Reset the data
|
||||||
|
totalCount = null;
|
||||||
|
fetchedCount = 0;
|
||||||
|
currentFilter = filter;
|
||||||
|
|
||||||
|
state = AsyncData<List<T>>([]);
|
||||||
|
|
||||||
|
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||||
|
return await fetch();
|
||||||
|
});
|
||||||
|
state = newState;
|
||||||
|
}
|
||||||
|
}
|
||||||
65
lib/pods/timeline.dart
Normal file
65
lib/pods/timeline.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/activity.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
|
|
||||||
|
final activityListNotifierProvider =
|
||||||
|
AsyncNotifierProvider<ActivityListNotifier, List<SnTimelineEvent>>(
|
||||||
|
ActivityListNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
|
class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
|
||||||
|
with
|
||||||
|
AsyncPaginationController<SnTimelineEvent>,
|
||||||
|
AsyncPaginationFilter<String?, SnTimelineEvent> {
|
||||||
|
static const int pageSize = 20;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? currentFilter;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<SnTimelineEvent>> fetch() async {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
|
||||||
|
final cursor =
|
||||||
|
state.valueOrNull?.lastOrNull?.createdAt.toUtc().toIso8601String();
|
||||||
|
|
||||||
|
final queryParameters = {
|
||||||
|
if (cursor != null) 'cursor': cursor,
|
||||||
|
'take': pageSize,
|
||||||
|
if (currentFilter != null) 'filter': currentFilter,
|
||||||
|
if (kDebugMode)
|
||||||
|
'debugInclude': 'realms,publishers,articles,shuffledPosts',
|
||||||
|
};
|
||||||
|
|
||||||
|
final response = await client.get(
|
||||||
|
'/sphere/timeline',
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<SnTimelineEvent> items =
|
||||||
|
(response.data as List)
|
||||||
|
.map((e) => SnTimelineEvent.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final hasMore = (items.firstOrNull?.type ?? 'empty') != 'empty';
|
||||||
|
|
||||||
|
totalCount =
|
||||||
|
(state.valueOrNull?.length ?? 0) +
|
||||||
|
items.length +
|
||||||
|
(hasMore ? pageSize : 0);
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateOne(int index, SnTimelineEvent activity) {
|
||||||
|
final currentState = state.valueOrNull;
|
||||||
|
if (currentState == null) return;
|
||||||
|
|
||||||
|
final updatedItems = [...currentState];
|
||||||
|
updatedItems[index] = activity;
|
||||||
|
|
||||||
|
state = AsyncData(updatedItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
|
import 'package:island/services/time.dart';
|
||||||
|
import 'package:island/widgets/paging/pagination_list.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.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:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
part 'credits.g.dart';
|
part 'credits.g.dart';
|
||||||
@@ -21,40 +23,35 @@ Future<double> socialCredits(Ref ref) async {
|
|||||||
return response.data?.toDouble() ?? 0.0;
|
return response.data?.toDouble() ?? 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
final socialCreditHistoryNotifierProvider = AsyncNotifierProvider(
|
||||||
class SocialCreditHistoryNotifier extends _$SocialCreditHistoryNotifier
|
SocialCreditHistoryNotifier.new,
|
||||||
with CursorPagingNotifierMixin<SnSocialCreditRecord> {
|
);
|
||||||
static const int _pageSize = 20;
|
|
||||||
|
class SocialCreditHistoryNotifier
|
||||||
|
extends AsyncNotifier<List<SnSocialCreditRecord>>
|
||||||
|
with AsyncPaginationController<SnSocialCreditRecord> {
|
||||||
|
static const int pageSize = 20;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnSocialCreditRecord>> build() => fetch(cursor: null);
|
Future<List<SnSocialCreditRecord>> fetch() async {
|
||||||
|
|
||||||
@override
|
|
||||||
Future<CursorPagingData<SnSocialCreditRecord>> fetch({
|
|
||||||
required String? cursor,
|
|
||||||
}) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
|
||||||
|
|
||||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
final queryParams = {'offset': fetchedCount.toString(), 'take': pageSize};
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/pass/accounts/me/credits/history',
|
'/pass/accounts/me/credits/history',
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
);
|
);
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
|
||||||
final List<dynamic> data = response.data;
|
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
|
|
||||||
final records =
|
final records =
|
||||||
data.map((json) => SnSocialCreditRecord.fromJson(json)).toList();
|
response.data
|
||||||
|
.map((json) => SnSocialCreditRecord.fromJson(json))
|
||||||
|
.cast<SnSocialCreditRecord>()
|
||||||
|
.toList();
|
||||||
|
|
||||||
final hasMore = offset + records.length < total;
|
return records;
|
||||||
final nextCursor = hasMore ? (offset + records.length).toString() : null;
|
|
||||||
|
|
||||||
return CursorPagingData(
|
|
||||||
items: records,
|
|
||||||
hasMore: hasMore,
|
|
||||||
nextCursor: nextCursor,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,31 +107,39 @@ class SocialCreditsTab extends HookConsumerWidget {
|
|||||||
.padding(horizontal: 20, vertical: 16),
|
.padding(horizontal: 20, vertical: 16),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PagingHelperView(
|
child: PaginationList(
|
||||||
provider: socialCreditHistoryNotifierProvider,
|
|
||||||
futureRefreshable: socialCreditHistoryNotifierProvider.future,
|
|
||||||
notifierRefreshable: socialCreditHistoryNotifierProvider.notifier,
|
|
||||||
contentBuilder:
|
|
||||||
(data, widgetCount, endItemView) => ListView.builder(
|
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
itemCount: widgetCount,
|
provider: socialCreditHistoryNotifierProvider,
|
||||||
itemBuilder: (context, index) {
|
notifier: socialCreditHistoryNotifierProvider.notifier,
|
||||||
if (index == widgetCount - 1) {
|
itemBuilder: (context, idx, record) {
|
||||||
return endItemView;
|
final isExpired =
|
||||||
}
|
record.expiredAt != null &&
|
||||||
final record = data.items[index];
|
record.expiredAt!.isBefore(DateTime.now());
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
horizontal: 24,
|
title: Text(
|
||||||
|
record.reason,
|
||||||
|
style:
|
||||||
|
isExpired
|
||||||
|
? TextStyle(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withOpacity(0.8),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(record.reason),
|
subtitle: Row(
|
||||||
subtitle: Text(
|
spacing: 4,
|
||||||
DateFormat.yMMMd().format(record.createdAt),
|
children: [
|
||||||
|
Text(record.createdAt.formatSystem()),
|
||||||
|
Text('to'),
|
||||||
|
if (record.expiredAt != null)
|
||||||
|
Text(record.expiredAt!.formatSystem()),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
record.delta > 0
|
record.delta > 0 ? '+${record.delta}' : '${record.delta}',
|
||||||
? '+${record.delta}'
|
|
||||||
: '${record.delta}',
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: record.delta > 0 ? Colors.green : Colors.red,
|
color: record.delta > 0 ? Colors.green : Colors.red,
|
||||||
),
|
),
|
||||||
@@ -143,7 +148,6 @@ class SocialCreditsTab extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,26 +24,5 @@ final socialCreditsProvider = AutoDisposeFutureProvider<double>.internal(
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef SocialCreditsRef = AutoDisposeFutureProviderRef<double>;
|
typedef SocialCreditsRef = AutoDisposeFutureProviderRef<double>;
|
||||||
String _$socialCreditHistoryNotifierHash() =>
|
|
||||||
r'3e87af246cc5dc72a1f3a87b81d1c87169bdfb5b';
|
|
||||||
|
|
||||||
/// See also [SocialCreditHistoryNotifier].
|
|
||||||
@ProviderFor(SocialCreditHistoryNotifier)
|
|
||||||
final socialCreditHistoryNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
|
||||||
SocialCreditHistoryNotifier,
|
|
||||||
CursorPagingData<SnSocialCreditRecord>
|
|
||||||
>.internal(
|
|
||||||
SocialCreditHistoryNotifier.new,
|
|
||||||
name: r'socialCreditHistoryNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$socialCreditHistoryNotifierHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$SocialCreditHistoryNotifier =
|
|
||||||
AutoDisposeAsyncNotifier<CursorPagingData<SnSocialCreditRecord>>;
|
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
import 'package:island/screens/account/credits.dart';
|
import 'package:island/screens/account/credits.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/services/time.dart';
|
||||||
@@ -10,46 +11,37 @@ import 'package:island/widgets/account/leveling_progress.dart';
|
|||||||
import 'package:island/widgets/account/stellar_program_tab.dart';
|
import 'package:island/widgets/account/stellar_program_tab.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:island/widgets/paging/pagination_list.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
part 'leveling.g.dart';
|
final levelingHistoryNotifierProvider = AsyncNotifierProvider(
|
||||||
|
LevelingHistoryNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
@riverpod
|
class LevelingHistoryNotifier extends AsyncNotifier<List<SnExperienceRecord>>
|
||||||
class LevelingHistoryNotifier extends _$LevelingHistoryNotifier
|
with AsyncPaginationController<SnExperienceRecord> {
|
||||||
with CursorPagingNotifierMixin<SnExperienceRecord> {
|
static const int pageSize = 20;
|
||||||
static const int _pageSize = 20;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnExperienceRecord>> build() => fetch(cursor: null);
|
Future<List<SnExperienceRecord>> fetch() async {
|
||||||
|
|
||||||
@override
|
|
||||||
Future<CursorPagingData<SnExperienceRecord>> fetch({
|
|
||||||
required String? cursor,
|
|
||||||
}) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
|
||||||
|
|
||||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
final queryParams = {'offset': fetchedCount.toString(), 'take': pageSize};
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/pass/accounts/me/leveling',
|
'/pass/accounts/me/leveling',
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
);
|
);
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
|
||||||
final List<dynamic> data = response.data;
|
|
||||||
final records =
|
|
||||||
data.map((json) => SnExperienceRecord.fromJson(json)).toList();
|
|
||||||
|
|
||||||
final hasMore = offset + records.length < total;
|
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
final nextCursor = hasMore ? (offset + records.length).toString() : null;
|
|
||||||
|
|
||||||
return CursorPagingData(
|
final List<SnExperienceRecord> records =
|
||||||
items: records,
|
response.data
|
||||||
hasMore: hasMore,
|
.map((json) => SnExperienceRecord.fromJson(json))
|
||||||
nextCursor: nextCursor,
|
.cast<SnExperienceRecord>()
|
||||||
);
|
.toList();
|
||||||
|
|
||||||
|
return records;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,19 +181,13 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SliverGap(8),
|
const SliverGap(8),
|
||||||
PagingHelperSliverView(
|
PaginationList(
|
||||||
provider: levelingHistoryNotifierProvider,
|
provider: levelingHistoryNotifierProvider,
|
||||||
futureRefreshable: levelingHistoryNotifierProvider.future,
|
notifier: levelingHistoryNotifierProvider.notifier,
|
||||||
notifierRefreshable: levelingHistoryNotifierProvider.notifier,
|
isRefreshable: false,
|
||||||
contentBuilder:
|
isSliver: true,
|
||||||
(data, widgetCount, endItemView) => SliverList.builder(
|
itemBuilder:
|
||||||
itemCount: widgetCount,
|
(context, idx, record) => ListTile(
|
||||||
itemBuilder: (context, index) {
|
|
||||||
if (index == widgetCount - 1) {
|
|
||||||
return endItemView;
|
|
||||||
}
|
|
||||||
final record = data.items[index];
|
|
||||||
return ListTile(
|
|
||||||
title: Column(
|
title: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -214,9 +200,7 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
record.createdAt.formatRelative(context),
|
record.createdAt.formatRelative(context),
|
||||||
).fontSize(13),
|
).fontSize(13),
|
||||||
Text('·').fontSize(13).bold(),
|
Text('·').fontSize(13).bold(),
|
||||||
Text(
|
Text(record.createdAt.formatSystem()).fontSize(13),
|
||||||
record.createdAt.formatSystem(),
|
|
||||||
).fontSize(13),
|
|
||||||
],
|
],
|
||||||
).opacity(0.8),
|
).opacity(0.8),
|
||||||
],
|
],
|
||||||
@@ -233,8 +217,6 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
minTileHeight: 56,
|
minTileHeight: 56,
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'leveling.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$levelingHistoryNotifierHash() =>
|
|
||||||
r'de51012e1590ac46388b6f3f2050b21cb96698d1';
|
|
||||||
|
|
||||||
/// See also [LevelingHistoryNotifier].
|
|
||||||
@ProviderFor(LevelingHistoryNotifier)
|
|
||||||
final levelingHistoryNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
|
||||||
LevelingHistoryNotifier,
|
|
||||||
CursorPagingData<SnExperienceRecord>
|
|
||||||
>.internal(
|
|
||||||
LevelingHistoryNotifier.new,
|
|
||||||
name: r'levelingHistoryNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$levelingHistoryNotifierHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$LevelingHistoryNotifier =
|
|
||||||
AutoDisposeAsyncNotifier<CursorPagingData<SnExperienceRecord>>;
|
|
||||||
// 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,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@@ -7,9 +6,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/models/file.dart';
|
|
||||||
import 'package:island/models/account.dart';
|
|
||||||
import 'package:island/pods/database.dart';
|
|
||||||
import 'package:island/pods/chat/chat_summary.dart';
|
import 'package:island/pods/chat/chat_summary.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
@@ -24,11 +20,9 @@ import 'package:island/widgets/navigation/fab_menu.dart';
|
|||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/widgets/response.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:relative_time/relative_time.dart';
|
import 'package:relative_time/relative_time.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
part 'chat.g.dart';
|
|
||||||
|
|
||||||
class ChatRoomListTile extends HookConsumerWidget {
|
class ChatRoomListTile extends HookConsumerWidget {
|
||||||
final SnChatRoom room;
|
final SnChatRoom room;
|
||||||
@@ -183,90 +177,6 @@ class ChatRoomListTile extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
|
||||||
Future<List<SnChatRoom>> chatroomsJoined(Ref ref) async {
|
|
||||||
final db = ref.watch(databaseProvider);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final localRoomsData = await db.select(db.chatRooms).get();
|
|
||||||
if (localRoomsData.isNotEmpty) {
|
|
||||||
final localRooms = await Future.wait(
|
|
||||||
localRoomsData.map((row) async {
|
|
||||||
final membersRows =
|
|
||||||
await (db.select(db.chatMembers)
|
|
||||||
..where((m) => m.chatRoomId.equals(row.id))).get();
|
|
||||||
final members =
|
|
||||||
membersRows.map((mRow) {
|
|
||||||
final account = SnAccount.fromJson(mRow.account);
|
|
||||||
return SnChatMember(
|
|
||||||
id: mRow.id,
|
|
||||||
chatRoomId: mRow.chatRoomId,
|
|
||||||
accountId: mRow.accountId,
|
|
||||||
account: account,
|
|
||||||
nick: mRow.nick,
|
|
||||||
notify: mRow.notify,
|
|
||||||
joinedAt: mRow.joinedAt,
|
|
||||||
breakUntil: mRow.breakUntil,
|
|
||||||
timeoutUntil: mRow.timeoutUntil,
|
|
||||||
status: null,
|
|
||||||
createdAt: mRow.createdAt,
|
|
||||||
updatedAt: mRow.updatedAt,
|
|
||||||
deletedAt: mRow.deletedAt,
|
|
||||||
chatRoom: null,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
return SnChatRoom(
|
|
||||||
id: row.id,
|
|
||||||
name: row.name,
|
|
||||||
description: row.description,
|
|
||||||
type: row.type,
|
|
||||||
isPublic: row.isPublic!,
|
|
||||||
isCommunity: row.isCommunity!,
|
|
||||||
picture:
|
|
||||||
row.picture != null ? SnCloudFile.fromJson(row.picture!) : null,
|
|
||||||
background:
|
|
||||||
row.background != null
|
|
||||||
? SnCloudFile.fromJson(row.background!)
|
|
||||||
: null,
|
|
||||||
realmId: row.realmId,
|
|
||||||
accountId: row.accountId,
|
|
||||||
realm: null,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
updatedAt: row.updatedAt,
|
|
||||||
deletedAt: row.deletedAt,
|
|
||||||
members: members,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Background sync
|
|
||||||
Future(() async {
|
|
||||||
try {
|
|
||||||
final client = ref.read(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat');
|
|
||||||
final remoteRooms =
|
|
||||||
resp.data
|
|
||||||
.map((e) => SnChatRoom.fromJson(e))
|
|
||||||
.cast<SnChatRoom>()
|
|
||||||
.toList();
|
|
||||||
await db.saveChatRooms(remoteRooms);
|
|
||||||
ref.invalidateSelf();
|
|
||||||
} catch (_) {}
|
|
||||||
}).ignore();
|
|
||||||
|
|
||||||
return localRooms;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// Fallback to API
|
|
||||||
final client = ref.watch(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat');
|
|
||||||
final rooms =
|
|
||||||
resp.data.map((e) => SnChatRoom.fromJson(e)).cast<SnChatRoom>().toList();
|
|
||||||
await db.saveChatRooms(rooms);
|
|
||||||
return rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatListBodyWidget extends HookConsumerWidget {
|
class ChatListBodyWidget extends HookConsumerWidget {
|
||||||
final bool isFloating;
|
final bool isFloating;
|
||||||
final TabController tabController;
|
final TabController tabController;
|
||||||
@@ -281,7 +191,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chats = ref.watch(chatroomsJoinedProvider);
|
final chats = ref.watch(chatRoomJoinedNotifierProvider);
|
||||||
|
|
||||||
Widget bodyWidget = Column(
|
Widget bodyWidget = Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -304,7 +214,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
(items) => RefreshIndicator(
|
(items) => RefreshIndicator(
|
||||||
onRefresh:
|
onRefresh:
|
||||||
() => Future.sync(() {
|
() => Future.sync(() {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
}),
|
}),
|
||||||
child: SuperListView.builder(
|
child: SuperListView.builder(
|
||||||
padding: EdgeInsets.only(bottom: 96),
|
padding: EdgeInsets.only(bottom: 96),
|
||||||
@@ -354,7 +264,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
(error, stack) => ResponseErrorWidget(
|
(error, stack) => ResponseErrorWidget(
|
||||||
error: error,
|
error: error,
|
||||||
onRetry: () {
|
onRetry: () {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -431,7 +341,7 @@ class ChatListScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Listen for chat rooms refresh events
|
// Listen for chat rooms refresh events
|
||||||
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
|
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () {
|
return () {
|
||||||
@@ -599,46 +509,6 @@ class ChatListScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
|
||||||
Future<SnChatRoom?> chatroom(Ref ref, String? identifier) async {
|
|
||||||
if (identifier == null) return null;
|
|
||||||
try {
|
|
||||||
final client = ref.watch(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat/$identifier');
|
|
||||||
return SnChatRoom.fromJson(resp.data);
|
|
||||||
} catch (err) {
|
|
||||||
if (err is DioException && err.response?.statusCode == 404) {
|
|
||||||
return null; // Chat room not found
|
|
||||||
}
|
|
||||||
rethrow; // Rethrow other errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@riverpod
|
|
||||||
Future<SnChatMember?> chatroomIdentity(Ref ref, String? identifier) async {
|
|
||||||
if (identifier == null) return null;
|
|
||||||
try {
|
|
||||||
final client = ref.watch(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
|
||||||
return SnChatMember.fromJson(resp.data);
|
|
||||||
} catch (err) {
|
|
||||||
if (err is DioException && err.response?.statusCode == 404) {
|
|
||||||
return null; // Chat member not found
|
|
||||||
}
|
|
||||||
rethrow; // Rethrow other errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@riverpod
|
|
||||||
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
|
|
||||||
final client = ref.watch(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat/invites');
|
|
||||||
return resp.data
|
|
||||||
.map((e) => SnChatMember.fromJson(e))
|
|
||||||
.cast<SnChatMember>()
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChatInvitesSheet extends HookConsumerWidget {
|
class _ChatInvitesSheet extends HookConsumerWidget {
|
||||||
const _ChatInvitesSheet();
|
const _ChatInvitesSheet();
|
||||||
|
|
||||||
@@ -651,7 +521,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
|
|||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
|
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
|
||||||
ref.invalidate(chatroomInvitesProvider);
|
ref.invalidate(chatroomInvitesProvider);
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,309 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'chat.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$chatroomsJoinedHash() => r'50abce4f03a7a8509f16d5ad0b1dbf8e3aeb73b6';
|
|
||||||
|
|
||||||
/// See also [chatroomsJoined].
|
|
||||||
@ProviderFor(chatroomsJoined)
|
|
||||||
final chatroomsJoinedProvider =
|
|
||||||
AutoDisposeFutureProvider<List<SnChatRoom>>.internal(
|
|
||||||
chatroomsJoined,
|
|
||||||
name: r'chatroomsJoinedProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$chatroomsJoinedHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
typedef ChatroomsJoinedRef = AutoDisposeFutureProviderRef<List<SnChatRoom>>;
|
|
||||||
String _$chatroomHash() => r'2b17d94728026420d18d6c383d2400cf4a070913';
|
|
||||||
|
|
||||||
/// 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 [chatroom].
|
|
||||||
@ProviderFor(chatroom)
|
|
||||||
const chatroomProvider = ChatroomFamily();
|
|
||||||
|
|
||||||
/// See also [chatroom].
|
|
||||||
class ChatroomFamily extends Family<AsyncValue<SnChatRoom?>> {
|
|
||||||
/// See also [chatroom].
|
|
||||||
const ChatroomFamily();
|
|
||||||
|
|
||||||
/// See also [chatroom].
|
|
||||||
ChatroomProvider call(String? identifier) {
|
|
||||||
return ChatroomProvider(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ChatroomProvider getProviderOverride(covariant ChatroomProvider provider) {
|
|
||||||
return call(provider.identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'chatroomProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [chatroom].
|
|
||||||
class ChatroomProvider extends AutoDisposeFutureProvider<SnChatRoom?> {
|
|
||||||
/// See also [chatroom].
|
|
||||||
ChatroomProvider(String? identifier)
|
|
||||||
: this._internal(
|
|
||||||
(ref) => chatroom(ref as ChatroomRef, identifier),
|
|
||||||
from: chatroomProvider,
|
|
||||||
name: r'chatroomProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$chatroomHash,
|
|
||||||
dependencies: ChatroomFamily._dependencies,
|
|
||||||
allTransitiveDependencies: ChatroomFamily._allTransitiveDependencies,
|
|
||||||
identifier: identifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
ChatroomProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.identifier,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? identifier;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(
|
|
||||||
FutureOr<SnChatRoom?> Function(ChatroomRef provider) create,
|
|
||||||
) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: ChatroomProvider._internal(
|
|
||||||
(ref) => create(ref as ChatroomRef),
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
identifier: identifier,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeFutureProviderElement<SnChatRoom?> createElement() {
|
|
||||||
return _ChatroomProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is ChatroomProvider && other.identifier == identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, identifier.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
mixin ChatroomRef on AutoDisposeFutureProviderRef<SnChatRoom?> {
|
|
||||||
/// The parameter `identifier` of this provider.
|
|
||||||
String? get identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChatroomProviderElement
|
|
||||||
extends AutoDisposeFutureProviderElement<SnChatRoom?>
|
|
||||||
with ChatroomRef {
|
|
||||||
_ChatroomProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get identifier => (origin as ChatroomProvider).identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$chatroomIdentityHash() => r'35e19a5a3e31752c79b97ba0358a7ec8fb8f6e99';
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
@ProviderFor(chatroomIdentity)
|
|
||||||
const chatroomIdentityProvider = ChatroomIdentityFamily();
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
class ChatroomIdentityFamily extends Family<AsyncValue<SnChatMember?>> {
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
const ChatroomIdentityFamily();
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
ChatroomIdentityProvider call(String? identifier) {
|
|
||||||
return ChatroomIdentityProvider(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ChatroomIdentityProvider getProviderOverride(
|
|
||||||
covariant ChatroomIdentityProvider provider,
|
|
||||||
) {
|
|
||||||
return call(provider.identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'chatroomIdentityProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
class ChatroomIdentityProvider
|
|
||||||
extends AutoDisposeFutureProvider<SnChatMember?> {
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
ChatroomIdentityProvider(String? identifier)
|
|
||||||
: this._internal(
|
|
||||||
(ref) => chatroomIdentity(ref as ChatroomIdentityRef, identifier),
|
|
||||||
from: chatroomIdentityProvider,
|
|
||||||
name: r'chatroomIdentityProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$chatroomIdentityHash,
|
|
||||||
dependencies: ChatroomIdentityFamily._dependencies,
|
|
||||||
allTransitiveDependencies:
|
|
||||||
ChatroomIdentityFamily._allTransitiveDependencies,
|
|
||||||
identifier: identifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
ChatroomIdentityProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.identifier,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? identifier;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(
|
|
||||||
FutureOr<SnChatMember?> Function(ChatroomIdentityRef provider) create,
|
|
||||||
) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: ChatroomIdentityProvider._internal(
|
|
||||||
(ref) => create(ref as ChatroomIdentityRef),
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
identifier: identifier,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeFutureProviderElement<SnChatMember?> createElement() {
|
|
||||||
return _ChatroomIdentityProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is ChatroomIdentityProvider && other.identifier == identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, identifier.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
mixin ChatroomIdentityRef on AutoDisposeFutureProviderRef<SnChatMember?> {
|
|
||||||
/// The parameter `identifier` of this provider.
|
|
||||||
String? get identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChatroomIdentityProviderElement
|
|
||||||
extends AutoDisposeFutureProviderElement<SnChatMember?>
|
|
||||||
with ChatroomIdentityRef {
|
|
||||||
_ChatroomIdentityProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get identifier => (origin as ChatroomIdentityProvider).identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
|
||||||
|
|
||||||
/// See also [chatroomInvites].
|
|
||||||
@ProviderFor(chatroomInvites)
|
|
||||||
final chatroomInvitesProvider =
|
|
||||||
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
|
|
||||||
chatroomInvites,
|
|
||||||
name: r'chatroomInvitesProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$chatroomInvitesHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
typedef ChatroomInvitesRef = AutoDisposeFutureProviderRef<List<SnChatMember>>;
|
|
||||||
// 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,8 +10,8 @@ import 'package:image_picker/image_picker.dart';
|
|||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/realm.dart';
|
import 'package:island/models/realm.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/chat/chat.dart';
|
|
||||||
import 'package:island/screens/realm/realms.dart';
|
import 'package:island/screens/realm/realms.dart';
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/services/file.dart';
|
||||||
import 'package:island/services/file_uploader.dart';
|
import 'package:island/services/file_uploader.dart';
|
||||||
@@ -47,7 +47,7 @@ class EditChatScreen extends HookConsumerWidget {
|
|||||||
final isPublic = useState(true);
|
final isPublic = useState(true);
|
||||||
final isCommunity = useState(false);
|
final isCommunity = useState(false);
|
||||||
|
|
||||||
final chat = ref.watch(chatroomProvider(id));
|
final chat = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
|
|
||||||
final joinedRealms = ref.watch(realmsJoinedProvider);
|
final joinedRealms = ref.watch(realmsJoinedProvider);
|
||||||
final currentRealm = useState<SnRealm?>(null);
|
final currentRealm = useState<SnRealm?>(null);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import "package:flutter_hooks/flutter_hooks.dart";
|
|||||||
import "package:gap/gap.dart";
|
import "package:gap/gap.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:island/database/message.dart";
|
import "package:island/database/message.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/widgets/content/cloud_files.dart";
|
import "package:island/widgets/content/cloud_files.dart";
|
||||||
import "package:super_sliver_list/super_sliver_list.dart";
|
import "package:super_sliver_list/super_sliver_list.dart";
|
||||||
import "package:easy_localization/easy_localization.dart";
|
import "package:easy_localization/easy_localization.dart";
|
||||||
@@ -203,7 +203,7 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ import "package:island/models/chat.dart";
|
|||||||
import "package:island/models/file.dart";
|
import "package:island/models/file.dart";
|
||||||
import "package:island/models/poll.dart";
|
import "package:island/models/poll.dart";
|
||||||
import "package:island/models/wallet.dart";
|
import "package:island/models/wallet.dart";
|
||||||
import "package:island/pods/chat/chat_rooms.dart";
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/pods/chat/chat_subscribe.dart";
|
import "package:island/pods/chat/chat_subscribe.dart";
|
||||||
import "package:island/pods/chat/messages_notifier.dart";
|
import "package:island/pods/chat/messages_notifier.dart";
|
||||||
import "package:island/pods/network.dart";
|
import "package:island/pods/network.dart";
|
||||||
import "package:island/pods/chat/chat_online_count.dart";
|
import "package:island/pods/chat/chat_online_count.dart";
|
||||||
import "package:island/pods/config.dart";
|
import "package:island/pods/config.dart";
|
||||||
|
import "package:island/pods/userinfo.dart";
|
||||||
import "package:island/screens/chat/search_messages.dart";
|
import "package:island/screens/chat/search_messages.dart";
|
||||||
import "package:island/services/file_uploader.dart";
|
import "package:island/services/file_uploader.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
|
||||||
import "package:island/services/responsive.dart";
|
import "package:island/services/responsive.dart";
|
||||||
import "package:island/widgets/alert.dart";
|
import "package:island/widgets/alert.dart";
|
||||||
import "package:island/widgets/app_scaffold.dart";
|
import "package:island/widgets/app_scaffold.dart";
|
||||||
@@ -48,14 +48,12 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatRoom = ref.watch(chatroomProvider(id));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final isSyncing = ref.watch(isSyncingProvider);
|
final isSyncing = ref.watch(isSyncingProvider);
|
||||||
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
||||||
final settings = ref.watch(appSettingsNotifierProvider);
|
final settings = ref.watch(appSettingsNotifierProvider);
|
||||||
|
|
||||||
final hasOnlineCount = onlineCount.hasValue;
|
|
||||||
|
|
||||||
if (chatIdentity.isLoading || chatRoom.isLoading) {
|
if (chatIdentity.isLoading || chatRoom.isLoading) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
appBar: AppBar(leading: const PageBackButton()),
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
@@ -102,7 +100,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
await apiClient.post(
|
await apiClient.post(
|
||||||
'/sphere/chat/${room.id}/members/me',
|
'/sphere/chat/${room.id}/members/me',
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(
|
||||||
|
ChatRoomIdentityNotifierProvider(id),
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -131,7 +131,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
appBar: AppBar(leading: const PageBackButton()),
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
body: ResponseErrorWidget(
|
body: ResponseErrorWidget(
|
||||||
error: error,
|
error: error,
|
||||||
onRetry: () => ref.refresh(chatroomProvider(id)),
|
onRetry: () => ref.refresh(ChatRoomNotifierProvider(id)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -410,19 +410,27 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
final compactHeader = isWideScreen(context);
|
final compactHeader = isWideScreen(context);
|
||||||
|
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
List<SnChatMember> getValidMembers(List<SnChatMember> members) {
|
||||||
|
return members
|
||||||
|
.where((member) => member.accountId != userInfo.value?.id)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Widget comfortHeaderWidget(SnChatRoom? room) => Column(
|
Widget comfortHeaderWidget(SnChatRoom? room) => Column(
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Badge(
|
Badge(
|
||||||
isLabelVisible: hasOnlineCount,
|
isLabelVisible: (onlineCount.value ?? 0) > 1,
|
||||||
label: Text('${(onlineCount as AsyncData?)?.value}'),
|
label: Text('${(onlineCount.value ?? 0)}'),
|
||||||
|
textStyle: GoogleFonts.robotoMono(fontSize: 10),
|
||||||
|
textColor: Colors.white,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
(onlineCount as AsyncData?)?.value != null &&
|
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
|
||||||
(onlineCount as AsyncData).value > 1
|
offset: Offset(6, 14),
|
||||||
? Colors.green
|
|
||||||
: Colors.grey,
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 26,
|
height: 26,
|
||||||
width: 26,
|
width: 26,
|
||||||
@@ -430,9 +438,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
(room!.type == 1 && room.picture?.id == null)
|
(room!.type == 1 && room.picture?.id == null)
|
||||||
? SplitAvatarWidget(
|
? SplitAvatarWidget(
|
||||||
filesId:
|
filesId:
|
||||||
room.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.profile.picture?.id)
|
room.members!,
|
||||||
.toList(),
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
)
|
)
|
||||||
: room.picture?.id != null
|
: room.picture?.id != null
|
||||||
? ProfilePictureWidget(
|
? ProfilePictureWidget(
|
||||||
@@ -449,7 +457,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? room.members!.map((e) => e.account.nick).join(', ')
|
? getValidMembers(
|
||||||
|
room.members!,
|
||||||
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(15),
|
).fontSize(15),
|
||||||
],
|
],
|
||||||
@@ -462,7 +472,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Badge(
|
Badge(
|
||||||
isLabelVisible: (onlineCount.value ?? 0) > 1,
|
isLabelVisible: (onlineCount.value ?? 0) > 1,
|
||||||
label: Text('${(onlineCount as AsyncData?)?.value}'),
|
label: Text('${(onlineCount.value ?? 0)}'),
|
||||||
textStyle: GoogleFonts.robotoMono(fontSize: 10),
|
textStyle: GoogleFonts.robotoMono(fontSize: 10),
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
|
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
|
||||||
@@ -475,9 +485,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
(room!.type == 1 && room.picture?.id == null)
|
(room!.type == 1 && room.picture?.id == null)
|
||||||
? SplitAvatarWidget(
|
? SplitAvatarWidget(
|
||||||
filesId:
|
filesId:
|
||||||
room.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.profile.picture?.id)
|
room.members!,
|
||||||
.toList(),
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
)
|
)
|
||||||
: room.picture?.id != null
|
: room.picture?.id != null
|
||||||
? ProfilePictureWidget(
|
? ProfilePictureWidget(
|
||||||
@@ -494,7 +504,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? room.members!.map((e) => e.account.nick).join(', ')
|
? getValidMembers(
|
||||||
|
room.members!,
|
||||||
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(19),
|
).fontSize(19),
|
||||||
],
|
],
|
||||||
@@ -734,7 +746,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: !compactHeader ? const Center(child: PageBackButton()) : null,
|
leading: !compactHeader ? const Center(child: PageBackButton()) : null,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
toolbarHeight: compactHeader ? null : 80,
|
toolbarHeight: compactHeader ? null : 74,
|
||||||
title: chatRoom.when(
|
title: chatRoom.when(
|
||||||
data:
|
data:
|
||||||
(room) =>
|
(room) =>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/chat/chat.dart';
|
|
||||||
import 'package:island/widgets/account/account_pfc.dart';
|
import 'package:island/widgets/account/account_pfc.dart';
|
||||||
import 'package:island/widgets/account/account_picker.dart';
|
import 'package:island/widgets/account/account_picker.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/widgets/account/status.dart';
|
||||||
@@ -39,8 +39,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final roomState = ref.watch(chatroomProvider(id));
|
final roomState = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
|
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final totalMessages = ref.watch(totalMessagesCountProvider(id));
|
final totalMessages = ref.watch(totalMessagesCountProvider(id));
|
||||||
|
|
||||||
const kNotifyLevelText = [
|
const kNotifyLevelText = [
|
||||||
@@ -56,7 +56,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
'/sphere/chat/$id/members/me/notify',
|
'/sphere/chat/$id/members/me/notify',
|
||||||
data: {'notify_level': level},
|
data: {'notify_level': level},
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showSnackBar(
|
showSnackBar(
|
||||||
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
|
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
|
||||||
@@ -74,7 +74,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
'/sphere/chat/$id/members/me/notify',
|
'/sphere/chat/$id/members/me/notify',
|
||||||
data: {'break_until': until.toUtc().toIso8601String()},
|
data: {'break_until': until.toUtc().toIso8601String()},
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomProvider(id));
|
ref.invalidate(ChatRoomNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
}
|
}
|
||||||
@@ -439,8 +439,8 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final chatRoom = ref.watch(chatroomProvider(id));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
|
|
||||||
final isManagable =
|
final isManagable =
|
||||||
chatIdentity.value?.accountId == chatRoom.value?.accountId ||
|
chatIdentity.value?.accountId == chatRoom.value?.accountId ||
|
||||||
@@ -461,7 +461,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
).then((value) {
|
).then((value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// Invalidate to refresh room data after edit
|
// Invalidate to refresh room data after edit
|
||||||
ref.invalidate(chatroomProvider(id));
|
ref.invalidate(ChatRoomNotifierProvider(id));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -497,7 +497,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.delete('/sphere/chat/$id');
|
await client.delete('/sphere/chat/$id');
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
@@ -530,7 +530,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.delete('/sphere/chat/$id/members/me');
|
await client.delete('/sphere/chat/$id/members/me');
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
@@ -648,8 +648,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
|||||||
final memberState = ref.watch(chatMemberStateProvider(roomId));
|
final memberState = ref.watch(chatMemberStateProvider(roomId));
|
||||||
final memberNotifier = ref.read(chatMemberStateProvider(roomId).notifier);
|
final memberNotifier = ref.read(chatMemberStateProvider(roomId).notifier);
|
||||||
|
|
||||||
final roomIdentity = ref.watch(chatroomIdentityProvider(roomId));
|
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(roomId));
|
||||||
final chatRoom = ref.watch(chatroomProvider(roomId));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(roomId));
|
||||||
|
|
||||||
final isManagable =
|
final isManagable =
|
||||||
chatRoom.value?.accountId == roomIdentity.value?.accountId ||
|
chatRoom.value?.accountId == roomIdentity.value?.accountId ||
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
import 'package:island/pods/chat/messages_notifier.dart';
|
import 'package:island/pods/chat/messages_notifier.dart';
|
||||||
import 'package:island/pods/chat/chat_rooms.dart';
|
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/chat/message_list_tile.dart';
|
import 'package:island/widgets/chat/message_list_tile.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
|
|||||||
@@ -573,6 +573,7 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
child: publisherStats.when(
|
child: publisherStats.when(
|
||||||
data:
|
data:
|
||||||
(stats) => SingleChildScrollView(
|
(stats) => SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||||
child:
|
child:
|
||||||
currentPublisher.value == null
|
currentPublisher.value == null
|
||||||
? ConstrainedBox(
|
? ConstrainedBox(
|
||||||
@@ -602,7 +603,7 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
).padding(horizontal: 12),
|
).padding(horizontal: 12),
|
||||||
buildNavigationWidget(true),
|
buildNavigationWidget(true),
|
||||||
],
|
],
|
||||||
).padding(vertical: 24)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -320,7 +320,6 @@ class StickerForm extends HookConsumerWidget {
|
|||||||
final formKey = useMemoized(() => GlobalKey<FormState>(), []);
|
final formKey = useMemoized(() => GlobalKey<FormState>(), []);
|
||||||
|
|
||||||
final image = useState<String?>(id == null ? '' : sticker.value?.image.id);
|
final image = useState<String?>(id == null ? '' : sticker.value?.image.id);
|
||||||
final imageController = useTextEditingController(text: image.value);
|
|
||||||
final slugController = useTextEditingController(
|
final slugController = useTextEditingController(
|
||||||
text: id == null ? '' : sticker.value?.slug,
|
text: id == null ? '' : sticker.value?.slug,
|
||||||
);
|
);
|
||||||
@@ -328,7 +327,6 @@ class StickerForm extends HookConsumerWidget {
|
|||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (sticker.value != null) {
|
if (sticker.value != null) {
|
||||||
image.value = sticker.value!.image.id;
|
image.value = sticker.value!.image.id;
|
||||||
imageController.text = sticker.value!.image.id;
|
|
||||||
slugController.text = sticker.value!.slug;
|
slugController.text = sticker.value!.slug;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -344,7 +342,7 @@ class StickerForm extends HookConsumerWidget {
|
|||||||
id == null
|
id == null
|
||||||
? '/sphere/stickers/$packId/content'
|
? '/sphere/stickers/$packId/content'
|
||||||
: '/sphere/stickers/$packId/content/$id',
|
: '/sphere/stickers/$packId/content/$id',
|
||||||
data: {'slug': slugController.text, 'image_id': imageController.text},
|
data: {'slug': slugController.text, 'image_id': image.value},
|
||||||
options: Options(method: id == null ? 'POST' : 'PATCH'),
|
options: Options(method: id == null ? 'POST' : 'PATCH'),
|
||||||
);
|
);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
@@ -392,7 +390,6 @@ class StickerForm extends HookConsumerWidget {
|
|||||||
).then((value) {
|
).then((value) {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
image.value = value[0].id;
|
image.value = value[0].id;
|
||||||
imageController.text = image.value!;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Symbols.cloud_upload),
|
icon: const Icon(Symbols.cloud_upload),
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/sticker.dart';
|
import 'package:island/models/sticker.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/services/responsive.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
|
import 'package:island/widgets/content/cloud_file_picker.dart';
|
||||||
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
import 'package:island/screens/creators/stickers/pack_detail.dart';
|
import 'package:island/screens/creators/stickers/pack_detail.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
@@ -207,6 +210,9 @@ class StickerPackForm extends HookConsumerWidget {
|
|||||||
final formKey = useMemoized(() => GlobalKey<FormState>(), []);
|
final formKey = useMemoized(() => GlobalKey<FormState>(), []);
|
||||||
final initialPack = ref.watch(stickerPackProvider(packId));
|
final initialPack = ref.watch(stickerPackProvider(packId));
|
||||||
|
|
||||||
|
final icon = useState<String?>(
|
||||||
|
packId == null ? '' : initialPack.value?.icon?.id,
|
||||||
|
);
|
||||||
final nameController = useTextEditingController();
|
final nameController = useTextEditingController();
|
||||||
final descriptionController = useTextEditingController();
|
final descriptionController = useTextEditingController();
|
||||||
final prefixController = useTextEditingController();
|
final prefixController = useTextEditingController();
|
||||||
@@ -229,11 +235,12 @@ class StickerPackForm extends HookConsumerWidget {
|
|||||||
submitting.value = true;
|
submitting.value = true;
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
final resp = await apiClient.request(
|
final resp = await apiClient.request(
|
||||||
'/sphere/stickers',
|
packId == null ? '/sphere/stickers' : '/sphere/stickers/$packId',
|
||||||
data: {
|
data: {
|
||||||
'name': nameController.text,
|
'name': nameController.text,
|
||||||
'description': descriptionController.text,
|
'description': descriptionController.text,
|
||||||
'prefix': prefixController.text,
|
'prefix': prefixController.text,
|
||||||
|
'icon_id': icon.value,
|
||||||
},
|
},
|
||||||
queryParameters: {'pub': pubName},
|
queryParameters: {'pub': pubName},
|
||||||
options: Options(method: packId == null ? 'POST' : 'PATCH'),
|
options: Options(method: packId == null ? 'POST' : 'PATCH'),
|
||||||
@@ -255,6 +262,44 @@ class StickerPackForm extends HookConsumerWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
spacing: 16,
|
spacing: 16,
|
||||||
children: [
|
children: [
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 80,
|
||||||
|
width: 80,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||||
|
),
|
||||||
|
child:
|
||||||
|
(icon.value?.isEmpty ?? true)
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: CloudImageWidget(fileId: icon.value!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton.filledTonal(
|
||||||
|
onPressed: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => CloudFilePicker(
|
||||||
|
allowedTypes: {UniversalFileType.image},
|
||||||
|
),
|
||||||
|
).then((value) {
|
||||||
|
if (value == null) return;
|
||||||
|
icon.value = value[0].id;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.cloud_upload),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:desktop_drop/desktop_drop.dart';
|
import 'package:desktop_drop/desktop_drop.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
@@ -12,6 +11,7 @@ import 'package:island/models/publisher.dart';
|
|||||||
import 'package:island/models/realm.dart';
|
import 'package:island/models/realm.dart';
|
||||||
import 'package:island/models/webfeed.dart';
|
import 'package:island/models/webfeed.dart';
|
||||||
import 'package:island/pods/event_calendar.dart';
|
import 'package:island/pods/event_calendar.dart';
|
||||||
|
import 'package:island/pods/timeline.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
import 'package:island/screens/auth/login_modal.dart';
|
import 'package:island/screens/auth/login_modal.dart';
|
||||||
import 'package:island/screens/notification.dart';
|
import 'package:island/screens/notification.dart';
|
||||||
@@ -21,24 +21,20 @@ import 'package:island/widgets/account/friends_overview.dart';
|
|||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
import 'package:island/widgets/check_in.dart';
|
import 'package:island/widgets/check_in.dart';
|
||||||
|
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||||
import 'package:island/widgets/navigation/fab_menu.dart';
|
import 'package:island/widgets/navigation/fab_menu.dart';
|
||||||
|
import 'package:island/widgets/paging/pagination_list.dart';
|
||||||
import 'package:island/widgets/post/post_featured.dart';
|
import 'package:island/widgets/post/post_featured.dart';
|
||||||
import 'package:island/widgets/post/post_item.dart';
|
import 'package:island/widgets/post/post_item.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
|
||||||
import 'package:island/pods/network.dart';
|
|
||||||
import 'package:island/widgets/realm/realm_card.dart';
|
import 'package:island/widgets/realm/realm_card.dart';
|
||||||
import 'package:island/widgets/publisher/publisher_card.dart';
|
import 'package:island/widgets/publisher/publisher_card.dart';
|
||||||
import 'package:island/widgets/web_article_card.dart';
|
import 'package:island/widgets/web_article_card.dart';
|
||||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
|
||||||
import 'package:island/services/event_bus.dart';
|
import 'package:island/services/event_bus.dart';
|
||||||
import 'package:island/widgets/share/share_sheet.dart';
|
import 'package:island/widgets/share/share_sheet.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||||
|
|
||||||
part 'explore.g.dart';
|
|
||||||
|
|
||||||
Widget notificationIndicatorWidget(
|
Widget notificationIndicatorWidget(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required int count,
|
required int count,
|
||||||
@@ -76,8 +72,8 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final tabController = useTabController(initialLength: 3);
|
|
||||||
final currentFilter = useState<String?>(null);
|
final currentFilter = useState<String?>(null);
|
||||||
|
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
// Set FAB type to chat
|
// Set FAB type to chat
|
||||||
@@ -95,32 +91,15 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() {
|
void handleFilterChange(String? filter) {
|
||||||
void listener() {
|
currentFilter.value = filter;
|
||||||
switch (tabController.index) {
|
notifier.applyFilter(filter);
|
||||||
case 0:
|
|
||||||
currentFilter.value = null;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
currentFilter.value = 'subscriptions';
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
currentFilter.value = 'friends';
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tabController.addListener(listener);
|
|
||||||
return () => tabController.removeListener(listener);
|
|
||||||
}, [tabController]);
|
|
||||||
|
|
||||||
// Listen for post creation events to refresh activities
|
// Listen for post creation events to refresh activities
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
final subscription = eventBus.on<PostCreatedEvent>().listen((event) {
|
final subscription = eventBus.on<PostCreatedEvent>().listen((event) {
|
||||||
// Refresh all activity lists when a new post is created
|
ref.invalidate(activityListNotifierProvider);
|
||||||
ref.invalidate(activityListNotifierProvider(null));
|
|
||||||
ref.invalidate(activityListNotifierProvider('subscriptions'));
|
|
||||||
ref.invalidate(activityListNotifierProvider('friends'));
|
|
||||||
});
|
});
|
||||||
return subscription.cancel;
|
return subscription.cancel;
|
||||||
}, []);
|
}, []);
|
||||||
@@ -147,35 +126,51 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Row(
|
||||||
child: TabBar(
|
spacing: 8,
|
||||||
controller: tabController,
|
children: [
|
||||||
tabAlignment: TabAlignment.start,
|
IconButton(
|
||||||
isScrollable: true,
|
onPressed: () => handleFilterChange(null),
|
||||||
dividerColor: Colors.transparent,
|
icon: Icon(
|
||||||
labelPadding: const EdgeInsets.symmetric(horizontal: 12),
|
Symbols.explore,
|
||||||
tabs: [
|
fill: currentFilter.value == null ? 1 : null,
|
||||||
Tab(
|
|
||||||
icon: Tooltip(
|
|
||||||
message: 'explore'.tr(),
|
|
||||||
child: Icon(Symbols.explore),
|
|
||||||
),
|
),
|
||||||
|
tooltip: 'explore'.tr(),
|
||||||
|
isSelected: currentFilter.value == null,
|
||||||
|
color:
|
||||||
|
currentFilter.value == null
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
Tab(
|
IconButton(
|
||||||
icon: Tooltip(
|
onPressed: () => handleFilterChange('subscriptions'),
|
||||||
message: 'exploreFilterSubscriptions'.tr(),
|
icon: Icon(
|
||||||
child: Icon(Symbols.subscriptions),
|
Symbols.subscriptions,
|
||||||
|
fill: currentFilter.value == 'subscriptions' ? 1 : null,
|
||||||
),
|
),
|
||||||
|
tooltip: 'exploreFilterSubscriptions'.tr(),
|
||||||
|
isSelected: currentFilter.value == 'subscriptions',
|
||||||
|
color:
|
||||||
|
currentFilter.value == 'subscriptions'
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
Tab(
|
IconButton(
|
||||||
icon: Tooltip(
|
onPressed: () => handleFilterChange('friends'),
|
||||||
message: 'exploreFilterFriends'.tr(),
|
icon: Icon(
|
||||||
child: Icon(Symbols.people),
|
Symbols.people,
|
||||||
|
fill: currentFilter.value == 'friends' ? 1 : null,
|
||||||
),
|
),
|
||||||
|
tooltip: 'exploreFilterFriends'.tr(),
|
||||||
|
isSelected: currentFilter.value == 'friends',
|
||||||
|
color:
|
||||||
|
currentFilter.value == 'friends'
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushNamed('articles');
|
context.pushNamed('articles');
|
||||||
@@ -239,10 +234,13 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
tooltip: 'search'.tr(),
|
tooltip: 'search'.tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(horizontal: 8),
|
).padding(horizontal: 8, vertical: 4),
|
||||||
);
|
);
|
||||||
|
|
||||||
final appBar = isWide ? null : _buildAppBar(tabController, context);
|
final appBar =
|
||||||
|
isWide
|
||||||
|
? null
|
||||||
|
: _buildAppBar(currentFilter.value, handleFilterChange, context);
|
||||||
|
|
||||||
final dragging = useState(false);
|
final dragging = useState(false);
|
||||||
|
|
||||||
@@ -276,7 +274,6 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
query,
|
query,
|
||||||
events,
|
events,
|
||||||
selectedDay,
|
selectedDay,
|
||||||
currentFilter.value,
|
|
||||||
)
|
)
|
||||||
: _buildNarrowBody(context, ref, currentFilter.value),
|
: _buildNarrowBody(context, ref, currentFilter.value),
|
||||||
),
|
),
|
||||||
@@ -315,29 +312,18 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildActivityList(
|
Widget _buildActivityList(BuildContext context, WidgetRef ref) {
|
||||||
BuildContext context,
|
|
||||||
WidgetRef ref,
|
|
||||||
String? filter,
|
|
||||||
) {
|
|
||||||
final activitiesNotifier = ref.watch(
|
|
||||||
activityListNotifierProvider(filter).notifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
final isWide = isWideScreen(context);
|
final isWide = isWideScreen(context);
|
||||||
|
|
||||||
return PagingHelperSliverView(
|
return PaginationWidget(
|
||||||
provider: activityListNotifierProvider(filter),
|
provider: activityListNotifierProvider,
|
||||||
futureRefreshable: activityListNotifierProvider(filter).future,
|
notifier: activityListNotifierProvider.notifier,
|
||||||
notifierRefreshable: activityListNotifierProvider(filter).notifier,
|
// Sliver list cannot provide refresh handled by the pagination list
|
||||||
|
isRefreshable: false,
|
||||||
|
isSliver: true,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) => _ActivityListView(
|
(data, footer) =>
|
||||||
data: data,
|
_ActivityListView(data: data, isWide: isWide, footer: footer),
|
||||||
widgetCount: widgetCount,
|
|
||||||
endItemView: endItemView,
|
|
||||||
activitiesNotifier: activitiesNotifier,
|
|
||||||
isWide: isWide,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,13 +336,10 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
ValueNotifier<EventCalendarQuery> query,
|
ValueNotifier<EventCalendarQuery> query,
|
||||||
AsyncValue<List<dynamic>> events,
|
AsyncValue<List<dynamic>> events,
|
||||||
ValueNotifier<DateTime> selectedDay,
|
ValueNotifier<DateTime> selectedDay,
|
||||||
String? currentFilter,
|
|
||||||
) {
|
) {
|
||||||
final bodyView = _buildActivityList(context, ref, currentFilter);
|
final bodyView = _buildActivityList(context, ref);
|
||||||
|
|
||||||
final activitiesNotifier = ref.watch(
|
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||||
activityListNotifierProvider(currentFilter).notifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
@@ -364,7 +347,7 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: ExtendedRefreshIndicator(
|
child: ExtendedRefreshIndicator(
|
||||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
onRefresh: notifier.refresh,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
const SliverGap(12),
|
const SliverGap(12),
|
||||||
@@ -449,54 +432,57 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(
|
PreferredSizeWidget _buildAppBar(
|
||||||
TabController tabController,
|
String? currentFilter,
|
||||||
|
void Function(String?) handleFilterChange,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
final foregroundColor = Theme.of(context).appBarTheme.foregroundColor;
|
final foregroundColor = Theme.of(context).appBarTheme.foregroundColor;
|
||||||
|
|
||||||
return AppBar(
|
return AppBar(
|
||||||
toolbarHeight: 48 + 4,
|
toolbarHeight: 48,
|
||||||
flexibleSpace: Container(
|
flexibleSpace: Container(
|
||||||
height: 48,
|
height: 48,
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: 8,
|
left: 8,
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 4 + MediaQuery.of(context).padding.top,
|
top: 4 + MediaQuery.of(context).padding.top,
|
||||||
|
bottom: 4,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
IconButton(
|
||||||
child: TabBar(
|
onPressed: () => handleFilterChange(null),
|
||||||
controller: tabController,
|
icon: Icon(
|
||||||
tabAlignment: TabAlignment.start,
|
Symbols.explore,
|
||||||
isScrollable: true,
|
color: foregroundColor,
|
||||||
dividerColor: Colors.transparent,
|
fill: currentFilter == null ? 1 : null,
|
||||||
labelPadding: const EdgeInsets.symmetric(horizontal: 12),
|
|
||||||
tabs: [
|
|
||||||
Tab(
|
|
||||||
icon: Tooltip(
|
|
||||||
message: 'explore'.tr(),
|
|
||||||
child: Icon(Symbols.explore, color: foregroundColor),
|
|
||||||
),
|
),
|
||||||
|
tooltip: 'explore'.tr(),
|
||||||
|
isSelected: currentFilter == null,
|
||||||
|
color: currentFilter == null ? foregroundColor : null,
|
||||||
),
|
),
|
||||||
Tab(
|
IconButton(
|
||||||
icon: Tooltip(
|
onPressed: () => handleFilterChange('subscriptions'),
|
||||||
message: 'exploreFilterSubscriptions'.tr(),
|
icon: Icon(
|
||||||
child: Icon(
|
|
||||||
Symbols.subscriptions,
|
Symbols.subscriptions,
|
||||||
color: foregroundColor,
|
color: foregroundColor,
|
||||||
|
fill: currentFilter == 'subscription' ? 1 : null,
|
||||||
),
|
),
|
||||||
|
tooltip: 'exploreFilterSubscriptions'.tr(),
|
||||||
|
isSelected: currentFilter == 'subscriptions',
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => handleFilterChange('friends'),
|
||||||
|
icon: Icon(
|
||||||
|
Symbols.people,
|
||||||
|
color: foregroundColor,
|
||||||
|
fill: currentFilter == 'friends' ? 1 : null,
|
||||||
),
|
),
|
||||||
Tab(
|
tooltip: 'exploreFilterFriends'.tr(),
|
||||||
icon: Tooltip(
|
isSelected: currentFilter == 'friends',
|
||||||
message: 'exploreFilterFriends'.tr(),
|
|
||||||
child: Icon(Symbols.people, color: foregroundColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushNamed('articles');
|
context.pushNamed('articles');
|
||||||
@@ -575,17 +561,15 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
notificationUnreadCountNotifierProvider,
|
notificationUnreadCountNotifierProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
final activitiesNotifier = ref.watch(
|
final bodyView = _buildActivityList(context, ref);
|
||||||
activityListNotifierProvider(currentFilter).notifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
final bodyView = _buildActivityList(context, ref, currentFilter);
|
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: ExtendedRefreshIndicator(
|
|
||||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: ExtendedRefreshIndicator(
|
||||||
|
onRefresh: notifier.refresh,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
const SliverGap(8),
|
const SliverGap(8),
|
||||||
@@ -623,8 +607,8 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
bodyView,
|
bodyView,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
).padding(horizontal: 8),
|
|
||||||
),
|
),
|
||||||
|
).padding(horizontal: 8),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,31 +725,29 @@ class _DiscoveryActivityItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ActivityListView extends HookConsumerWidget {
|
class _ActivityListView extends HookConsumerWidget {
|
||||||
final CursorPagingData<SnTimelineEvent> data;
|
final List<SnTimelineEvent> data;
|
||||||
final int widgetCount;
|
|
||||||
final Widget endItemView;
|
|
||||||
final ActivityListNotifier activitiesNotifier;
|
|
||||||
final bool isWide;
|
final bool isWide;
|
||||||
|
final Widget footer;
|
||||||
|
|
||||||
const _ActivityListView({
|
const _ActivityListView({
|
||||||
required this.data,
|
required this.data,
|
||||||
required this.widgetCount,
|
|
||||||
required this.endItemView,
|
|
||||||
required this.activitiesNotifier,
|
|
||||||
required this.isWide,
|
required this.isWide,
|
||||||
|
required this.footer,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final notifier = ref.watch(activityListNotifierProvider.notifier);
|
||||||
|
|
||||||
return SliverList.separated(
|
return SliverList.separated(
|
||||||
itemCount: widgetCount,
|
itemCount: data.length + 1,
|
||||||
separatorBuilder: (_, _) => const Gap(8),
|
separatorBuilder: (_, _) => const Gap(8),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == data.length) {
|
||||||
return endItemView;
|
return footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
final item = data.items[index];
|
final item = data[index];
|
||||||
if (item.data == null) {
|
if (item.data == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
@@ -778,13 +760,10 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
item: SnPost.fromJson(item.data!),
|
item: SnPost.fromJson(item.data!),
|
||||||
onRefresh: () {
|
onRefresh: () {
|
||||||
activitiesNotifier.forceRefresh();
|
notifier.refresh();
|
||||||
},
|
},
|
||||||
onUpdate: (post) {
|
onUpdate: (post) {
|
||||||
activitiesNotifier.updateOne(
|
notifier.updateOne(index, item.copyWith(data: post.toJson()));
|
||||||
index,
|
|
||||||
item.copyWith(data: post.toJson()),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
itemWidget = Card(margin: EdgeInsets.zero, child: itemWidget);
|
itemWidget = Card(margin: EdgeInsets.zero, child: itemWidget);
|
||||||
@@ -801,69 +780,3 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
|
||||||
class ActivityListNotifier extends _$ActivityListNotifier
|
|
||||||
with CursorPagingNotifierMixin<SnTimelineEvent> {
|
|
||||||
@override
|
|
||||||
Future<CursorPagingData<SnTimelineEvent>> build(String? filter) =>
|
|
||||||
fetch(cursor: null);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<CursorPagingData<SnTimelineEvent>> fetch({
|
|
||||||
required String? cursor,
|
|
||||||
}) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
|
||||||
final take = 20;
|
|
||||||
|
|
||||||
final queryParameters = {
|
|
||||||
if (cursor != null) 'cursor': cursor,
|
|
||||||
'take': take,
|
|
||||||
if (filter != null) 'filter': filter,
|
|
||||||
if (kDebugMode)
|
|
||||||
'debugInclude': 'realms,publishers,articles,shuffledPosts',
|
|
||||||
};
|
|
||||||
|
|
||||||
final response = await client.get(
|
|
||||||
'/sphere/timeline',
|
|
||||||
queryParameters: queryParameters,
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<SnTimelineEvent> items =
|
|
||||||
(response.data as List)
|
|
||||||
.map((e) => SnTimelineEvent.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final hasMore = (items.firstOrNull?.type ?? 'empty') != 'empty';
|
|
||||||
final nextCursor =
|
|
||||||
items.isNotEmpty
|
|
||||||
? items
|
|
||||||
.map((x) => x.createdAt)
|
|
||||||
.reduce((a, b) => a.isBefore(b) ? a : b)
|
|
||||||
.toUtc()
|
|
||||||
.toIso8601String()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return CursorPagingData(
|
|
||||||
items: items,
|
|
||||||
hasMore: hasMore,
|
|
||||||
nextCursor: nextCursor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateOne(int index, SnTimelineEvent activity) {
|
|
||||||
final currentState = state.valueOrNull;
|
|
||||||
if (currentState == null) return;
|
|
||||||
|
|
||||||
final updatedItems = [...currentState.items];
|
|
||||||
updatedItems[index] = activity;
|
|
||||||
|
|
||||||
state = AsyncData(
|
|
||||||
CursorPagingData(
|
|
||||||
items: updatedItems,
|
|
||||||
hasMore: currentState.hasMore,
|
|
||||||
nextCursor: currentState.nextCursor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'explore.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$activityListNotifierHash() =>
|
|
||||||
r'77ffc7852feffa5438b56fa26123d453b7c310cf';
|
|
||||||
|
|
||||||
/// 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 _$ActivityListNotifier
|
|
||||||
extends
|
|
||||||
BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnTimelineEvent>> {
|
|
||||||
late final String? filter;
|
|
||||||
|
|
||||||
FutureOr<CursorPagingData<SnTimelineEvent>> build(String? filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
@ProviderFor(ActivityListNotifier)
|
|
||||||
const activityListNotifierProvider = ActivityListNotifierFamily();
|
|
||||||
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
class ActivityListNotifierFamily
|
|
||||||
extends Family<AsyncValue<CursorPagingData<SnTimelineEvent>>> {
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
const ActivityListNotifierFamily();
|
|
||||||
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
ActivityListNotifierProvider call(String? filter) {
|
|
||||||
return ActivityListNotifierProvider(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ActivityListNotifierProvider getProviderOverride(
|
|
||||||
covariant ActivityListNotifierProvider provider,
|
|
||||||
) {
|
|
||||||
return call(provider.filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'activityListNotifierProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
class ActivityListNotifierProvider
|
|
||||||
extends
|
|
||||||
AutoDisposeAsyncNotifierProviderImpl<
|
|
||||||
ActivityListNotifier,
|
|
||||||
CursorPagingData<SnTimelineEvent>
|
|
||||||
> {
|
|
||||||
/// See also [ActivityListNotifier].
|
|
||||||
ActivityListNotifierProvider(String? filter)
|
|
||||||
: this._internal(
|
|
||||||
() => ActivityListNotifier()..filter = filter,
|
|
||||||
from: activityListNotifierProvider,
|
|
||||||
name: r'activityListNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$activityListNotifierHash,
|
|
||||||
dependencies: ActivityListNotifierFamily._dependencies,
|
|
||||||
allTransitiveDependencies:
|
|
||||||
ActivityListNotifierFamily._allTransitiveDependencies,
|
|
||||||
filter: filter,
|
|
||||||
);
|
|
||||||
|
|
||||||
ActivityListNotifierProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.filter,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? filter;
|
|
||||||
|
|
||||||
@override
|
|
||||||
FutureOr<CursorPagingData<SnTimelineEvent>> runNotifierBuild(
|
|
||||||
covariant ActivityListNotifier notifier,
|
|
||||||
) {
|
|
||||||
return notifier.build(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(ActivityListNotifier Function() create) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: ActivityListNotifierProvider._internal(
|
|
||||||
() => create()..filter = filter,
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
filter: filter,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeAsyncNotifierProviderElement<
|
|
||||||
ActivityListNotifier,
|
|
||||||
CursorPagingData<SnTimelineEvent>
|
|
||||||
>
|
|
||||||
createElement() {
|
|
||||||
return _ActivityListNotifierProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is ActivityListNotifierProvider && other.filter == filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, filter.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
mixin ActivityListNotifierRef
|
|
||||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnTimelineEvent>> {
|
|
||||||
/// The parameter `filter` of this provider.
|
|
||||||
String? get filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ActivityListNotifierProviderElement
|
|
||||||
extends
|
|
||||||
AutoDisposeAsyncNotifierProviderElement<
|
|
||||||
ActivityListNotifier,
|
|
||||||
CursorPagingData<SnTimelineEvent>
|
|
||||||
>
|
|
||||||
with ActivityListNotifierRef {
|
|
||||||
_ActivityListNotifierProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get filter => (origin as ActivityListNotifierProvider).filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
@@ -116,7 +116,7 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
completer.future
|
completer.future
|
||||||
.then((uploadedFile) {
|
.then((uploadedFile) {
|
||||||
if (uploadedFile != null) {
|
if (uploadedFile != null) {
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
ref.invalidate(indexedCloudFileListNotifierProvider);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catchError((error) {
|
.catchError((error) {
|
||||||
|
|||||||
@@ -1,60 +1,72 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/sticker.dart';
|
import 'package:island/models/sticker.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/paging/pagination_list.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
|
||||||
|
|
||||||
part 'sticker_marketplace.g.dart';
|
part 'sticker_marketplace.freezed.dart';
|
||||||
|
|
||||||
@riverpod
|
@freezed
|
||||||
class MarketplaceStickerPacksNotifier extends _$MarketplaceStickerPacksNotifier
|
sealed class MarketplaceStickerQuery with _$MarketplaceStickerQuery {
|
||||||
with CursorPagingNotifierMixin<SnStickerPack> {
|
const factory MarketplaceStickerQuery({
|
||||||
@override
|
|
||||||
Future<CursorPagingData<SnStickerPack>> build({
|
|
||||||
required String? query,
|
|
||||||
required bool byUsage,
|
required bool byUsage,
|
||||||
}) {
|
required String? query,
|
||||||
return fetch(cursor: null);
|
}) = _MarketplaceStickerQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final marketplaceStickerPacksNotifierProvider = AsyncNotifierProvider(
|
||||||
|
MarketplaceStickerPacksNotifier.new,
|
||||||
|
);
|
||||||
|
|
||||||
|
class MarketplaceStickerPacksNotifier extends AsyncNotifier<List<SnStickerPack>>
|
||||||
|
with
|
||||||
|
AsyncPaginationController<SnStickerPack>,
|
||||||
|
AsyncPaginationFilter<MarketplaceStickerQuery, SnStickerPack> {
|
||||||
|
static const int pageSize = 20;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnStickerPack>> fetch({
|
MarketplaceStickerQuery currentFilter = MarketplaceStickerQuery(
|
||||||
required String? cursor,
|
byUsage: true,
|
||||||
}) async {
|
query: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<SnStickerPack>> fetch() async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/sphere/stickers',
|
'/sphere/stickers',
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'offset': offset,
|
'offset': fetchedCount.toString(),
|
||||||
'take': 20,
|
'take': pageSize,
|
||||||
'order': byUsage ? 'usage' : 'date',
|
'order': currentFilter.byUsage ? 'usage' : 'date',
|
||||||
if (query != null && query!.isNotEmpty) 'query': query,
|
if (currentFilter.query != null && currentFilter.query!.isNotEmpty)
|
||||||
|
'query': currentFilter.query,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
final List<dynamic> data = response.data;
|
final stickers =
|
||||||
final stickers = data.map((e) => SnStickerPack.fromJson(e)).toList();
|
response.data
|
||||||
|
.map((e) => SnStickerPack.fromJson(e))
|
||||||
|
.cast<SnStickerPack>()
|
||||||
|
.toList();
|
||||||
|
|
||||||
final hasMore = offset + stickers.length < total;
|
return stickers;
|
||||||
final nextCursor = hasMore ? (offset + stickers.length).toString() : null;
|
|
||||||
|
|
||||||
return CursorPagingData(
|
|
||||||
items: stickers,
|
|
||||||
hasMore: hasMore,
|
|
||||||
nextCursor: nextCursor,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,17 +77,23 @@ class MarketplaceStickersScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final byUsage = useState(true);
|
final query = useState<MarketplaceStickerQuery>(
|
||||||
final query = useState<String?>(null);
|
MarketplaceStickerQuery(byUsage: true, query: null),
|
||||||
|
);
|
||||||
final searchController = useTextEditingController();
|
final searchController = useTextEditingController();
|
||||||
final focusNode = useFocusNode();
|
final focusNode = useFocusNode();
|
||||||
final debounceTimer = useState<Timer?>(null);
|
final debounceTimer = useState<Timer?>(null);
|
||||||
|
|
||||||
|
final notifier = ref.watch(
|
||||||
|
marketplaceStickerPacksNotifierProvider.notifier,
|
||||||
|
);
|
||||||
|
|
||||||
// Clear search when query is cleared
|
// Clear search when query is cleared
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (query.value == null || query.value!.isEmpty) {
|
if (query.value.query == null || query.value.query!.isEmpty) {
|
||||||
searchController.clear();
|
searchController.clear();
|
||||||
}
|
}
|
||||||
|
notifier.applyFilter(query.value);
|
||||||
return null;
|
return null;
|
||||||
}, [query]);
|
}, [query]);
|
||||||
|
|
||||||
@@ -92,41 +110,24 @@ class MarketplaceStickersScreen extends HookConsumerWidget {
|
|||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
byUsage.value = !byUsage.value;
|
query.value = query.value.copyWith(byUsage: !query.value.byUsage);
|
||||||
},
|
},
|
||||||
icon:
|
icon:
|
||||||
byUsage.value
|
query.value.byUsage
|
||||||
? const Icon(Symbols.local_fire_department)
|
? const Icon(Symbols.local_fire_department)
|
||||||
: const Icon(Symbols.access_time),
|
: const Icon(Symbols.access_time),
|
||||||
tooltip:
|
tooltip:
|
||||||
byUsage.value
|
query.value.byUsage
|
||||||
? 'orderByPopularity'.tr()
|
? 'orderByPopularity'.tr()
|
||||||
: 'orderByReleaseDate'.tr(),
|
: 'orderByReleaseDate'.tr(),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: PagingHelperView(
|
body: Column(
|
||||||
provider: marketplaceStickerPacksNotifierProvider(
|
|
||||||
byUsage: byUsage.value,
|
|
||||||
query: query.value,
|
|
||||||
),
|
|
||||||
futureRefreshable:
|
|
||||||
marketplaceStickerPacksNotifierProvider(
|
|
||||||
byUsage: byUsage.value,
|
|
||||||
query: query.value,
|
|
||||||
).future,
|
|
||||||
notifierRefreshable:
|
|
||||||
marketplaceStickerPacksNotifierProvider(
|
|
||||||
byUsage: byUsage.value,
|
|
||||||
query: query.value,
|
|
||||||
).notifier,
|
|
||||||
contentBuilder:
|
|
||||||
(data, widgetCount, endItemView) => Column(
|
|
||||||
children: [
|
children: [
|
||||||
// Search bar above the list
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||||
child: SearchBar(
|
child: SearchBar(
|
||||||
elevation: WidgetStateProperty.all(4),
|
elevation: WidgetStateProperty.all(4),
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
@@ -139,11 +140,11 @@ class MarketplaceStickersScreen extends HookConsumerWidget {
|
|||||||
onTapOutside:
|
onTapOutside:
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
trailing: [
|
trailing: [
|
||||||
if (query.value != null && query.value!.isNotEmpty)
|
if (query.value.query != null && query.value.query!.isNotEmpty)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.close),
|
icon: const Icon(Symbols.close),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
query.value = null;
|
query.value = query.value.copyWith(query: null);
|
||||||
searchController.clear();
|
searchController.clear();
|
||||||
focusNode.unfocus();
|
focusNode.unfocus();
|
||||||
},
|
},
|
||||||
@@ -155,27 +156,121 @@ class MarketplaceStickersScreen extends HookConsumerWidget {
|
|||||||
debounceTimer.value = Timer(
|
debounceTimer.value = Timer(
|
||||||
const Duration(milliseconds: 500),
|
const Duration(milliseconds: 500),
|
||||||
() {
|
() {
|
||||||
query.value = value.isEmpty ? null : value;
|
query.value = query.value.copyWith(query: value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
query.value = value.isEmpty ? null : value;
|
query.value = query.value.copyWith(query: value);
|
||||||
focusNode.unfocus();
|
focusNode.unfocus();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: PaginationList(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.only(top: 8),
|
||||||
itemCount: widgetCount,
|
provider: marketplaceStickerPacksNotifierProvider,
|
||||||
itemBuilder: (context, index) {
|
notifier: marketplaceStickerPacksNotifierProvider.notifier,
|
||||||
if (index == widgetCount - 1) {
|
itemBuilder:
|
||||||
return endItemView;
|
(context, idx, pack) => Card(
|
||||||
}
|
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||||
|
child: Column(
|
||||||
final pack = data.items[index];
|
children: [
|
||||||
return ListTile(
|
Container(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 20,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: List.generate(
|
||||||
|
math.min(pack.stickers.length, 4),
|
||||||
|
(index) => Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
right: index < 3 ? 8 : 0,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 80,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.tertiaryContainer,
|
||||||
|
),
|
||||||
|
child: CloudImageWidget(
|
||||||
|
file: pack.stickers[index].image,
|
||||||
|
),
|
||||||
|
).clipRRect(all: 8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (pack.stickers.length > 4)
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (pack.stickers.length > 4)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: List.generate(
|
||||||
|
math.min(pack.stickers.length - 4, 4),
|
||||||
|
(index) => Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
right: index < 3 ? 8 : 0,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 80,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.tertiaryContainer,
|
||||||
|
),
|
||||||
|
child: CloudImageWidget(
|
||||||
|
file:
|
||||||
|
pack.stickers[index + 4].image,
|
||||||
|
),
|
||||||
|
).clipRRect(all: 8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).clipRRect(topLeft: 8, topRight: 8),
|
||||||
|
ListTile(
|
||||||
|
leading: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.tertiaryContainer,
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: CloudImageWidget(
|
||||||
|
file: pack.icon ?? pack.stickers.first.image,
|
||||||
|
),
|
||||||
|
).width(40).height(40).clipRRect(all: 8),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
title: Text(pack.name),
|
title: Text(pack.name),
|
||||||
subtitle: Text(pack.description),
|
subtitle: Text(pack.description),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
@@ -187,13 +282,14 @@ class MarketplaceStickersScreen extends HookConsumerWidget {
|
|||||||
pathParameters: {'packId': pack.id},
|
pathParameters: {'packId': pack.id},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
268
lib/screens/stickers/sticker_marketplace.freezed.dart
Normal file
268
lib/screens/stickers/sticker_marketplace.freezed.dart
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'sticker_marketplace.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$MarketplaceStickerQuery {
|
||||||
|
|
||||||
|
bool get byUsage; String? get query;
|
||||||
|
/// Create a copy of MarketplaceStickerQuery
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$MarketplaceStickerQueryCopyWith<MarketplaceStickerQuery> get copyWith => _$MarketplaceStickerQueryCopyWithImpl<MarketplaceStickerQuery>(this as MarketplaceStickerQuery, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is MarketplaceStickerQuery&&(identical(other.byUsage, byUsage) || other.byUsage == byUsage)&&(identical(other.query, query) || other.query == query));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,byUsage,query);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'MarketplaceStickerQuery(byUsage: $byUsage, query: $query)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $MarketplaceStickerQueryCopyWith<$Res> {
|
||||||
|
factory $MarketplaceStickerQueryCopyWith(MarketplaceStickerQuery value, $Res Function(MarketplaceStickerQuery) _then) = _$MarketplaceStickerQueryCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
bool byUsage, String? query
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$MarketplaceStickerQueryCopyWithImpl<$Res>
|
||||||
|
implements $MarketplaceStickerQueryCopyWith<$Res> {
|
||||||
|
_$MarketplaceStickerQueryCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final MarketplaceStickerQuery _self;
|
||||||
|
final $Res Function(MarketplaceStickerQuery) _then;
|
||||||
|
|
||||||
|
/// Create a copy of MarketplaceStickerQuery
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? byUsage = null,Object? query = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
byUsage: null == byUsage ? _self.byUsage : byUsage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,query: freezed == query ? _self.query : query // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [MarketplaceStickerQuery].
|
||||||
|
extension MarketplaceStickerQueryPatterns on MarketplaceStickerQuery {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _MarketplaceStickerQuery value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _MarketplaceStickerQuery value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _MarketplaceStickerQuery value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool byUsage, String? query)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery() when $default != null:
|
||||||
|
return $default(_that.byUsage,_that.query);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool byUsage, String? query) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery():
|
||||||
|
return $default(_that.byUsage,_that.query);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool byUsage, String? query)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _MarketplaceStickerQuery() when $default != null:
|
||||||
|
return $default(_that.byUsage,_that.query);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
|
||||||
|
class _MarketplaceStickerQuery implements MarketplaceStickerQuery {
|
||||||
|
const _MarketplaceStickerQuery({required this.byUsage, required this.query});
|
||||||
|
|
||||||
|
|
||||||
|
@override final bool byUsage;
|
||||||
|
@override final String? query;
|
||||||
|
|
||||||
|
/// Create a copy of MarketplaceStickerQuery
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$MarketplaceStickerQueryCopyWith<_MarketplaceStickerQuery> get copyWith => __$MarketplaceStickerQueryCopyWithImpl<_MarketplaceStickerQuery>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MarketplaceStickerQuery&&(identical(other.byUsage, byUsage) || other.byUsage == byUsage)&&(identical(other.query, query) || other.query == query));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,byUsage,query);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'MarketplaceStickerQuery(byUsage: $byUsage, query: $query)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$MarketplaceStickerQueryCopyWith<$Res> implements $MarketplaceStickerQueryCopyWith<$Res> {
|
||||||
|
factory _$MarketplaceStickerQueryCopyWith(_MarketplaceStickerQuery value, $Res Function(_MarketplaceStickerQuery) _then) = __$MarketplaceStickerQueryCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
bool byUsage, String? query
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$MarketplaceStickerQueryCopyWithImpl<$Res>
|
||||||
|
implements _$MarketplaceStickerQueryCopyWith<$Res> {
|
||||||
|
__$MarketplaceStickerQueryCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _MarketplaceStickerQuery _self;
|
||||||
|
final $Res Function(_MarketplaceStickerQuery) _then;
|
||||||
|
|
||||||
|
/// Create a copy of MarketplaceStickerQuery
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? byUsage = null,Object? query = freezed,}) {
|
||||||
|
return _then(_MarketplaceStickerQuery(
|
||||||
|
byUsage: null == byUsage ? _self.byUsage : byUsage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,query: freezed == query ? _self.query : query // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'sticker_marketplace.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$marketplaceStickerPacksNotifierHash() =>
|
|
||||||
r'3bde76e18bb024f45ff6261fe735cdba97b02808';
|
|
||||||
|
|
||||||
/// 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 _$MarketplaceStickerPacksNotifier
|
|
||||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> {
|
|
||||||
late final String? query;
|
|
||||||
late final bool byUsage;
|
|
||||||
|
|
||||||
FutureOr<CursorPagingData<SnStickerPack>> build({
|
|
||||||
required String? query,
|
|
||||||
required bool byUsage,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
@ProviderFor(MarketplaceStickerPacksNotifier)
|
|
||||||
const marketplaceStickerPacksNotifierProvider =
|
|
||||||
MarketplaceStickerPacksNotifierFamily();
|
|
||||||
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
class MarketplaceStickerPacksNotifierFamily
|
|
||||||
extends Family<AsyncValue<CursorPagingData<SnStickerPack>>> {
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
const MarketplaceStickerPacksNotifierFamily();
|
|
||||||
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
MarketplaceStickerPacksNotifierProvider call({
|
|
||||||
required String? query,
|
|
||||||
required bool byUsage,
|
|
||||||
}) {
|
|
||||||
return MarketplaceStickerPacksNotifierProvider(
|
|
||||||
query: query,
|
|
||||||
byUsage: byUsage,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
MarketplaceStickerPacksNotifierProvider getProviderOverride(
|
|
||||||
covariant MarketplaceStickerPacksNotifierProvider provider,
|
|
||||||
) {
|
|
||||||
return call(query: provider.query, byUsage: provider.byUsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'marketplaceStickerPacksNotifierProvider';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
class MarketplaceStickerPacksNotifierProvider
|
|
||||||
extends
|
|
||||||
AutoDisposeAsyncNotifierProviderImpl<
|
|
||||||
MarketplaceStickerPacksNotifier,
|
|
||||||
CursorPagingData<SnStickerPack>
|
|
||||||
> {
|
|
||||||
/// See also [MarketplaceStickerPacksNotifier].
|
|
||||||
MarketplaceStickerPacksNotifierProvider({
|
|
||||||
required String? query,
|
|
||||||
required bool byUsage,
|
|
||||||
}) : this._internal(
|
|
||||||
() =>
|
|
||||||
MarketplaceStickerPacksNotifier()
|
|
||||||
..query = query
|
|
||||||
..byUsage = byUsage,
|
|
||||||
from: marketplaceStickerPacksNotifierProvider,
|
|
||||||
name: r'marketplaceStickerPacksNotifierProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$marketplaceStickerPacksNotifierHash,
|
|
||||||
dependencies: MarketplaceStickerPacksNotifierFamily._dependencies,
|
|
||||||
allTransitiveDependencies:
|
|
||||||
MarketplaceStickerPacksNotifierFamily._allTransitiveDependencies,
|
|
||||||
query: query,
|
|
||||||
byUsage: byUsage,
|
|
||||||
);
|
|
||||||
|
|
||||||
MarketplaceStickerPacksNotifierProvider._internal(
|
|
||||||
super._createNotifier, {
|
|
||||||
required super.name,
|
|
||||||
required super.dependencies,
|
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.query,
|
|
||||||
required this.byUsage,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? query;
|
|
||||||
final bool byUsage;
|
|
||||||
|
|
||||||
@override
|
|
||||||
FutureOr<CursorPagingData<SnStickerPack>> runNotifierBuild(
|
|
||||||
covariant MarketplaceStickerPacksNotifier notifier,
|
|
||||||
) {
|
|
||||||
return notifier.build(query: query, byUsage: byUsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Override overrideWith(MarketplaceStickerPacksNotifier Function() create) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: MarketplaceStickerPacksNotifierProvider._internal(
|
|
||||||
() =>
|
|
||||||
create()
|
|
||||||
..query = query
|
|
||||||
..byUsage = byUsage,
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
query: query,
|
|
||||||
byUsage: byUsage,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
AutoDisposeAsyncNotifierProviderElement<
|
|
||||||
MarketplaceStickerPacksNotifier,
|
|
||||||
CursorPagingData<SnStickerPack>
|
|
||||||
>
|
|
||||||
createElement() {
|
|
||||||
return _MarketplaceStickerPacksNotifierProviderElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is MarketplaceStickerPacksNotifierProvider &&
|
|
||||||
other.query == query &&
|
|
||||||
other.byUsage == byUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, query.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, byUsage.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
mixin MarketplaceStickerPacksNotifierRef
|
|
||||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnStickerPack>> {
|
|
||||||
/// The parameter `query` of this provider.
|
|
||||||
String? get query;
|
|
||||||
|
|
||||||
/// The parameter `byUsage` of this provider.
|
|
||||||
bool get byUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MarketplaceStickerPacksNotifierProviderElement
|
|
||||||
extends
|
|
||||||
AutoDisposeAsyncNotifierProviderElement<
|
|
||||||
MarketplaceStickerPacksNotifier,
|
|
||||||
CursorPagingData<SnStickerPack>
|
|
||||||
>
|
|
||||||
with MarketplaceStickerPacksNotifierRef {
|
|
||||||
_MarketplaceStickerPacksNotifierProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get query =>
|
|
||||||
(origin as MarketplaceStickerPacksNotifierProvider).query;
|
|
||||||
@override
|
|
||||||
bool get byUsage =>
|
|
||||||
(origin as MarketplaceStickerPacksNotifierProvider).byUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
@@ -11,6 +12,7 @@ import 'package:island/services/udid.dart';
|
|||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:island/widgets/sites/info_row.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -19,28 +21,30 @@ import 'package:island/widgets/extended_refresh_indicator.dart';
|
|||||||
part 'account_devices.g.dart';
|
part 'account_devices.g.dart';
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<List<SnAuthDeviceWithChallenge>> authDevices(Ref ref) async {
|
Future<List<SnAuthDeviceWithSession>> authDevices(Ref ref) async {
|
||||||
final resp = await ref
|
final resp = await ref
|
||||||
.watch(apiClientProvider)
|
.watch(apiClientProvider)
|
||||||
.get('/pass/accounts/me/devices');
|
.get('/pass/accounts/me/devices');
|
||||||
final currentId = await getUdid();
|
final currentId = await getUdid();
|
||||||
final data =
|
final data =
|
||||||
resp.data.map<SnAuthDeviceWithChallenge>((e) {
|
resp.data.map<SnAuthDeviceWithSession>((e) {
|
||||||
final ele = SnAuthDeviceWithChallenge.fromJson(e);
|
final ele = SnAuthDeviceWithSession.fromJson(e);
|
||||||
return ele.copyWith(isCurrent: ele.deviceId == currentId);
|
return ele.copyWith(isCurrent: ele.deviceId == currentId);
|
||||||
}).toList();
|
}).toList();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceListTile extends StatelessWidget {
|
class _DeviceListTile extends StatelessWidget {
|
||||||
final SnAuthDeviceWithChallenge device;
|
final SnAuthDeviceWithSession device;
|
||||||
final Function(String) updateDeviceLabel;
|
final Function(String) updateDeviceLabel;
|
||||||
final Function(String) logoutDevice;
|
final Function(String) logoutDevice;
|
||||||
|
final Function(String) logoutSession;
|
||||||
|
|
||||||
const _DeviceListTile({
|
const _DeviceListTile({
|
||||||
required this.device,
|
required this.device,
|
||||||
required this.updateDeviceLabel,
|
required this.updateDeviceLabel,
|
||||||
required this.logoutDevice,
|
required this.logoutDevice,
|
||||||
|
required this.logoutSession,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -69,9 +73,10 @@ class _DeviceListTile extends StatelessWidget {
|
|||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
if (device.sessions.isNotEmpty)
|
||||||
Text(
|
Text(
|
||||||
'lastActiveAt'.tr(
|
'lastActiveAt'.tr(
|
||||||
args: [device.challenges.first.createdAt.formatSystem()],
|
args: [device.sessions.first.createdAt.formatSystem()],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -114,26 +119,55 @@ class _DeviceListTile extends StatelessWidget {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
child: Text('authDeviceChallenges'.tr()),
|
child: Text('authDeviceChallenges'.tr()),
|
||||||
),
|
),
|
||||||
for (final challenge in device.challenges)
|
...device.sessions
|
||||||
ListTile(
|
.map(
|
||||||
minTileHeight: 48,
|
(session) => Row(
|
||||||
title: Text(DateFormat().format(challenge.createdAt.toLocal())),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
subtitle: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
Text(challenge.ipAddress),
|
Expanded(
|
||||||
if (challenge.location != null)
|
child: Column(
|
||||||
Row(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
children:
|
children: [
|
||||||
[challenge.location?.city, challenge.location?.country]
|
InfoRow(
|
||||||
.where((e) => e?.isNotEmpty ?? false)
|
label: 'createdAt'.tr(
|
||||||
.map((e) => Text(e!))
|
args: [session.createdAt.toLocal().formatSystem()],
|
||||||
.toList(),
|
),
|
||||||
|
icon: Symbols.join,
|
||||||
|
),
|
||||||
|
InfoRow(
|
||||||
|
label: 'lastActiveAt'.tr(
|
||||||
|
args: [
|
||||||
|
session.lastGrantedAt.toLocal().formatSystem(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
icon: Symbols.refresh_rounded,
|
||||||
|
),
|
||||||
|
InfoRow(
|
||||||
|
label:
|
||||||
|
'${'location'.tr()} ${session.location?.city ?? 'unknown'.tr()}',
|
||||||
|
icon: Symbols.pin_drop,
|
||||||
|
),
|
||||||
|
InfoRow(
|
||||||
|
label:
|
||||||
|
'${'ipAddress'.tr()} ${session.ipAddress ?? 'unknown'.tr()}',
|
||||||
|
icon: Symbols.dns,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.logout),
|
||||||
|
tooltip: 'authSessionLogout'.tr(),
|
||||||
|
onPressed: () => logoutSession(session.id),
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 20, vertical: 8),
|
||||||
|
)
|
||||||
|
.expand((element) => [element, const Divider(height: 1)])
|
||||||
|
.toList()
|
||||||
|
..removeLast(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -162,6 +196,22 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logoutSession(String sessionId) async {
|
||||||
|
final confirm = await showConfirmAlert(
|
||||||
|
'authSessionLogoutHint'.tr(),
|
||||||
|
'authSessionLogout'.tr(),
|
||||||
|
isDanger: true,
|
||||||
|
);
|
||||||
|
if (!confirm || !context.mounted) return;
|
||||||
|
try {
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
await apiClient.delete('/pass/accounts/me/sessions/$sessionId');
|
||||||
|
ref.invalidate(authDevicesProvider);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateDeviceLabel(String sessionId) async {
|
void updateDeviceLabel(String sessionId) async {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
final label = await showDialog<String>(
|
final label = await showDialog<String>(
|
||||||
@@ -249,6 +299,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
device: device,
|
device: device,
|
||||||
updateDeviceLabel: updateDeviceLabel,
|
updateDeviceLabel: updateDeviceLabel,
|
||||||
logoutDevice: logoutDevice,
|
logoutDevice: logoutDevice,
|
||||||
|
logoutSession: logoutSession,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Dismissible(
|
return Dismissible(
|
||||||
@@ -304,6 +355,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
device: device,
|
device: device,
|
||||||
updateDeviceLabel: updateDeviceLabel,
|
updateDeviceLabel: updateDeviceLabel,
|
||||||
logoutDevice: logoutDevice,
|
logoutDevice: logoutDevice,
|
||||||
|
logoutSession: logoutSession,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ part of 'account_devices.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$authDevicesHash() => r'35735af4ed75b73fe80c8942e53b3bc26a569c01';
|
String _$authDevicesHash() => r'1af378149286020ec263be178c573ccc247a0cd1';
|
||||||
|
|
||||||
/// See also [authDevices].
|
/// See also [authDevices].
|
||||||
@ProviderFor(authDevices)
|
@ProviderFor(authDevices)
|
||||||
final authDevicesProvider =
|
final authDevicesProvider =
|
||||||
AutoDisposeFutureProvider<List<SnAuthDeviceWithChallenge>>.internal(
|
AutoDisposeFutureProvider<List<SnAuthDeviceWithSession>>.internal(
|
||||||
authDevices,
|
authDevices,
|
||||||
name: r'authDevicesProvider',
|
name: r'authDevicesProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
@@ -25,6 +25,6 @@ final authDevicesProvider =
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef AuthDevicesRef =
|
typedef AuthDevicesRef =
|
||||||
AutoDisposeFutureProviderRef<List<SnAuthDeviceWithChallenge>>;
|
AutoDisposeFutureProviderRef<List<SnAuthDeviceWithSession>>;
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import "package:island/models/wallet.dart";
|
|||||||
import "package:island/models/realm.dart";
|
import "package:island/models/realm.dart";
|
||||||
import "package:island/models/sticker.dart";
|
import "package:island/models/sticker.dart";
|
||||||
import "package:island/pods/config.dart";
|
import "package:island/pods/config.dart";
|
||||||
|
import "package:island/pods/userinfo.dart";
|
||||||
import "package:island/services/autocomplete_service.dart";
|
import "package:island/services/autocomplete_service.dart";
|
||||||
import "package:island/services/responsive.dart";
|
import "package:island/services/responsive.dart";
|
||||||
import "package:island/widgets/content/attachment_preview.dart";
|
import "package:island/widgets/content/attachment_preview.dart";
|
||||||
@@ -344,6 +345,14 @@ class ChatInput extends HookConsumerWidget {
|
|||||||
final double rightMargin = isWideScreen(context) ? leftMargin + 8 : 16;
|
final double rightMargin = isWideScreen(context) ? leftMargin + 8 : 16;
|
||||||
const double bottomMargin = 16;
|
const double bottomMargin = 16;
|
||||||
|
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
List<SnChatMember> getValidMembers(List<SnChatMember> members) {
|
||||||
|
return members
|
||||||
|
.where((member) => member.accountId != userInfo.value?.id)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: leftMargin,
|
left: leftMargin,
|
||||||
@@ -878,9 +887,9 @@ class ChatInput extends HookConsumerWidget {
|
|||||||
(chatRoom.type == 1 && chatRoom.name == null)
|
(chatRoom.type == 1 && chatRoom.name == null)
|
||||||
? 'chatDirectMessageHint'.tr(
|
? 'chatDirectMessageHint'.tr(
|
||||||
args: [
|
args: [
|
||||||
chatRoom.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.nick)
|
chatRoom.members!,
|
||||||
.join(', '),
|
).map((e) => e.account.nick).join(', '),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: 'chatMessageHint'.tr(
|
: 'chatMessageHint'.tr(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/database/message.dart';
|
import 'package:island/database/message.dart';
|
||||||
import 'package:island/pods/chat/chat_rooms.dart';
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
import 'package:island/pods/chat/messages_notifier.dart';
|
import 'package:island/pods/chat/messages_notifier.dart';
|
||||||
import 'package:island/pods/translate.dart';
|
import 'package:island/pods/translate.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import "package:gap/gap.dart";
|
|||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:island/database/message.dart";
|
import "package:island/database/message.dart";
|
||||||
import "package:island/models/chat.dart";
|
import "package:island/models/chat.dart";
|
||||||
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/pods/chat/messages_notifier.dart";
|
import "package:island/pods/chat/messages_notifier.dart";
|
||||||
import "package:island/pods/network.dart";
|
import "package:island/pods/network.dart";
|
||||||
import "package:island/services/responsive.dart";
|
import "package:island/services/responsive.dart";
|
||||||
@@ -19,8 +20,6 @@ import "package:styled_widget/styled_widget.dart";
|
|||||||
import "package:super_sliver_list/super_sliver_list.dart";
|
import "package:super_sliver_list/super_sliver_list.dart";
|
||||||
import "package:material_symbols_icons/symbols.dart";
|
import "package:material_symbols_icons/symbols.dart";
|
||||||
|
|
||||||
import "package:island/screens/chat/chat.dart";
|
|
||||||
|
|
||||||
class PublicRoomPreview extends HookConsumerWidget {
|
class PublicRoomPreview extends HookConsumerWidget {
|
||||||
final String id;
|
final String id;
|
||||||
final SnChatRoom room;
|
final SnChatRoom room;
|
||||||
@@ -205,7 +204,7 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@@ -14,12 +15,14 @@ import 'package:island/screens/account/profile.dart';
|
|||||||
import 'package:island/screens/creators/publishers_form.dart';
|
import 'package:island/screens/creators/publishers_form.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/content/cloud_file_lightbox.dart';
|
||||||
import 'package:island/widgets/content/markdown_latex.dart';
|
import 'package:island/widgets/content/markdown_latex.dart';
|
||||||
import 'package:markdown/markdown.dart' as markdown;
|
import 'package:markdown/markdown.dart' as markdown;
|
||||||
import 'package:markdown_widget/markdown_widget.dart';
|
import 'package:markdown_widget/markdown_widget.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import 'image.dart';
|
import 'image.dart';
|
||||||
|
|
||||||
@@ -185,20 +188,34 @@ class MarkdownTextContent extends HookConsumerWidget {
|
|||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClipRRect(
|
final heroTag = 'cloud-file-markdown#${const Uuid().v4()}';
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
context.pushTransparentRoute(
|
||||||
|
CloudFileLightbox(item: file, heroTag: heroTag),
|
||||||
|
rootNavigator: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
color:
|
||||||
|
Theme.of(context).colorScheme.surfaceContainer,
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
Radius.circular(8),
|
Radius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: CloudFileWidget(
|
child: CloudFileWidget(
|
||||||
item: file,
|
item: file,
|
||||||
|
heroTag: heroTag,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
).clipRRect(all: 8),
|
).clipRRect(all: 8),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import 'package:island/utils/format.dart';
|
|||||||
import 'package:island/utils/text.dart';
|
import 'package:island/utils/text.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/paging/pagination_list.dart';
|
||||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
enum FileListMode { normal, unindexed }
|
enum FileListMode { normal, unindexed }
|
||||||
@@ -59,7 +59,9 @@ class FileListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (mode.value == FileListMode.normal) {
|
if (mode.value == FileListMode.normal) {
|
||||||
final notifier = ref.read(cloudFileListNotifierProvider.notifier);
|
final notifier = ref.read(
|
||||||
|
indexedCloudFileListNotifierProvider.notifier,
|
||||||
|
);
|
||||||
notifier.setPath(currentPath.value);
|
notifier.setPath(currentPath.value);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -70,7 +72,9 @@ class FileListView extends HookConsumerWidget {
|
|||||||
final unindexedNotifier = ref.read(
|
final unindexedNotifier = ref.read(
|
||||||
unindexedFileListNotifierProvider.notifier,
|
unindexedFileListNotifierProvider.notifier,
|
||||||
);
|
);
|
||||||
final cloudNotifier = ref.read(cloudFileListNotifierProvider.notifier);
|
final cloudNotifier = ref.read(
|
||||||
|
indexedCloudFileListNotifierProvider.notifier,
|
||||||
|
);
|
||||||
final recycled = useState<bool>(false);
|
final recycled = useState<bool>(false);
|
||||||
final poolsAsync = ref.watch(poolsProvider);
|
final poolsAsync = ref.watch(poolsProvider);
|
||||||
final isSelectionMode = useState<bool>(false);
|
final isSelectionMode = useState<bool>(false);
|
||||||
@@ -115,49 +119,50 @@ class FileListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
final isRefreshing = ref.watch(
|
final isRefreshing = ref.watch(
|
||||||
mode.value == FileListMode.normal
|
mode.value == FileListMode.normal
|
||||||
? cloudFileListNotifierProvider.select((value) => value.isLoading)
|
? indexedCloudFileListNotifierProvider.select(
|
||||||
|
(value) => value.isLoading,
|
||||||
|
)
|
||||||
: unindexedFileListNotifierProvider.select(
|
: unindexedFileListNotifierProvider.select(
|
||||||
(value) => value.isLoading,
|
(value) => value.isLoading,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final bodyWidget = switch (mode.value) {
|
final bodyWidget = switch (mode.value) {
|
||||||
FileListMode.unindexed => PagingHelperSliverView(
|
FileListMode.unindexed => PaginationWidget(
|
||||||
provider: unindexedFileListNotifierProvider,
|
provider: unindexedFileListNotifierProvider,
|
||||||
futureRefreshable: unindexedFileListNotifierProvider.future,
|
notifier: unindexedFileListNotifierProvider.notifier,
|
||||||
notifierRefreshable: unindexedFileListNotifierProvider.notifier,
|
isRefreshable: false,
|
||||||
|
isSliver: true,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) =>
|
(data, footer) =>
|
||||||
data.items.isEmpty
|
data.isEmpty
|
||||||
? SliverToBoxAdapter(
|
? SliverToBoxAdapter(
|
||||||
child: _buildEmptyUnindexedFilesHint(ref),
|
child: _buildEmptyUnindexedFilesHint(ref),
|
||||||
)
|
)
|
||||||
: _buildUnindexedFileListContent(
|
: _buildUnindexedFileListContent(
|
||||||
data.items,
|
data,
|
||||||
widgetCount,
|
|
||||||
endItemView,
|
|
||||||
ref,
|
ref,
|
||||||
context,
|
context,
|
||||||
viewMode,
|
viewMode,
|
||||||
isSelectionMode,
|
isSelectionMode,
|
||||||
selectedFileIds,
|
selectedFileIds,
|
||||||
currentVisibleItems,
|
currentVisibleItems,
|
||||||
|
footer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_ => PagingHelperSliverView(
|
_ => PaginationWidget(
|
||||||
provider: cloudFileListNotifierProvider,
|
provider: indexedCloudFileListNotifierProvider,
|
||||||
futureRefreshable: cloudFileListNotifierProvider.future,
|
notifier: indexedCloudFileListNotifierProvider.notifier,
|
||||||
notifierRefreshable: cloudFileListNotifierProvider.notifier,
|
isRefreshable: false,
|
||||||
|
isSliver: true,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) =>
|
(data, footer) =>
|
||||||
data.items.isEmpty
|
data.isEmpty
|
||||||
? SliverToBoxAdapter(
|
? SliverToBoxAdapter(
|
||||||
child: _buildEmptyDirectoryHint(ref, currentPath),
|
child: _buildEmptyDirectoryHint(ref, currentPath),
|
||||||
)
|
)
|
||||||
: _buildFileListContent(
|
: _buildFileListContent(
|
||||||
data.items,
|
data,
|
||||||
widgetCount,
|
|
||||||
endItemView,
|
|
||||||
ref,
|
ref,
|
||||||
context,
|
context,
|
||||||
currentPath,
|
currentPath,
|
||||||
@@ -165,6 +170,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
isSelectionMode,
|
isSelectionMode,
|
||||||
selectedFileIds,
|
selectedFileIds,
|
||||||
currentVisibleItems,
|
currentVisibleItems,
|
||||||
|
footer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@@ -255,7 +261,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
completer.future
|
completer.future
|
||||||
.then((uploadedFile) {
|
.then((uploadedFile) {
|
||||||
if (uploadedFile != null) {
|
if (uploadedFile != null) {
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
ref.invalidate(indexedCloudFileListNotifierProvider);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catchError((error) {
|
.catchError((error) {
|
||||||
@@ -532,7 +538,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
isSelectionMode.value = false;
|
isSelectionMode.value = false;
|
||||||
ref.invalidate(
|
ref.invalidate(
|
||||||
mode.value == FileListMode.normal
|
mode.value == FileListMode.normal
|
||||||
? cloudFileListNotifierProvider
|
? indexedCloudFileListNotifierProvider
|
||||||
: unindexedFileListNotifierProvider,
|
: unindexedFileListNotifierProvider,
|
||||||
);
|
);
|
||||||
showSnackBar('Deleted $count files.');
|
showSnackBar('Deleted $count files.');
|
||||||
@@ -560,8 +566,6 @@ class FileListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
Widget _buildFileListContent(
|
Widget _buildFileListContent(
|
||||||
List<FileListItem> items,
|
List<FileListItem> items,
|
||||||
int widgetCount,
|
|
||||||
Widget endItemView,
|
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
ValueNotifier<String> currentPath,
|
ValueNotifier<String> currentPath,
|
||||||
@@ -569,6 +573,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
ValueNotifier<bool> isSelectionMode,
|
ValueNotifier<bool> isSelectionMode,
|
||||||
ValueNotifier<Set<String>> selectedFileIds,
|
ValueNotifier<Set<String>> selectedFileIds,
|
||||||
ValueNotifier<List<FileListItem>> currentVisibleItems,
|
ValueNotifier<List<FileListItem>> currentVisibleItems,
|
||||||
|
Widget footer,
|
||||||
) {
|
) {
|
||||||
currentVisibleItems.value = items;
|
currentVisibleItems.value = items;
|
||||||
return switch (currentViewMode.value) {
|
return switch (currentViewMode.value) {
|
||||||
@@ -580,11 +585,10 @@ class FileListView extends HookConsumerWidget {
|
|||||||
crossAxisSpacing: 8,
|
crossAxisSpacing: 8,
|
||||||
mainAxisSpacing: 8,
|
mainAxisSpacing: 8,
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == items.length) {
|
||||||
return endItemView;
|
return footer;
|
||||||
}
|
}
|
||||||
|
if (index > items.length) {
|
||||||
if (index >= items.length) {
|
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,16 +619,15 @@ class FileListView extends HookConsumerWidget {
|
|||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, childCount: widgetCount),
|
}, childCount: items.length + 1),
|
||||||
),
|
),
|
||||||
// ListView mode
|
// ListView mode
|
||||||
_ => SliverList.builder(
|
_ => SliverList.builder(
|
||||||
itemCount: widgetCount,
|
itemCount: items.length + 1,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == items.length) {
|
||||||
return endItemView;
|
return footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
final item = items[index];
|
final item = items[index];
|
||||||
return item.map(
|
return item.map(
|
||||||
file:
|
file:
|
||||||
@@ -801,7 +804,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
await client.delete(
|
await client.delete(
|
||||||
'/drive/index/remove/${fileItem.fileIndex.id}',
|
'/drive/index/remove/${fileItem.fileIndex.id}',
|
||||||
);
|
);
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
ref.invalidate(indexedCloudFileListNotifierProvider);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackBar('failedToDeleteFile'.tr());
|
showSnackBar('failedToDeleteFile'.tr());
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1010,14 +1013,13 @@ class FileListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
Widget _buildUnindexedFileListContent(
|
Widget _buildUnindexedFileListContent(
|
||||||
List<FileListItem> items,
|
List<FileListItem> items,
|
||||||
int widgetCount,
|
|
||||||
Widget endItemView,
|
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
ValueNotifier<FileListViewMode> currentViewMode,
|
ValueNotifier<FileListViewMode> currentViewMode,
|
||||||
ValueNotifier<bool> isSelectionMode,
|
ValueNotifier<bool> isSelectionMode,
|
||||||
ValueNotifier<Set<String>> selectedFileIds,
|
ValueNotifier<Set<String>> selectedFileIds,
|
||||||
ValueNotifier<List<FileListItem>> currentVisibleItems,
|
ValueNotifier<List<FileListItem>> currentVisibleItems,
|
||||||
|
Widget footer,
|
||||||
) {
|
) {
|
||||||
currentVisibleItems.value = items;
|
currentVisibleItems.value = items;
|
||||||
return switch (currentViewMode.value) {
|
return switch (currentViewMode.value) {
|
||||||
@@ -1029,11 +1031,10 @@ class FileListView extends HookConsumerWidget {
|
|||||||
crossAxisSpacing: 12,
|
crossAxisSpacing: 12,
|
||||||
mainAxisSpacing: 12,
|
mainAxisSpacing: 12,
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == items.length) {
|
||||||
return endItemView;
|
return footer;
|
||||||
}
|
}
|
||||||
|
if (index > items.length) {
|
||||||
if (index >= items.length) {
|
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,16 +1068,15 @@ class FileListView extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}, childCount: widgetCount),
|
}, childCount: items.length + 1),
|
||||||
),
|
),
|
||||||
// ListView mode
|
// ListView mode
|
||||||
_ => SliverList.builder(
|
_ => SliverList.builder(
|
||||||
itemCount: widgetCount,
|
itemCount: items.length + 1,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == items.length) {
|
||||||
return endItemView;
|
return footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
final item = items[index];
|
final item = items[index];
|
||||||
return item.map(
|
return item.map(
|
||||||
file: (fileItem) {
|
file: (fileItem) {
|
||||||
@@ -1168,7 +1168,7 @@ class FileListView extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.delete('/drive/index/remove/${fileItem.fileIndex.id}');
|
await client.delete('/drive/index/remove/${fileItem.fileIndex.id}');
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
ref.invalidate(indexedCloudFileListNotifierProvider);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackBar('failedToDeleteFile'.tr());
|
showSnackBar('failedToDeleteFile'.tr());
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
167
lib/widgets/paging/pagination_list.dart
Normal file
167
lib/widgets/paging/pagination_list.dart
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/pods/paging.dart';
|
||||||
|
|
||||||
|
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||||
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||||
|
import 'package:visibility_detector/visibility_detector.dart';
|
||||||
|
|
||||||
|
class PaginationList<T> extends HookConsumerWidget {
|
||||||
|
final ProviderListenable<AsyncValue<List<T>>> provider;
|
||||||
|
final Refreshable<PaginationController<T>> notifier;
|
||||||
|
final Widget? Function(BuildContext, int, T) itemBuilder;
|
||||||
|
final bool isRefreshable;
|
||||||
|
final bool isSliver;
|
||||||
|
final bool showDefaultWidgets;
|
||||||
|
final EdgeInsets? padding;
|
||||||
|
const PaginationList({
|
||||||
|
super.key,
|
||||||
|
required this.provider,
|
||||||
|
required this.notifier,
|
||||||
|
required this.itemBuilder,
|
||||||
|
this.isRefreshable = true,
|
||||||
|
this.isSliver = false,
|
||||||
|
this.showDefaultWidgets = true,
|
||||||
|
this.padding,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final data = ref.watch(provider);
|
||||||
|
final noti = ref.watch(notifier);
|
||||||
|
|
||||||
|
if (data.isLoading && data.valueOrNull?.isEmpty == true) {
|
||||||
|
final content = ResponseLoadingWidget();
|
||||||
|
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hasError) {
|
||||||
|
final content = ResponseErrorWidget(
|
||||||
|
error: data.error,
|
||||||
|
onRetry: noti.refresh,
|
||||||
|
);
|
||||||
|
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||||
|
}
|
||||||
|
|
||||||
|
final listView =
|
||||||
|
isSliver
|
||||||
|
? SuperSliverList.builder(
|
||||||
|
itemCount: (data.valueOrNull?.length ?? 0) + 1,
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
if (idx == data.valueOrNull?.length) {
|
||||||
|
return PaginationListFooter(noti: noti, data: data);
|
||||||
|
}
|
||||||
|
final entry = data.valueOrNull?[idx];
|
||||||
|
if (entry != null) return itemBuilder(context, idx, entry);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: SuperListView.builder(
|
||||||
|
padding: padding,
|
||||||
|
itemCount: (data.valueOrNull?.length ?? 0) + 1,
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
if (idx == data.valueOrNull?.length) {
|
||||||
|
return PaginationListFooter(noti: noti, data: data);
|
||||||
|
}
|
||||||
|
final entry = data.valueOrNull?[idx];
|
||||||
|
if (entry != null) return itemBuilder(context, idx, entry);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return isRefreshable
|
||||||
|
? ExtendedRefreshIndicator(onRefresh: noti.refresh, child: listView)
|
||||||
|
: listView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaginationWidget<T> extends HookConsumerWidget {
|
||||||
|
final ProviderListenable<AsyncValue<List<T>>> provider;
|
||||||
|
final Refreshable<PaginationController<T>> notifier;
|
||||||
|
final Widget Function(List<T>, Widget) contentBuilder;
|
||||||
|
final bool isRefreshable;
|
||||||
|
final bool isSliver;
|
||||||
|
final bool showDefaultWidgets;
|
||||||
|
const PaginationWidget({
|
||||||
|
super.key,
|
||||||
|
required this.provider,
|
||||||
|
required this.notifier,
|
||||||
|
required this.contentBuilder,
|
||||||
|
this.isRefreshable = true,
|
||||||
|
this.isSliver = false,
|
||||||
|
this.showDefaultWidgets = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final data = ref.watch(provider);
|
||||||
|
final noti = ref.watch(notifier);
|
||||||
|
|
||||||
|
if (data.isLoading && data.valueOrNull?.isEmpty == true) {
|
||||||
|
final content = ResponseLoadingWidget();
|
||||||
|
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hasError) {
|
||||||
|
final content = ResponseErrorWidget(
|
||||||
|
error: data.error,
|
||||||
|
onRetry: noti.refresh,
|
||||||
|
);
|
||||||
|
return isSliver ? SliverFillRemaining(child: content) : content;
|
||||||
|
}
|
||||||
|
|
||||||
|
final footer = PaginationListFooter(noti: noti, data: data);
|
||||||
|
final content = contentBuilder(data.valueOrNull ?? [], footer);
|
||||||
|
|
||||||
|
return isRefreshable
|
||||||
|
? ExtendedRefreshIndicator(onRefresh: noti.refresh, child: content)
|
||||||
|
: content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaginationListFooter<T> extends StatelessWidget {
|
||||||
|
final PaginationController<T> noti;
|
||||||
|
final AsyncValue<List<T>> data;
|
||||||
|
final bool isSliver;
|
||||||
|
|
||||||
|
const PaginationListFooter({
|
||||||
|
super.key,
|
||||||
|
required this.noti,
|
||||||
|
required this.data,
|
||||||
|
this.isSliver = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final child = SizedBox(
|
||||||
|
height: 64,
|
||||||
|
child: Center(
|
||||||
|
child:
|
||||||
|
data.isLoading
|
||||||
|
? CircularProgressIndicator()
|
||||||
|
: Row(
|
||||||
|
spacing: 8,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.close, size: 16),
|
||||||
|
Text('noFurtherData').tr().fontSize(13),
|
||||||
|
],
|
||||||
|
).opacity(0.9),
|
||||||
|
).padding(all: 8),
|
||||||
|
);
|
||||||
|
|
||||||
|
return VisibilityDetector(
|
||||||
|
key: Key("pagination-list-${noti.hashCode}"),
|
||||||
|
onVisibilityChanged: (VisibilityInfo info) {
|
||||||
|
if (!noti.fetchedAll && !data.isLoading && !data.hasError) {
|
||||||
|
noti.fetchFurther();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: isSliver ? SliverToBoxAdapter(child: child) : child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
import 'package:island/services/file_uploader.dart';
|
import 'package:island/services/file_uploader.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
@@ -17,7 +18,6 @@ import 'package:island/pods/network.dart';
|
|||||||
import 'package:mime/mime.dart';
|
import 'package:mime/mime.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/screens/chat/chat.dart';
|
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
@@ -664,7 +664,7 @@ class _ChatRoomsList extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatRooms = ref.watch(chatroomsJoinedProvider);
|
final chatRooms = ref.watch(chatRoomJoinedNotifierProvider);
|
||||||
|
|
||||||
return chatRooms.when(
|
return chatRooms.when(
|
||||||
data: (rooms) {
|
data: (rooms) {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class FileItem extends HookConsumerWidget {
|
|||||||
if (confirmed != true) return;
|
if (confirmed != true) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _showEditSheet(context, ref);
|
if (context.mounted) await _showEditSheet(context, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showEditSheet(BuildContext context, WidgetRef ref) async {
|
Future<void> _showEditSheet(BuildContext context, WidgetRef ref) async {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
|
|
||||||
class InfoRow extends StatelessWidget {
|
class InfoRow extends StatelessWidget {
|
||||||
final String label;
|
final String label;
|
||||||
final String value;
|
final String? value;
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final bool monospace;
|
final bool monospace;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
@@ -12,7 +12,7 @@ class InfoRow extends StatelessWidget {
|
|||||||
const InfoRow({
|
const InfoRow({
|
||||||
super.key,
|
super.key,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.value,
|
this.value,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.monospace = false,
|
this.monospace = false,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
@@ -20,8 +20,11 @@ class InfoRow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget valueWidget = Text(
|
Widget? valueWidget =
|
||||||
value,
|
value == null
|
||||||
|
? null
|
||||||
|
: Text(
|
||||||
|
value!,
|
||||||
style:
|
style:
|
||||||
monospace
|
monospace
|
||||||
? GoogleFonts.robotoMono(fontSize: 14)
|
? GoogleFonts.robotoMono(fontSize: 14)
|
||||||
@@ -40,13 +43,16 @@ class InfoRow extends StatelessWidget {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
label,
|
label,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style:
|
||||||
|
valueWidget == null
|
||||||
|
? null
|
||||||
|
: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(12),
|
if (valueWidget != null) const Gap(12),
|
||||||
Expanded(flex: 3, child: valueWidget),
|
if (valueWidget != null) Expanded(flex: 3, child: valueWidget),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,8 +369,10 @@ class _EmbeddedPackSwitcherState extends State<_EmbeddedPackSwitcher> {
|
|||||||
children: [
|
children: [
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
// Vertical, scrollable packs rail like common emoji pickers
|
// Vertical, scrollable packs rail like common emoji pickers
|
||||||
SizedBox(
|
Card(
|
||||||
height: 32,
|
margin: EdgeInsets.zero,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 36,
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
@@ -380,22 +382,51 @@ class _EmbeddedPackSwitcherState extends State<_EmbeddedPackSwitcher> {
|
|||||||
final selected = _index == i;
|
final selected = _index == i;
|
||||||
return Tooltip(
|
return Tooltip(
|
||||||
message: packs[i].name,
|
message: packs[i].name,
|
||||||
child: FilterChip(
|
child: AnimatedContainer(
|
||||||
visualDensity: const VisualDensity(
|
duration: const Duration(milliseconds: 200),
|
||||||
horizontal: 0,
|
curve: Curves.easeInOut,
|
||||||
vertical: -4,
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
selected
|
||||||
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
|
: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
border:
|
||||||
|
selected
|
||||||
|
? Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
width: 4,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
label: Text(packs[i].name, overflow: TextOverflow.ellipsis),
|
margin: const EdgeInsets.only(right: 8),
|
||||||
selected: selected,
|
child: InkWell(
|
||||||
onSelected: (_) {
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
onTap: () {
|
||||||
setState(() => _index = i);
|
setState(() => _index = i);
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
},
|
},
|
||||||
|
child: TweenAnimationBuilder<double>(
|
||||||
|
tween: Tween<double>(end: selected ? 4 : 8),
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return packs[i].icon != null
|
||||||
|
? CloudImageWidget(
|
||||||
|
file: packs[i].icon!,
|
||||||
|
).clipRRect(all: value)
|
||||||
|
: CloudImageWidget(
|
||||||
|
file: packs[i].stickers.firstOrNull?.image,
|
||||||
|
).clipRRect(all: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
).padding(vertical: 4),
|
||||||
|
).padding(horizontal: 12),
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
platform :osx, '11.0'
|
platform :osx, '12.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
@@ -214,25 +214,25 @@ PODS:
|
|||||||
- sqflite_darwin (0.0.4):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- sqlite3 (3.50.4):
|
- sqlite3 (3.51.1):
|
||||||
- sqlite3/common (= 3.50.4)
|
- sqlite3/common (= 3.51.1)
|
||||||
- sqlite3/common (3.50.4)
|
- sqlite3/common (3.51.1)
|
||||||
- sqlite3/dbstatvtab (3.50.4):
|
- sqlite3/dbstatvtab (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/fts5 (3.50.4):
|
- sqlite3/fts5 (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/math (3.50.4):
|
- sqlite3/math (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/perf-threadsafe (3.50.4):
|
- sqlite3/perf-threadsafe (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/rtree (3.50.4):
|
- sqlite3/rtree (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3/session (3.50.4):
|
- sqlite3/session (3.51.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3_flutter_libs (0.0.1):
|
- sqlite3_flutter_libs (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- sqlite3 (~> 3.50.4)
|
- sqlite3 (~> 3.51.1)
|
||||||
- sqlite3/dbstatvtab
|
- sqlite3/dbstatvtab
|
||||||
- sqlite3/fts5
|
- sqlite3/fts5
|
||||||
- sqlite3/math
|
- sqlite3/math
|
||||||
@@ -456,8 +456,8 @@ SPEC CHECKSUMS:
|
|||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
sign_in_with_apple: 6673c03c9e3643f6c8d33601943fbfa9ae99f94e
|
sign_in_with_apple: 6673c03c9e3643f6c8d33601943fbfa9ae99f94e
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
||||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41
|
||||||
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
|
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
|
||||||
syncfusion_pdfviewer_macos: b3b110c68039178ca4105dd03ef38761eca3b36b
|
syncfusion_pdfviewer_macos: b3b110c68039178ca4105dd03ef38761eca3b36b
|
||||||
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
|
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
|
||||||
@@ -466,6 +466,6 @@ SPEC CHECKSUMS:
|
|||||||
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
||||||
window_manager: b729e31d38fb04905235df9ea896128991cad99e
|
window_manager: b729e31d38fb04905235df9ea896128991cad99e
|
||||||
|
|
||||||
PODFILE CHECKSUM: 346bfb2deb41d4a6ebd6f6799f92188bde2d246f
|
PODFILE CHECKSUM: 1e95c36afbfd1cb6423ceca4de7a8e1b256fb6ac
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
@@ -613,7 +613,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
@@ -751,7 +751,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -777,7 +777,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
|
|||||||
76
pubspec.lock
76
pubspec.lock
@@ -1257,10 +1257,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_fonts
|
name: google_fonts
|
||||||
sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c"
|
sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.2"
|
version: "6.3.3"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1545,10 +1545,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_android
|
name: local_auth_android
|
||||||
sha256: "04dd9050b59cb4bcaf051d44eec65865779a9b2f6daccc523f59f96b565a5d54"
|
sha256: "162b8e177fd9978c4620da2a8002a5c6bed4d20f0c6daf5137e72e9a8b767d2e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.4"
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1633,18 +1633,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: material_symbols_icons
|
name: material_symbols_icons
|
||||||
sha256: "9a7de58ffc299c8e362b4e860e36e1d198fa0981a894376fe1b6bfe52773e15b"
|
sha256: "02555a48e1ec02b16e532dfd4ef13c4f6bf7ec7c20230e58e56641a393433dc3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2874.0"
|
version: "4.2892.0"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: media_kit
|
name: media_kit
|
||||||
sha256: dfd5ab85d49a1806b1314a0b81f3d14da48f0db0a657336b2d77c5f17db28944
|
sha256: "2a207ea7baf1a2ea2ff2016d512e572ca6fc02a937769effb5c27b4d682b4a53"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.3"
|
||||||
media_kit_libs_android_video:
|
media_kit_libs_android_video:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1697,10 +1697,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: media_kit_video
|
name: media_kit_video
|
||||||
sha256: eac9b5f27310afe6def49f9b785cef155f99f1db6079d2b2b127b8bddafb6472
|
sha256: afaa509e7b7e0bf247557a3a740cde903a52c34ace9810f94500e127bd7b043d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.1"
|
||||||
menu_base:
|
menu_base:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2354,10 +2354,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "46a46fd64659eff15f4638bbe19de43f9483f0e0bf024a9fb6b3582064bacc7b"
|
sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.17"
|
version: "2.4.18"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2543,10 +2543,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlite3_flutter_libs
|
name: sqlite3_flutter_libs
|
||||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
sha256: "1e800ebe7f85a80a66adacaa6febe4d5f4d8b75f244e9838a27cb2ffc7aec08d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.40"
|
version: "0.5.41"
|
||||||
sqlparser:
|
sqlparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2639,18 +2639,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_core
|
name: syncfusion_flutter_core
|
||||||
sha256: a55762b7d6fdfe588378127b7b186aad418c04a8670c40d3d3438fa09e3d259a
|
sha256: e68a7e214659faf0df483c760d295ab58e376a639285d2a9f7d1e43351efcbb3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_flutter_pdf:
|
syncfusion_flutter_pdf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_pdf
|
name: syncfusion_flutter_pdf
|
||||||
sha256: ac85ff223e830f3f9d4f799bc5817e1ce6a136d60b3f8dac28bd9d6860db56e0
|
sha256: "7a09952cc5193f78211a84eed3f0bd67876861997221b2479889013951fb5fba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_flutter_pdfviewer:
|
syncfusion_flutter_pdfviewer:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -2663,50 +2663,50 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_signaturepad
|
name: syncfusion_flutter_signaturepad
|
||||||
sha256: ea5f6d5245f2297d1e6d296bfd43d5bd1ce5a13f8e24b6824fcd58ba9e152f72
|
sha256: f65d43512fccb2733dcee292a36d561e1963c61f86482007d70c0d4a007718f1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_pdfviewer_linux:
|
syncfusion_pdfviewer_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_pdfviewer_linux
|
name: syncfusion_pdfviewer_linux
|
||||||
sha256: "9f7c99392acad22d3e837490226ccad85a172a9b0b958a9e6346237cb966c9c8"
|
sha256: "2a80a35c11fd3f06444ce4cad2e7b36ce1cea28030379186a8545851588d1784"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_pdfviewer_macos:
|
syncfusion_pdfviewer_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_pdfviewer_macos
|
name: syncfusion_pdfviewer_macos
|
||||||
sha256: "4965ce7c8ccdd6d9cb1248bd87af4c4f69af7e7bdd822e1f13a94e25dc62262b"
|
sha256: "9bf2c720d59539cf2e621b9b5214301c3ae9d4c62c1a5a2e0e9c2b20f9e4727d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_pdfviewer_platform_interface:
|
syncfusion_pdfviewer_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_pdfviewer_platform_interface
|
name: syncfusion_pdfviewer_platform_interface
|
||||||
sha256: bc1121557352cb1b9710a79963300799dc6ff129522e04a47fcbc7a958e2feb8
|
sha256: b5eded6e60270422db529549142cc16e927dbb7317afe3559140bf4ec4301ac3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_pdfviewer_web:
|
syncfusion_pdfviewer_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_pdfviewer_web
|
name: syncfusion_pdfviewer_web
|
||||||
sha256: e4b12a8d9e7d3e867a5d5c5153e94db028b43b52b7b11be3a1c36f49b87c93db
|
sha256: "251e4d43a54958c17ba33bf27a0ca143224663755cac68fe2fe8fb0cce5bd846"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
syncfusion_pdfviewer_windows:
|
syncfusion_pdfviewer_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_pdfviewer_windows
|
name: syncfusion_pdfviewer_windows
|
||||||
sha256: "057f85e3978ebb2550121c6b2237db63f3b195b17e53806b1745dcc2c743bc7d"
|
sha256: "33014789595c9782337773e2c891e25fc4b22ede60cc5c95be032765c5d43989"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "31.2.15"
|
version: "31.2.16"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2727,34 +2727,34 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: talker
|
name: talker
|
||||||
sha256: "31b3081b6787c93b41bc14182229681a4a48b8b22f4b368f3493e7f41825a36d"
|
sha256: "5ab800e29d91ce7728fa218c8a7d46f6c228202ac89af650c3f82cb938a64ba6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.3"
|
||||||
talker_dio_logger:
|
talker_dio_logger:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: talker_dio_logger
|
name: talker_dio_logger
|
||||||
sha256: "5534edf33aa913bdc9b4c733baee4795a884e46e6e632b024762738b53622da5"
|
sha256: "214a31d2ecc488ae6abf623ca9dac3831d34e66195f633bd1909a9d0c282ab8c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.3"
|
||||||
talker_flutter:
|
talker_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: talker_flutter
|
name: talker_flutter
|
||||||
sha256: cd276e639841ddcd50effe86bc16e04ff9a58d1a06d470b0c3c7d62f13579ae8
|
sha256: "79158cf0fe3fd2bcdb1dc6f5a870cb623f18d0b59a4fd87414f53ce446d80a45"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.3"
|
||||||
talker_logger:
|
talker_logger:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: talker_logger
|
name: talker_logger
|
||||||
sha256: "5e2cc1dd9cbb7811c44ed620b5365768e30b86b6a65e909a5c2324722517f077"
|
sha256: bc75612ace4dbb82fbad36181ff27e95b1ee152c719c2fea6b8ac59c4f091cd2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.3"
|
||||||
talker_riverpod_logger:
|
talker_riverpod_logger:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
16
pubspec.yaml
16
pubspec.yaml
@@ -52,13 +52,13 @@ dependencies:
|
|||||||
flutter_highlight: ^0.7.0
|
flutter_highlight: ^0.7.0
|
||||||
uuid: ^4.5.2
|
uuid: ^4.5.2
|
||||||
url_launcher: ^6.3.2
|
url_launcher: ^6.3.2
|
||||||
google_fonts: ^6.3.2
|
google_fonts: ^6.3.3
|
||||||
gap: ^3.0.1
|
gap: ^3.0.1
|
||||||
cached_network_image: ^3.4.1
|
cached_network_image: ^3.4.1
|
||||||
web: ^1.1.1
|
web: ^1.1.1
|
||||||
flutter_blurhash: ^0.9.1
|
flutter_blurhash: ^0.9.1
|
||||||
media_kit: ^1.2.2
|
media_kit: ^1.2.3
|
||||||
media_kit_video: ^2.0.0
|
media_kit_video: ^2.0.1
|
||||||
media_kit_libs_video: ^1.0.7
|
media_kit_libs_video: ^1.0.7
|
||||||
flutter_cache_manager: ^3.4.1
|
flutter_cache_manager: ^3.4.1
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ dependencies:
|
|||||||
flutter_udid: ^4.1.1
|
flutter_udid: ^4.1.1
|
||||||
firebase_core: ^4.2.1
|
firebase_core: ^4.2.1
|
||||||
web_socket_channel: ^3.0.3
|
web_socket_channel: ^3.0.3
|
||||||
material_symbols_icons: ^4.2874.0
|
material_symbols_icons: ^4.2892.0
|
||||||
drift: ^2.28.2
|
drift: ^2.28.2
|
||||||
drift_flutter: ^0.2.7
|
drift_flutter: ^0.2.7
|
||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
@@ -155,10 +155,10 @@ dependencies:
|
|||||||
dart_ipc: ^1.0.1
|
dart_ipc: ^1.0.1
|
||||||
pretty_diff_text: ^2.1.0
|
pretty_diff_text: ^2.1.0
|
||||||
window_manager: ^0.5.1
|
window_manager: ^0.5.1
|
||||||
talker: ^5.1.1
|
talker: ^5.1.3
|
||||||
talker_flutter: ^5.1.1
|
talker_flutter: ^5.1.3
|
||||||
talker_logger: ^5.1.1
|
talker_logger: ^5.1.3
|
||||||
talker_dio_logger: ^5.1.1
|
talker_dio_logger: ^5.1.3
|
||||||
talker_riverpod_logger: ^5.0.1
|
talker_riverpod_logger: ^5.0.1
|
||||||
syncfusion_flutter_pdfviewer: ^31.1.21
|
syncfusion_flutter_pdfviewer: ^31.1.21
|
||||||
swipe_to: ^1.0.6
|
swipe_to: ^1.0.6
|
||||||
|
|||||||
Reference in New Issue
Block a user