Compare commits
15 Commits
3.2.0+127
...
a127b5bace
Author | SHA1 | Date | |
---|---|---|---|
|
a127b5bace | ||
|
b2097cf044 | ||
|
701f29748d | ||
|
9e40ed4600 | ||
|
c90e6fe661 | ||
|
569483300d | ||
|
bab602d98b | ||
|
b4f2bb803a | ||
|
03bfed6f46 | ||
|
f98e5a0aec | ||
|
3d473e2fec | ||
|
0b6efa373a | ||
|
9b60e96cde | ||
|
81cd9b2082 | ||
|
923d5d7514 |
@@ -854,5 +854,26 @@
|
||||
"failedToLoadUserInfo": "Failed to load user info",
|
||||
"failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.",
|
||||
"failedToLoadUserInfoUnauthorized": "It seems your session has been logged out or not available anymore, you can still try agian to fetch the user info if you want.",
|
||||
"okay": "Okay"
|
||||
"okay": "Okay",
|
||||
"postDetails": "Post Details",
|
||||
"postCount": {
|
||||
"zero": "No posts",
|
||||
"one": "{} post",
|
||||
"other": "{} posts"
|
||||
},
|
||||
"mimeType": "MIME Type",
|
||||
"fileSize": "File Size",
|
||||
"fileHash": "File Hash",
|
||||
"exifData": "EXIF Data",
|
||||
"postShuffle": "Shuffle Posts",
|
||||
"leveling": "Leveling",
|
||||
"levelingHistory": "Leveling History",
|
||||
"stellarProgram": "Stellar Program",
|
||||
"socialCredits": "Social Credits",
|
||||
"credits": "Credits",
|
||||
"socialCreditsDescription": "Social Credit is a way for Solar Network to evaluate users. It is calculated based on their behavior and interactions. With a base score of 100, higher scores indicate a user's credibility within the community. Scores change over time to reflect a user's recent behavior. Users with higher credit ratings enjoy more benefits, while users with lower credit ratings may have some functionality restricted.",
|
||||
"socialCreditsLevelPoor": "Poor",
|
||||
"socialCreditsLevelNormal": "Normal",
|
||||
"socialCreditsLevelGood": "Good",
|
||||
"socialCreditsLevelExcellent": "Excellent"
|
||||
}
|
||||
|
@@ -828,5 +828,20 @@
|
||||
"failedToLoadUserInfo": "加载用户信息失败",
|
||||
"failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试",
|
||||
"failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。",
|
||||
"okay": "了解"
|
||||
"okay": "了解",
|
||||
"postDetails": "帖子详情",
|
||||
"mimeType": "类型",
|
||||
"fileSize": "大小",
|
||||
"fileHash": "哈希",
|
||||
"exifData": "EXIF 数据",
|
||||
"leveling": "等级",
|
||||
"levelingHistory": "经验记录",
|
||||
"stellarProgram": "恒星计划",
|
||||
"socialCredits": "社会信用点",
|
||||
"credits": "信用",
|
||||
"socialCreditsDescription": "社会信用是 Solar Network 评价用户的一种方式。它基于用户的行为和互动来计算。以 100 分为基准,分数越高表示用户在社区中的信誉越好。分数会随着时间的推移而变化,反映用户的最新行为。信用等级高的用户可以享受到更多的福利,反之的用户部份功能可能受到限制。",
|
||||
"socialCreditsLevelPoor": "糟糕",
|
||||
"socialCreditsLevelNormal": "正常",
|
||||
"socialCreditsLevelGood": "良好",
|
||||
"socialCreditsLevelExcellent": "优秀"
|
||||
}
|
||||
|
@@ -208,3 +208,37 @@ sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge {
|
||||
factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnAuthDeviceWithChallengeFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnExperienceRecord with _$SnExperienceRecord {
|
||||
const factory SnExperienceRecord({
|
||||
required String id,
|
||||
required int delta,
|
||||
required String reasonType,
|
||||
required String reason,
|
||||
@Default(1.0) double? bonusMultiplier,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnExperienceRecord;
|
||||
|
||||
factory SnExperienceRecord.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnExperienceRecordFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnSocialCreditRecord with _$SnSocialCreditRecord {
|
||||
const factory SnSocialCreditRecord({
|
||||
required String id,
|
||||
required double delta,
|
||||
required String reasonType,
|
||||
required String reason,
|
||||
required DateTime? expiredAt,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnSocialCreditRecord;
|
||||
|
||||
factory SnSocialCreditRecord.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnSocialCreditRecordFromJson(json);
|
||||
}
|
||||
|
@@ -3018,6 +3018,562 @@ as bool,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SnExperienceRecord {
|
||||
|
||||
String get id; int get delta; String get reasonType; String get reason; double? get bonusMultiplier; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||
/// Create a copy of SnExperienceRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnExperienceRecordCopyWith<SnExperienceRecord> get copyWith => _$SnExperienceRecordCopyWithImpl<SnExperienceRecord>(this as SnExperienceRecord, _$identity);
|
||||
|
||||
/// Serializes this SnExperienceRecord to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnExperienceRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.bonusMultiplier, bonusMultiplier) || other.bonusMultiplier == bonusMultiplier)&&(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)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,bonusMultiplier,createdAt,updatedAt,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnExperienceRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, bonusMultiplier: $bonusMultiplier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SnExperienceRecordCopyWith<$Res> {
|
||||
factory $SnExperienceRecordCopyWith(SnExperienceRecord value, $Res Function(SnExperienceRecord) _then) = _$SnExperienceRecordCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$SnExperienceRecordCopyWithImpl<$Res>
|
||||
implements $SnExperienceRecordCopyWith<$Res> {
|
||||
_$SnExperienceRecordCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SnExperienceRecord _self;
|
||||
final $Res Function(SnExperienceRecord) _then;
|
||||
|
||||
/// Create a copy of SnExperienceRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? bonusMultiplier = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable
|
||||
as int,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable
|
||||
as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable
|
||||
as String,bonusMultiplier: freezed == bonusMultiplier ? _self.bonusMultiplier : bonusMultiplier // ignore: cast_nullable_to_non_nullable
|
||||
as double?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [SnExperienceRecord].
|
||||
extension SnExperienceRecordPatterns on SnExperienceRecord {
|
||||
/// 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( _SnExperienceRecord value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord() 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( _SnExperienceRecord value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord():
|
||||
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( _SnExperienceRecord value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord() 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( String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord() when $default != null:
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);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( String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord():
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||
}
|
||||
/// 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( String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnExperienceRecord() when $default != null:
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnExperienceRecord implements SnExperienceRecord {
|
||||
const _SnExperienceRecord({required this.id, required this.delta, required this.reasonType, required this.reason, this.bonusMultiplier = 1.0, required this.createdAt, required this.updatedAt, required this.deletedAt});
|
||||
factory _SnExperienceRecord.fromJson(Map<String, dynamic> json) => _$SnExperienceRecordFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@override final int delta;
|
||||
@override final String reasonType;
|
||||
@override final String reason;
|
||||
@override@JsonKey() final double? bonusMultiplier;
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override final DateTime? deletedAt;
|
||||
|
||||
/// Create a copy of SnExperienceRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SnExperienceRecordCopyWith<_SnExperienceRecord> get copyWith => __$SnExperienceRecordCopyWithImpl<_SnExperienceRecord>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$SnExperienceRecordToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnExperienceRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.bonusMultiplier, bonusMultiplier) || other.bonusMultiplier == bonusMultiplier)&&(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)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,bonusMultiplier,createdAt,updatedAt,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnExperienceRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, bonusMultiplier: $bonusMultiplier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SnExperienceRecordCopyWith<$Res> implements $SnExperienceRecordCopyWith<$Res> {
|
||||
factory _$SnExperienceRecordCopyWith(_SnExperienceRecord value, $Res Function(_SnExperienceRecord) _then) = __$SnExperienceRecordCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$SnExperienceRecordCopyWithImpl<$Res>
|
||||
implements _$SnExperienceRecordCopyWith<$Res> {
|
||||
__$SnExperienceRecordCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SnExperienceRecord _self;
|
||||
final $Res Function(_SnExperienceRecord) _then;
|
||||
|
||||
/// Create a copy of SnExperienceRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? bonusMultiplier = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
return _then(_SnExperienceRecord(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable
|
||||
as int,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable
|
||||
as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable
|
||||
as String,bonusMultiplier: freezed == bonusMultiplier ? _self.bonusMultiplier : bonusMultiplier // ignore: cast_nullable_to_non_nullable
|
||||
as double?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SnSocialCreditRecord {
|
||||
|
||||
String get id; double get delta; String get reasonType; String get reason; DateTime? get expiredAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||
/// Create a copy of SnSocialCreditRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnSocialCreditRecordCopyWith<SnSocialCreditRecord> get copyWith => _$SnSocialCreditRecordCopyWithImpl<SnSocialCreditRecord>(this as SnSocialCreditRecord, _$identity);
|
||||
|
||||
/// Serializes this SnSocialCreditRecord to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnSocialCreditRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(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)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,expiredAt,createdAt,updatedAt,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnSocialCreditRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SnSocialCreditRecordCopyWith<$Res> {
|
||||
factory $SnSocialCreditRecordCopyWith(SnSocialCreditRecord value, $Res Function(SnSocialCreditRecord) _then) = _$SnSocialCreditRecordCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$SnSocialCreditRecordCopyWithImpl<$Res>
|
||||
implements $SnSocialCreditRecordCopyWith<$Res> {
|
||||
_$SnSocialCreditRecordCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SnSocialCreditRecord _self;
|
||||
final $Res Function(SnSocialCreditRecord) _then;
|
||||
|
||||
/// Create a copy of SnSocialCreditRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable
|
||||
as double,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable
|
||||
as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable
|
||||
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [SnSocialCreditRecord].
|
||||
extension SnSocialCreditRecordPatterns on SnSocialCreditRecord {
|
||||
/// 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( _SnSocialCreditRecord value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord() 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( _SnSocialCreditRecord value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord():
|
||||
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( _SnSocialCreditRecord value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord() 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( String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord() when $default != null:
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);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( String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord():
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||
}
|
||||
/// 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( String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnSocialCreditRecord() when $default != null:
|
||||
return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnSocialCreditRecord implements SnSocialCreditRecord {
|
||||
const _SnSocialCreditRecord({required this.id, required this.delta, required this.reasonType, required this.reason, required this.expiredAt, required this.createdAt, required this.updatedAt, required this.deletedAt});
|
||||
factory _SnSocialCreditRecord.fromJson(Map<String, dynamic> json) => _$SnSocialCreditRecordFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@override final double delta;
|
||||
@override final String reasonType;
|
||||
@override final String reason;
|
||||
@override final DateTime? expiredAt;
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override final DateTime? deletedAt;
|
||||
|
||||
/// Create a copy of SnSocialCreditRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SnSocialCreditRecordCopyWith<_SnSocialCreditRecord> get copyWith => __$SnSocialCreditRecordCopyWithImpl<_SnSocialCreditRecord>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$SnSocialCreditRecordToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnSocialCreditRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(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)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,expiredAt,createdAt,updatedAt,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnSocialCreditRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SnSocialCreditRecordCopyWith<$Res> implements $SnSocialCreditRecordCopyWith<$Res> {
|
||||
factory _$SnSocialCreditRecordCopyWith(_SnSocialCreditRecord value, $Res Function(_SnSocialCreditRecord) _then) = __$SnSocialCreditRecordCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$SnSocialCreditRecordCopyWithImpl<$Res>
|
||||
implements _$SnSocialCreditRecordCopyWith<$Res> {
|
||||
__$SnSocialCreditRecordCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SnSocialCreditRecord _self;
|
||||
final $Res Function(_SnSocialCreditRecord) _then;
|
||||
|
||||
/// Create a copy of SnSocialCreditRecord
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
return _then(_SnSocialCreditRecord(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable
|
||||
as double,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable
|
||||
as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable
|
||||
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
@@ -348,3 +348,62 @@ Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson(
|
||||
'challenges': instance.challenges.map((e) => e.toJson()).toList(),
|
||||
'is_current': instance.isCurrent,
|
||||
};
|
||||
|
||||
_SnExperienceRecord _$SnExperienceRecordFromJson(Map<String, dynamic> json) =>
|
||||
_SnExperienceRecord(
|
||||
id: json['id'] as String,
|
||||
delta: (json['delta'] as num).toInt(),
|
||||
reasonType: json['reason_type'] as String,
|
||||
reason: json['reason'] as String,
|
||||
bonusMultiplier: (json['bonus_multiplier'] as num?)?.toDouble() ?? 1.0,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt:
|
||||
json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnExperienceRecordToJson(_SnExperienceRecord instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'delta': instance.delta,
|
||||
'reason_type': instance.reasonType,
|
||||
'reason': instance.reason,
|
||||
'bonus_multiplier': instance.bonusMultiplier,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnSocialCreditRecord _$SnSocialCreditRecordFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnSocialCreditRecord(
|
||||
id: json['id'] as String,
|
||||
delta: (json['delta'] as num).toDouble(),
|
||||
reasonType: json['reason_type'] as String,
|
||||
reason: json['reason'] as String,
|
||||
expiredAt:
|
||||
json['expired_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expired_at'] as String),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt:
|
||||
json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnSocialCreditRecordToJson(
|
||||
_SnSocialCreditRecord instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'delta': instance.delta,
|
||||
'reason_type': instance.reasonType,
|
||||
'reason': instance.reason,
|
||||
'expired_at': instance.expiredAt?.toIso8601String(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
@@ -104,7 +104,7 @@ sealed class SnChatMember with _$SnChatMember {
|
||||
sealed class SnChatSummary with _$SnChatSummary {
|
||||
const factory SnChatSummary({
|
||||
required int unreadCount,
|
||||
required SnChatMessage lastMessage,
|
||||
required SnChatMessage? lastMessage,
|
||||
}) = _SnChatSummary;
|
||||
|
||||
factory SnChatSummary.fromJson(Map<String, dynamic> json) =>
|
||||
|
@@ -1410,7 +1410,7 @@ $SnAccountStatusCopyWith<$Res>? get status {
|
||||
/// @nodoc
|
||||
mixin _$SnChatSummary {
|
||||
|
||||
int get unreadCount; SnChatMessage get lastMessage;
|
||||
int get unreadCount; SnChatMessage? get lastMessage;
|
||||
/// Create a copy of SnChatSummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -1443,11 +1443,11 @@ abstract mixin class $SnChatSummaryCopyWith<$Res> {
|
||||
factory $SnChatSummaryCopyWith(SnChatSummary value, $Res Function(SnChatSummary) _then) = _$SnChatSummaryCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int unreadCount, SnChatMessage lastMessage
|
||||
int unreadCount, SnChatMessage? lastMessage
|
||||
});
|
||||
|
||||
|
||||
$SnChatMessageCopyWith<$Res> get lastMessage;
|
||||
$SnChatMessageCopyWith<$Res>? get lastMessage;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -1460,20 +1460,23 @@ class _$SnChatSummaryCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnChatSummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? unreadCount = null,Object? lastMessage = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? unreadCount = null,Object? lastMessage = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,lastMessage: null == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMessage,
|
||||
as int,lastMessage: freezed == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMessage?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of SnChatSummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMessageCopyWith<$Res> get lastMessage {
|
||||
$SnChatMessageCopyWith<$Res>? get lastMessage {
|
||||
if (_self.lastMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) {
|
||||
return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) {
|
||||
return _then(_self.copyWith(lastMessage: value));
|
||||
});
|
||||
}
|
||||
@@ -1555,7 +1558,7 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int unreadCount, SnChatMessage lastMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int unreadCount, SnChatMessage? lastMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnChatSummary() when $default != null:
|
||||
return $default(_that.unreadCount,_that.lastMessage);case _:
|
||||
@@ -1576,7 +1579,7 @@ return $default(_that.unreadCount,_that.lastMessage);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int unreadCount, SnChatMessage lastMessage) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int unreadCount, SnChatMessage? lastMessage) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnChatSummary():
|
||||
return $default(_that.unreadCount,_that.lastMessage);}
|
||||
@@ -1593,7 +1596,7 @@ return $default(_that.unreadCount,_that.lastMessage);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int unreadCount, SnChatMessage lastMessage)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int unreadCount, SnChatMessage? lastMessage)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnChatSummary() when $default != null:
|
||||
return $default(_that.unreadCount,_that.lastMessage);case _:
|
||||
@@ -1612,7 +1615,7 @@ class _SnChatSummary implements SnChatSummary {
|
||||
factory _SnChatSummary.fromJson(Map<String, dynamic> json) => _$SnChatSummaryFromJson(json);
|
||||
|
||||
@override final int unreadCount;
|
||||
@override final SnChatMessage lastMessage;
|
||||
@override final SnChatMessage? lastMessage;
|
||||
|
||||
/// Create a copy of SnChatSummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1647,11 +1650,11 @@ abstract mixin class _$SnChatSummaryCopyWith<$Res> implements $SnChatSummaryCopy
|
||||
factory _$SnChatSummaryCopyWith(_SnChatSummary value, $Res Function(_SnChatSummary) _then) = __$SnChatSummaryCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int unreadCount, SnChatMessage lastMessage
|
||||
int unreadCount, SnChatMessage? lastMessage
|
||||
});
|
||||
|
||||
|
||||
@override $SnChatMessageCopyWith<$Res> get lastMessage;
|
||||
@override $SnChatMessageCopyWith<$Res>? get lastMessage;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -1664,11 +1667,11 @@ class __$SnChatSummaryCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnChatSummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? unreadCount = null,Object? lastMessage = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? unreadCount = null,Object? lastMessage = freezed,}) {
|
||||
return _then(_SnChatSummary(
|
||||
unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,lastMessage: null == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMessage,
|
||||
as int,lastMessage: freezed == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as SnChatMessage?,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1676,9 +1679,12 @@ as SnChatMessage,
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnChatMessageCopyWith<$Res> get lastMessage {
|
||||
$SnChatMessageCopyWith<$Res>? get lastMessage {
|
||||
if (_self.lastMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) {
|
||||
return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) {
|
||||
return _then(_self.copyWith(lastMessage: value));
|
||||
});
|
||||
}
|
||||
|
@@ -213,7 +213,10 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) =>
|
||||
_SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) =>
|
||||
_SnChatSummary(
|
||||
unreadCount: (json['unread_count'] as num).toInt(),
|
||||
lastMessage: SnChatMessage.fromJson(
|
||||
lastMessage:
|
||||
json['last_message'] == null
|
||||
? null
|
||||
: SnChatMessage.fromJson(
|
||||
json['last_message'] as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
@@ -221,7 +224,7 @@ _SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) =>
|
||||
Map<String, dynamic> _$SnChatSummaryToJson(_SnChatSummary instance) =>
|
||||
<String, dynamic>{
|
||||
'unread_count': instance.unreadCount,
|
||||
'last_message': instance.lastMessage.toJson(),
|
||||
'last_message': instance.lastMessage?.toJson(),
|
||||
};
|
||||
|
||||
_MessageChange _$MessageChangeFromJson(Map<String, dynamic> json) =>
|
||||
|
@@ -15,6 +15,7 @@ sealed class SnPostCategory with _$SnPostCategory {
|
||||
required String slug,
|
||||
String? name,
|
||||
@Default([]) List<SnPost> posts,
|
||||
@Default(0) int usage,
|
||||
}) = _SnPostCategory;
|
||||
|
||||
factory SnPostCategory.fromJson(Map<String, dynamic> json) =>
|
||||
|
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SnPostCategory {
|
||||
|
||||
String get id; String get slug; String? get name; List<SnPost> get posts;
|
||||
String get id; String get slug; String? get name; List<SnPost> get posts; int get usage;
|
||||
/// Create a copy of SnPostCategory
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $SnPostCategoryCopyWith<SnPostCategory> get copyWith => _$SnPostCategoryCopyWith
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)&&(identical(other.usage, usage) || other.usage == usage));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts));
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts),usage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts)';
|
||||
return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ abstract mixin class $SnPostCategoryCopyWith<$Res> {
|
||||
factory $SnPostCategoryCopyWith(SnPostCategory value, $Res Function(SnPostCategory) _then) = _$SnPostCategoryCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String slug, String? name, List<SnPost> posts
|
||||
String id, String slug, String? name, List<SnPost> posts, int usage
|
||||
});
|
||||
|
||||
|
||||
@@ -65,13 +65,14 @@ class _$SnPostCategoryCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostCategory
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnPost>,
|
||||
as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -153,10 +154,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts, int usage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostCategory() when $default != null:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -174,10 +175,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts, int usage) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostCategory():
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);}
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -191,10 +192,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String? name, List<SnPost> posts)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String? name, List<SnPost> posts, int usage)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostCategory() when $default != null:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -206,7 +207,7 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnPostCategory extends SnPostCategory {
|
||||
const _SnPostCategory({required this.id, required this.slug, this.name, final List<SnPost> posts = const []}): _posts = posts,super._();
|
||||
const _SnPostCategory({required this.id, required this.slug, this.name, final List<SnPost> posts = const [], this.usage = 0}): _posts = posts,super._();
|
||||
factory _SnPostCategory.fromJson(Map<String, dynamic> json) => _$SnPostCategoryFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@@ -219,6 +220,7 @@ class _SnPostCategory extends SnPostCategory {
|
||||
return EqualUnmodifiableListView(_posts);
|
||||
}
|
||||
|
||||
@override@JsonKey() final int usage;
|
||||
|
||||
/// Create a copy of SnPostCategory
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -233,16 +235,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)&&(identical(other.usage, usage) || other.usage == usage));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts));
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts),usage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts)';
|
||||
return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +255,7 @@ abstract mixin class _$SnPostCategoryCopyWith<$Res> implements $SnPostCategoryCo
|
||||
factory _$SnPostCategoryCopyWith(_SnPostCategory value, $Res Function(_SnPostCategory) _then) = __$SnPostCategoryCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String slug, String? name, List<SnPost> posts
|
||||
String id, String slug, String? name, List<SnPost> posts, int usage
|
||||
});
|
||||
|
||||
|
||||
@@ -270,13 +272,14 @@ class __$SnPostCategoryCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostCategory
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) {
|
||||
return _then(_SnPostCategory(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnPost>,
|
||||
as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@ _SnPostCategory _$SnPostCategoryFromJson(Map<String, dynamic> json) =>
|
||||
?.map((e) => SnPost.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
usage: (json['usage'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnPostCategoryToJson(_SnPostCategory instance) =>
|
||||
@@ -24,4 +25,5 @@ Map<String, dynamic> _$SnPostCategoryToJson(_SnPostCategory instance) =>
|
||||
'slug': instance.slug,
|
||||
'name': instance.name,
|
||||
'posts': instance.posts.map((e) => e.toJson()).toList(),
|
||||
'usage': instance.usage,
|
||||
};
|
||||
|
@@ -11,6 +11,7 @@ sealed class SnPostTag with _$SnPostTag {
|
||||
required String slug,
|
||||
String? name,
|
||||
@Default([]) List<SnPost> posts,
|
||||
@Default(0) int usage,
|
||||
}) = _SnPostTag;
|
||||
|
||||
factory SnPostTag.fromJson(Map<String, dynamic> json) =>
|
||||
|
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SnPostTag {
|
||||
|
||||
String get id; String get slug; String? get name; List<SnPost> get posts;
|
||||
String get id; String get slug; String? get name; List<SnPost> get posts; int get usage;
|
||||
/// Create a copy of SnPostTag
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $SnPostTagCopyWith<SnPostTag> get copyWith => _$SnPostTagCopyWithImpl<SnPostTag>
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)&&(identical(other.usage, usage) || other.usage == usage));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts));
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts),usage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts)';
|
||||
return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ abstract mixin class $SnPostTagCopyWith<$Res> {
|
||||
factory $SnPostTagCopyWith(SnPostTag value, $Res Function(SnPostTag) _then) = _$SnPostTagCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String slug, String? name, List<SnPost> posts
|
||||
String id, String slug, String? name, List<SnPost> posts, int usage
|
||||
});
|
||||
|
||||
|
||||
@@ -65,13 +65,14 @@ class _$SnPostTagCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostTag
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnPost>,
|
||||
as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -153,10 +154,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts, int usage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostTag() when $default != null:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -174,10 +175,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String? name, List<SnPost> posts, int usage) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostTag():
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);}
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -191,10 +192,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String? name, List<SnPost> posts)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String? name, List<SnPost> posts, int usage)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostTag() when $default != null:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -206,7 +207,7 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _:
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnPostTag implements SnPostTag {
|
||||
const _SnPostTag({required this.id, required this.slug, this.name, final List<SnPost> posts = const []}): _posts = posts;
|
||||
const _SnPostTag({required this.id, required this.slug, this.name, final List<SnPost> posts = const [], this.usage = 0}): _posts = posts;
|
||||
factory _SnPostTag.fromJson(Map<String, dynamic> json) => _$SnPostTagFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@@ -219,6 +220,7 @@ class _SnPostTag implements SnPostTag {
|
||||
return EqualUnmodifiableListView(_posts);
|
||||
}
|
||||
|
||||
@override@JsonKey() final int usage;
|
||||
|
||||
/// Create a copy of SnPostTag
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -233,16 +235,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)&&(identical(other.usage, usage) || other.usage == usage));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts));
|
||||
int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts),usage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts)';
|
||||
return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +255,7 @@ abstract mixin class _$SnPostTagCopyWith<$Res> implements $SnPostTagCopyWith<$Re
|
||||
factory _$SnPostTagCopyWith(_SnPostTag value, $Res Function(_SnPostTag) _then) = __$SnPostTagCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String slug, String? name, List<SnPost> posts
|
||||
String id, String slug, String? name, List<SnPost> posts, int usage
|
||||
});
|
||||
|
||||
|
||||
@@ -270,13 +272,14 @@ class __$SnPostTagCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostTag
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) {
|
||||
return _then(_SnPostTag(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnPost>,
|
||||
as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@ _SnPostTag _$SnPostTagFromJson(Map<String, dynamic> json) => _SnPostTag(
|
||||
?.map((e) => SnPost.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
usage: (json['usage'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnPostTagToJson(_SnPostTag instance) =>
|
||||
@@ -23,4 +24,5 @@ Map<String, dynamic> _$SnPostTagToJson(_SnPostTag instance) =>
|
||||
'slug': instance.slug,
|
||||
'name': instance.name,
|
||||
'posts': instance.posts.map((e) => e.toJson()).toList(),
|
||||
'usage': instance.usage,
|
||||
};
|
||||
|
@@ -6,11 +6,13 @@ import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/screens/about.dart';
|
||||
import 'package:island/screens/account/credits.dart';
|
||||
import 'package:island/screens/developers/apps.dart';
|
||||
import 'package:island/screens/developers/edit_app.dart';
|
||||
import 'package:island/screens/developers/new_app.dart';
|
||||
import 'package:island/screens/developers/hub.dart';
|
||||
import 'package:island/screens/discovery/articles.dart';
|
||||
import 'package:island/screens/posts/post_categories_list.dart';
|
||||
import 'package:island/screens/posts/post_category_detail.dart';
|
||||
import 'package:island/screens/posts/post_search.dart';
|
||||
import 'package:island/widgets/app_wrapper.dart';
|
||||
@@ -52,6 +54,7 @@ import 'package:island/screens/account/event_calendar.dart';
|
||||
import 'package:island/screens/discovery/realms.dart';
|
||||
import 'package:island/screens/reports/report_detail.dart';
|
||||
import 'package:island/screens/reports/report_list.dart';
|
||||
import 'package:island/widgets/post/post_shuffle.dart';
|
||||
|
||||
// Shell route keys for nested navigation
|
||||
final rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||
@@ -376,12 +379,14 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
builder: (context, state) => const PostSearchScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postDetail',
|
||||
path: '/posts/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
return PostDetailScreen(id: id);
|
||||
},
|
||||
name: 'postShuffle',
|
||||
path: '/posts/shuffle',
|
||||
builder: (context, state) => const PostShuffleScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategories',
|
||||
path: '/posts/categories',
|
||||
builder: (context, state) => const PostCategoriesListScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategoryDetail',
|
||||
@@ -391,6 +396,11 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
return PostCategoryDetailScreen(slug: slug, isCategory: true);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postTags',
|
||||
path: '/posts/tags',
|
||||
builder: (context, state) => const PostTagsListScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postTagDetail',
|
||||
path: '/posts/tags/:slug',
|
||||
@@ -402,6 +412,14 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postDetail',
|
||||
path: '/posts/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
return PostDetailScreen(id: id);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'publisherProfile',
|
||||
path: '/publishers/:name',
|
||||
@@ -538,6 +556,11 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
path: '/account/wallet',
|
||||
builder: (context, state) => const WalletScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'socialCredits',
|
||||
path: '/account/credits',
|
||||
builder: (context, state) => const SocialCreditsScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'relationships',
|
||||
path: '/account/relationships',
|
||||
|
@@ -236,6 +236,16 @@ class AccountScreen extends HookConsumerWidget {
|
||||
context.pushNamed('stickerMarketplace');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
minTileHeight: 48,
|
||||
leading: const Icon(Symbols.star),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('credits').tr(),
|
||||
onTap: () {
|
||||
context.pushNamed('socialCredits');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
minTileHeight: 48,
|
||||
title: Text('abuseReport').tr(),
|
||||
@@ -389,6 +399,15 @@ class _UnauthorizedAccountScreen extends StatelessWidget {
|
||||
},
|
||||
child: Text('about').tr(),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('debugOptions').tr(),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => DebugSheet(),
|
||||
);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.pushNamed('settings');
|
||||
|
152
lib/screens/account/credits.dart
Normal file
152
lib/screens/account/credits.dart
Normal file
@@ -0,0 +1,152 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'credits.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<double> socialCredits(Ref ref) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final response = await client.get('/id/accounts/me/credits');
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to load social credits');
|
||||
}
|
||||
return response.data?.toDouble() ?? 0.0;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class SocialCreditHistoryNotifier extends _$SocialCreditHistoryNotifier
|
||||
with CursorPagingNotifierMixin<SnSocialCreditRecord> {
|
||||
static const int _pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnSocialCreditRecord>> build() => fetch(cursor: null);
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnSocialCreditRecord>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
||||
|
||||
final response = await client.get(
|
||||
'/id/accounts/me/credits/history',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final records =
|
||||
data.map((json) => SnSocialCreditRecord.fromJson(json)).toList();
|
||||
|
||||
final hasMore = offset + records.length < total;
|
||||
final nextCursor = hasMore ? (offset + records.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: records,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SocialCreditsScreen extends HookConsumerWidget {
|
||||
const SocialCreditsScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final socialCredits = ref.watch(socialCreditsProvider);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text('socialCredits').tr()),
|
||||
body: Column(
|
||||
children: [
|
||||
Card(
|
||||
margin: EdgeInsets.only(left: 16, right: 16, top: 8),
|
||||
child: socialCredits
|
||||
.when(
|
||||
data:
|
||||
(credits) => Stack(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
credits < 100
|
||||
? 'socialCreditsLevelPoor'.tr()
|
||||
: credits < 150
|
||||
? 'socialCreditsLevelNormal'.tr()
|
||||
: credits < 200
|
||||
? 'socialCreditsLevelGood'.tr()
|
||||
: 'socialCreditsLevelExcellent'.tr(),
|
||||
).tr().bold().fontSize(20),
|
||||
Text(
|
||||
'${credits.toStringAsFixed(2)} pts',
|
||||
).fontSize(14),
|
||||
const Gap(8),
|
||||
LinearProgressIndicator(value: credits / 200),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Symbols.info),
|
||||
tooltip: 'socialCreditsDescription'.tr(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
error: (_, _) => Text('Error loading credits'),
|
||||
loading: () => const LinearProgressIndicator(),
|
||||
)
|
||||
.padding(horizontal: 20, vertical: 16),
|
||||
),
|
||||
Expanded(
|
||||
child: PagingHelperView(
|
||||
provider: socialCreditHistoryNotifierProvider,
|
||||
futureRefreshable: socialCreditHistoryNotifierProvider.future,
|
||||
notifierRefreshable: socialCreditHistoryNotifierProvider.notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
final record = data.items[index];
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text(record.reason),
|
||||
subtitle: Text(
|
||||
DateFormat.yMMMd().format(record.createdAt),
|
||||
),
|
||||
trailing: Text(
|
||||
record.delta > 0
|
||||
? '+${record.delta}'
|
||||
: '${record.delta}',
|
||||
style: TextStyle(
|
||||
color: record.delta > 0 ? Colors.green : Colors.red,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
49
lib/screens/account/credits.g.dart
Normal file
49
lib/screens/account/credits.g.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'credits.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$socialCreditsHash() => r'2599844e892127ee4d315caced5c10e4dbaea142';
|
||||
|
||||
/// See also [socialCredits].
|
||||
@ProviderFor(socialCredits)
|
||||
final socialCreditsProvider = AutoDisposeFutureProvider<double>.internal(
|
||||
socialCredits,
|
||||
name: r'socialCreditsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$socialCreditsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef SocialCreditsRef = AutoDisposeFutureProviderRef<double>;
|
||||
String _$socialCreditHistoryNotifierHash() =>
|
||||
r'950db020754160f835c64cedf3fa2175e61e4d64';
|
||||
|
||||
/// 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: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/models/wallet.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
@@ -19,6 +20,7 @@ import 'package:island/widgets/payment/payment_overlay.dart';
|
||||
import 'package:easy_localization/easy_localization.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:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'leveling.g.dart';
|
||||
@@ -35,13 +37,49 @@ Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LevelingHistoryNotifier extends _$LevelingHistoryNotifier
|
||||
with CursorPagingNotifierMixin<SnExperienceRecord> {
|
||||
static const int _pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnExperienceRecord>> build() => fetch(cursor: null);
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnExperienceRecord>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
||||
|
||||
final response = await client.get(
|
||||
'/id/accounts/me/leveling',
|
||||
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;
|
||||
final nextCursor = hasMore ? (offset + records.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: records,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LevelingScreen extends HookConsumerWidget {
|
||||
const LevelingScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userInfoProvider);
|
||||
final stellarSubscription = ref.watch(accountStellarSubscriptionProvider);
|
||||
|
||||
if (user.value == null) {
|
||||
return AppScaffold(
|
||||
@@ -50,13 +88,140 @@ class LevelingScreen extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
final currentLevel = user.value!.profile.level;
|
||||
final currentExp = user.value!.profile.experience;
|
||||
final progress = user.value!.profile.levelingProgress;
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: AppScaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('levelingProgress'.tr()),
|
||||
bottom: TabBar(
|
||||
tabs: [
|
||||
Tab(text: 'leveling'.tr()),
|
||||
Tab(text: 'stellarProgram'.tr()),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
children: [
|
||||
_buildLevelingTab(context, ref, user.value!),
|
||||
_buildStellarProgramTab(context, ref),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text('levelingProgress'.tr())),
|
||||
body: SingleChildScrollView(
|
||||
Widget _buildLevelingTab(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
SnAccount user,
|
||||
) {
|
||||
final currentLevel = user.profile.level;
|
||||
final currentExp = user.profile.experience;
|
||||
final progress = user.profile.levelingProgress;
|
||||
|
||||
return Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
const SliverGap(20),
|
||||
|
||||
// Current Progress Card
|
||||
SliverToBoxAdapter(
|
||||
child: LevelingProgressCard(
|
||||
level: currentLevel,
|
||||
experience: currentExp,
|
||||
progress: progress,
|
||||
),
|
||||
),
|
||||
const SliverGap(24),
|
||||
|
||||
// Level Stairs Graph
|
||||
SliverToBoxAdapter(
|
||||
child: Text(
|
||||
'levelProgress'.tr(),
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverGap(16),
|
||||
|
||||
// Stairs visualization with fixed height and horizontal scroll
|
||||
SliverToBoxAdapter(child: _buildLevelStairs(context, currentLevel)),
|
||||
const SliverGap(24),
|
||||
|
||||
// Leveling History
|
||||
SliverToBoxAdapter(
|
||||
child: Text(
|
||||
'levelingHistory'.tr(),
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverGap(8),
|
||||
PagingHelperSliverView(
|
||||
provider: levelingHistoryNotifierProvider,
|
||||
futureRefreshable: levelingHistoryNotifierProvider.future,
|
||||
notifierRefreshable: levelingHistoryNotifierProvider.notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
final record = data.items[index];
|
||||
return ListTile(
|
||||
title: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(record.reason),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(
|
||||
record.createdAt.formatRelative(context),
|
||||
).fontSize(13),
|
||||
Text('·').fontSize(13).bold(),
|
||||
Text(
|
||||
record.createdAt.formatSystem(),
|
||||
).fontSize(13),
|
||||
],
|
||||
).opacity(0.8),
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
'${record.delta > 0 ? '+' : ''}${record.delta} EXP',
|
||||
),
|
||||
if (record.bonusMultiplier != 1.0)
|
||||
Text('x${record.bonusMultiplier}'),
|
||||
],
|
||||
),
|
||||
minTileHeight: 56,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
SliverGap(getTabbedPadding(context, vertical: 20).vertical),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStellarProgramTab(BuildContext context, WidgetRef ref) {
|
||||
final stellarSubscription = ref.watch(accountStellarSubscriptionProvider);
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: getTabbedPadding(context, horizontal: 20, vertical: 20),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
@@ -64,36 +229,12 @@ class LevelingScreen extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Current Progress Card
|
||||
LevelingProgressCard(
|
||||
level: currentLevel,
|
||||
experience: currentExp,
|
||||
progress: progress,
|
||||
),
|
||||
const Gap(24),
|
||||
|
||||
// Level Stairs Graph
|
||||
Text(
|
||||
'levelProgress'.tr(),
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const Gap(16),
|
||||
|
||||
// Stairs visualization with fixed height and horizontal scroll
|
||||
_buildLevelStairs(context, currentLevel),
|
||||
|
||||
const Gap(24),
|
||||
|
||||
// Membership section
|
||||
_buildMembershipSection(context, ref, stellarSubscription),
|
||||
const Gap(16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -27,5 +27,26 @@ final accountStellarSubscriptionProvider =
|
||||
// ignore: unused_element
|
||||
typedef AccountStellarSubscriptionRef =
|
||||
AutoDisposeFutureProviderRef<SnWalletSubscription?>;
|
||||
String _$levelingHistoryNotifierHash() =>
|
||||
r'e795f9b7911c9e50f15c095ea237cb0e87bf1e89';
|
||||
|
||||
/// 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
|
||||
|
@@ -79,18 +79,21 @@ class ChatRoomListTile extends HookConsumerWidget {
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
if (data.lastMessage == null)
|
||||
Text(room.description ?? 'descriptionNone'.tr(), maxLines: 1)
|
||||
else
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Badge(
|
||||
label: Text(data.lastMessage.sender.account.nick),
|
||||
label: Text(data.lastMessage!.sender.account.nick),
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
(data.lastMessage.content?.isNotEmpty ?? false)
|
||||
? data.lastMessage.content!
|
||||
(data.lastMessage!.content?.isNotEmpty ?? false)
|
||||
? data.lastMessage!.content!
|
||||
: 'messageNone'.tr(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -100,7 +103,9 @@ class ChatRoomListTile extends HookConsumerWidget {
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
RelativeTime(context).format(data.lastMessage.createdAt),
|
||||
RelativeTime(
|
||||
context,
|
||||
).format(data.lastMessage!.createdAt),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
|
@@ -7,7 +7,7 @@ part of 'room_detail.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$chatMemberListNotifierHash() =>
|
||||
r'c8fbf4b95df6dae24b1ba21063e9a43351832974';
|
||||
r'3ea30150278523e9f6b23f9200ea9a9fbae9c973';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@@ -106,11 +106,7 @@ class StickerPacksNotifier extends _$StickerPacksNotifier
|
||||
try {
|
||||
final response = await client.get(
|
||||
'/sphere/stickers',
|
||||
queryParameters: {
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
'pubName': pubName,
|
||||
},
|
||||
queryParameters: {'offset': offset, 'take': _pageSize, 'pub': pubName},
|
||||
);
|
||||
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
|
@@ -148,7 +148,7 @@ class _StickerPackProviderElement
|
||||
}
|
||||
|
||||
String _$stickerPacksNotifierHash() =>
|
||||
r'0a8edcf9c35396c411f1214f5e77b1e8fac6a3e6';
|
||||
r'30024b35235f3085a5b1ec2204d0a974ee907e22';
|
||||
|
||||
abstract class _$StickerPacksNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> {
|
||||
|
@@ -173,12 +173,60 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
),
|
||||
tooltip: 'webArticlesStand'.tr(),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
PopupMenuButton(
|
||||
itemBuilder:
|
||||
(context) => [
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.category),
|
||||
const Gap(12),
|
||||
Text('categories').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
context.pushNamed('postCategories');
|
||||
},
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.label),
|
||||
const Gap(12),
|
||||
Text('tags').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
context.pushNamed('postTags');
|
||||
},
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.shuffle),
|
||||
const Gap(12),
|
||||
Text('postShuffle').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
context.pushNamed('postShuffle');
|
||||
},
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.search),
|
||||
const Gap(12),
|
||||
Text('search').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
context.pushNamed('postSearch');
|
||||
},
|
||||
),
|
||||
],
|
||||
icon: Icon(
|
||||
Symbols.search,
|
||||
Symbols.action_key,
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
tooltip: 'search'.tr(),
|
||||
|
242
lib/screens/posts/post_categories_list.dart
Normal file
242
lib/screens/posts/post_categories_list.dart
Normal file
@@ -0,0 +1,242 @@
|
||||
import 'dart:async';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/post_tag.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
|
||||
// Post Categories Notifier
|
||||
final postCategoriesNotifierProvider = StateNotifierProvider.autoDispose<
|
||||
PostCategoriesNotifier,
|
||||
AsyncValue<CursorPagingData<SnPostCategory>>
|
||||
>((ref) {
|
||||
return PostCategoriesNotifier(ref);
|
||||
});
|
||||
|
||||
class PostCategoriesNotifier
|
||||
extends StateNotifier<AsyncValue<CursorPagingData<SnPostCategory>>> {
|
||||
final AutoDisposeRef ref;
|
||||
static const int _pageSize = 20;
|
||||
bool _isLoading = false;
|
||||
|
||||
PostCategoriesNotifier(this.ref) : super(const AsyncValue.loading()) {
|
||||
state = const AsyncValue.data(
|
||||
CursorPagingData(items: [], hasMore: false, nextCursor: null),
|
||||
);
|
||||
fetch(cursor: null);
|
||||
}
|
||||
|
||||
Future<void> fetch({String? cursor}) async {
|
||||
if (_isLoading) return;
|
||||
|
||||
_isLoading = true;
|
||||
if (cursor == null) {
|
||||
state = const AsyncValue.loading();
|
||||
}
|
||||
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/posts/categories',
|
||||
queryParameters: {
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
'order': 'usage',
|
||||
},
|
||||
);
|
||||
|
||||
final data = response.data as List;
|
||||
final categories =
|
||||
data.map((json) => SnPostCategory.fromJson(json)).toList();
|
||||
final hasMore = categories.length == _pageSize;
|
||||
final nextCursor =
|
||||
hasMore ? (offset + categories.length).toString() : null;
|
||||
|
||||
state = AsyncValue.data(
|
||||
CursorPagingData(
|
||||
items: [...(state.value?.items ?? []), ...categories],
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
),
|
||||
);
|
||||
} catch (e, stack) {
|
||||
state = AsyncValue.error(e, stack);
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Post Tags Notifier
|
||||
final postTagsNotifierProvider = StateNotifierProvider.autoDispose<
|
||||
PostTagsNotifier,
|
||||
AsyncValue<CursorPagingData<SnPostTag>>
|
||||
>((ref) {
|
||||
return PostTagsNotifier(ref);
|
||||
});
|
||||
|
||||
class PostTagsNotifier
|
||||
extends StateNotifier<AsyncValue<CursorPagingData<SnPostTag>>> {
|
||||
final AutoDisposeRef ref;
|
||||
static const int _pageSize = 20;
|
||||
bool _isLoading = false;
|
||||
|
||||
PostTagsNotifier(this.ref) : super(const AsyncValue.loading()) {
|
||||
state = const AsyncValue.data(
|
||||
CursorPagingData(items: [], hasMore: false, nextCursor: null),
|
||||
);
|
||||
fetch(cursor: null);
|
||||
}
|
||||
|
||||
Future<void> fetch({String? cursor}) async {
|
||||
if (_isLoading) return;
|
||||
|
||||
_isLoading = true;
|
||||
if (cursor == null) {
|
||||
state = const AsyncValue.loading();
|
||||
}
|
||||
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/posts/tags',
|
||||
queryParameters: {
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
'order': 'usage',
|
||||
},
|
||||
);
|
||||
|
||||
final data = response.data as List;
|
||||
final tags = data.map((json) => SnPostTag.fromJson(json)).toList();
|
||||
final hasMore = tags.length == _pageSize;
|
||||
final nextCursor = hasMore ? (offset + tags.length).toString() : null;
|
||||
|
||||
state = AsyncValue.data(
|
||||
CursorPagingData(
|
||||
items: [...(state.value?.items ?? []), ...tags],
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
),
|
||||
);
|
||||
} catch (e, stack) {
|
||||
state = AsyncValue.error(e, stack);
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PostCategoriesListScreen extends ConsumerWidget {
|
||||
const PostCategoriesListScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final categoriesState = ref.watch(postCategoriesNotifierProvider);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('categories').tr()),
|
||||
body: categoriesState.when(
|
||||
data: (data) {
|
||||
if (data.items.isEmpty) {
|
||||
return const Center(child: Text('No categories found'));
|
||||
}
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: data.items.length + (data.hasMore ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >= data.items.length) {
|
||||
ref
|
||||
.read(postCategoriesNotifierProvider.notifier)
|
||||
.fetch(cursor: data.nextCursor);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final category = data.items[index];
|
||||
return ListTile(
|
||||
leading: const Icon(Symbols.category),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
title: Text(category.categoryDisplayTitle),
|
||||
subtitle: Text('postCount'.plural(category.usage)),
|
||||
onTap: () {
|
||||
context.pushNamed(
|
||||
'postCategoryDetail',
|
||||
pathParameters: {'slug': category.slug},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error:
|
||||
(error, stack) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () => ref.invalidate(postCategoriesNotifierProvider),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PostTagsListScreen extends ConsumerWidget {
|
||||
const PostTagsListScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final tagsState = ref.watch(postTagsNotifierProvider);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('tags').tr()),
|
||||
body: tagsState.when(
|
||||
data: (data) {
|
||||
if (data.items.isEmpty) {
|
||||
return const Center(child: Text('No tags found'));
|
||||
}
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: data.items.length + (data.hasMore ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >= data.items.length) {
|
||||
ref
|
||||
.read(postTagsNotifierProvider.notifier)
|
||||
.fetch(cursor: data.nextCursor);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final tag = data.items[index];
|
||||
return ListTile(
|
||||
title: Text(tag.name ?? '#${tag.slug}'),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: const Icon(Symbols.label),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
subtitle: Text('postCount'.plural(tag.usage)),
|
||||
onTap: () {
|
||||
context.pushNamed(
|
||||
'postTagDetail',
|
||||
pathParameters: {'slug': tag.slug},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error:
|
||||
(error, stack) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () => ref.invalidate(postTagsNotifierProvider),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -8,6 +9,7 @@ import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:island/widgets/post/post_quick_reply.dart';
|
||||
import 'package:island/widgets/post/post_replies.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@@ -55,7 +57,10 @@ class PostDetailScreen extends HookConsumerWidget {
|
||||
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(title: const Text('Post')),
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
title: Text('postDetail').tr(),
|
||||
),
|
||||
body: postState.when(
|
||||
data: (post) {
|
||||
return Stack(
|
||||
@@ -117,8 +122,12 @@ class PostDetailScreen extends HookConsumerWidget {
|
||||
],
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (e, _) => Text('Error: $e'),
|
||||
loading: () => ResponseLoadingWidget(),
|
||||
error:
|
||||
(e, _) => ResponseErrorWidget(
|
||||
error: e,
|
||||
onRetry: () => ref.invalidate(postStateProvider(id)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -399,7 +399,7 @@ class _RealmChatRoomsProviderElement
|
||||
}
|
||||
|
||||
String _$realmMemberListNotifierHash() =>
|
||||
r'022bcef5a90cbae05ff23b937851afc3ef913d42';
|
||||
r'2f88f803b2e61e7287ed8a43025173e56ff6ca3b';
|
||||
|
||||
abstract class _$RealmMemberListNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnRealmMember>> {
|
||||
|
@@ -106,7 +106,7 @@ class RealmListScreen extends HookConsumerWidget {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 540),
|
||||
child: RealmListTile(realm: value[item]),
|
||||
).center();
|
||||
).padding(horizontal: 8).center();
|
||||
},
|
||||
separatorBuilder: (_, _) => const Gap(8),
|
||||
),
|
||||
|
@@ -235,7 +235,11 @@ class PageBackButton extends StatelessWidget {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
onWillPop?.call();
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/');
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
color: color,
|
||||
|
@@ -50,6 +50,6 @@ class AppWrapper extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
return TourTriggerWidget(child: child);
|
||||
return TourTriggerWidget(key: UniqueKey(), child: child);
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:dismissible_page/dismissible_page.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_blurhash/flutter_blurhash.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
@@ -326,7 +328,11 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
||||
|
||||
// Create a temporary file to save the image
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final filePath = '${tempDir.path}/${item.id}.${extension(item.name)}';
|
||||
var extName = extension(item.name).trim();
|
||||
if (extName.isEmpty) {
|
||||
extName = item.mimeType?.split('/').lastOrNull ?? 'jpeg';
|
||||
}
|
||||
final filePath = '${tempDir.path}/${item.id}.$extName';
|
||||
|
||||
await client.download(
|
||||
'/drive/files/${item.id}',
|
||||
@@ -342,39 +348,6 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildInfoRow(IconData icon, String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Flexible(
|
||||
child: Text(
|
||||
value,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500),
|
||||
textAlign: TextAlign.end,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String formatFileSize(int bytes) {
|
||||
if (bytes <= 0) return '0 B';
|
||||
if (bytes < 1024) return '$bytes B';
|
||||
@@ -400,57 +373,247 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
buildInfoRow(Icons.description, 'Name', item.name),
|
||||
const Divider(height: 1),
|
||||
buildInfoRow(
|
||||
Icons.storage,
|
||||
'Size',
|
||||
formatFileSize(item.size),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
buildInfoRow(
|
||||
Icons.category,
|
||||
'Type',
|
||||
item.mimeType?.toUpperCase() ?? 'UNKNOWN',
|
||||
),
|
||||
if (exifData.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('mimeType').tr(),
|
||||
Text(
|
||||
'EXIF Data',
|
||||
item.mimeType ?? 'unknown'.tr(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
).padding(horizontal: 24),
|
||||
const SizedBox(height: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 28, child: const VerticalDivider()),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('fileSize').tr(),
|
||||
Text(
|
||||
formatFileSize(item.size),
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (item.hash != null)
|
||||
SizedBox(height: 28, child: const VerticalDivider()),
|
||||
if (item.hash != null)
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('fileHash').tr(),
|
||||
Text(
|
||||
'${item.hash!.substring(0, 6)}...',
|
||||
style: theme.textTheme.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
onLongPress: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: item.hash!),
|
||||
);
|
||||
showSnackBar('File hash copied to clipboard');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24, vertical: 16),
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.file_present),
|
||||
title: Text('Name').tr(),
|
||||
subtitle: Text(
|
||||
item.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.copy),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: item.name));
|
||||
showSnackBar('File name copied to clipboard');
|
||||
},
|
||||
),
|
||||
),
|
||||
if (exifData.isNotEmpty) ...[
|
||||
const Divider(height: 1),
|
||||
Theme(
|
||||
data: theme.copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
tilePadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title: Text(
|
||||
'exifData'.tr(),
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...exifData.entries.map(
|
||||
(entry) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(entry) => ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title:
|
||||
Text(
|
||||
'• ${entry.key.contains('-') ? entry.key.split('-').last : entry.key}: ',
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
entry.key.contains('-')
|
||||
? entry.key.split('-').last
|
||||
: entry.key,
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
).bold(),
|
||||
subtitle: Text(
|
||||
'${entry.value}'.isNotEmpty
|
||||
? '${entry.value}'
|
||||
: 'N/A',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: '${entry.value}'),
|
||||
);
|
||||
showSnackBar('Value copied to clipboard');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (item.fileMeta != null && item.fileMeta!.isNotEmpty) ...[
|
||||
const Divider(height: 1),
|
||||
Theme(
|
||||
data: theme.copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
tilePadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title: Text(
|
||||
'File Metadata',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...item.fileMeta!.entries.map(
|
||||
(entry) => ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title:
|
||||
Text(
|
||||
entry.key,
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
).bold(),
|
||||
subtitle: Text(
|
||||
jsonEncode(entry.value),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: jsonEncode(entry.value),
|
||||
),
|
||||
);
|
||||
showSnackBar('Value copied to clipboard');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (item.userMeta != null && item.userMeta!.isNotEmpty) ...[
|
||||
const Divider(height: 1),
|
||||
Theme(
|
||||
data: theme.copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
tilePadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title: Text(
|
||||
'User Metadata',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...item.userMeta!.entries.map(
|
||||
(entry) => ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
title:
|
||||
Text(
|
||||
entry.key,
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
).bold(),
|
||||
subtitle: Text(
|
||||
jsonEncode(entry.value),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: jsonEncode(entry.value),
|
||||
),
|
||||
);
|
||||
showSnackBar('Value copied to clipboard');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
@@ -8,6 +8,52 @@ import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/widgets/content/network_status_sheet.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
|
||||
Future<void> _showSetTokenDialog(BuildContext context, WidgetRef ref) async {
|
||||
final TextEditingController controller = TextEditingController();
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Set Access Token'),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter access token',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
autofocus: true,
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('Cancel'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Set'),
|
||||
onPressed: () async {
|
||||
final token = controller.text.trim();
|
||||
if (token.isNotEmpty) {
|
||||
await setToken(prefs, token);
|
||||
ref.invalidate(tokenProvider);
|
||||
// Store context in local variable to avoid async gap issue
|
||||
final navigatorContext = context;
|
||||
if (navigatorContext.mounted) {
|
||||
Navigator.of(navigatorContext).pop();
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class DebugSheet extends HookConsumerWidget {
|
||||
const DebugSheet({super.key});
|
||||
@@ -49,6 +95,17 @@ class DebugSheet extends HookConsumerWidget {
|
||||
Clipboard.setData(ClipboardData(text: tk!.token));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
minTileHeight: 48,
|
||||
leading: const Icon(Symbols.edit),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
title: Text('Set access token'),
|
||||
onTap: () async {
|
||||
await _showSetTokenDialog(context, ref);
|
||||
},
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
minTileHeight: 48,
|
||||
leading: const Icon(Symbols.delete),
|
||||
|
@@ -94,7 +94,7 @@ class PostItemCreator extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () {
|
||||
if (isOpenable) {
|
||||
context.pushNamed('postDetail', pathParameters: {'id': item.id});
|
||||
context.goNamed('postDetail', pathParameters: {'id': item.id});
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
|
@@ -21,6 +21,7 @@ class PostListNotifier extends _$PostListNotifier
|
||||
int? type,
|
||||
List<String>? categories,
|
||||
List<String>? tags,
|
||||
bool shuffle = false,
|
||||
}) {
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
@@ -38,6 +39,7 @@ class PostListNotifier extends _$PostListNotifier
|
||||
if (type != null) 'type': type,
|
||||
if (tags != null) 'tags': tags,
|
||||
if (categories != null) 'categories': categories,
|
||||
if (shuffle) 'shuffle': true,
|
||||
};
|
||||
|
||||
final response = await client.get(
|
||||
@@ -74,6 +76,7 @@ class SliverPostList extends HookConsumerWidget {
|
||||
final int? type;
|
||||
final List<String>? categories;
|
||||
final List<String>? tags;
|
||||
final bool shuffle;
|
||||
final PostItemType itemType;
|
||||
final Color? backgroundColor;
|
||||
final EdgeInsets? padding;
|
||||
@@ -88,6 +91,7 @@ class SliverPostList extends HookConsumerWidget {
|
||||
this.type,
|
||||
this.categories,
|
||||
this.tags,
|
||||
this.shuffle = false,
|
||||
this.itemType = PostItemType.regular,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
@@ -105,6 +109,7 @@ class SliverPostList extends HookConsumerWidget {
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
),
|
||||
futureRefreshable:
|
||||
postListNotifierProvider(
|
||||
@@ -113,6 +118,7 @@ class SliverPostList extends HookConsumerWidget {
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
).future,
|
||||
notifierRefreshable:
|
||||
postListNotifierProvider(
|
||||
@@ -121,6 +127,7 @@ class SliverPostList extends HookConsumerWidget {
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.builder(
|
||||
|
@@ -6,7 +6,7 @@ part of 'post_list.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$postListNotifierHash() => r'9784b282b3ee14b7109e263c5841a082cf0be78e';
|
||||
String _$postListNotifierHash() => r'faa0b939fae56367ff120ce63d9deb17b1995c9c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
@@ -36,6 +36,7 @@ abstract class _$PostListNotifier
|
||||
late final int? type;
|
||||
late final List<String>? categories;
|
||||
late final List<String>? tags;
|
||||
late final bool shuffle;
|
||||
|
||||
FutureOr<CursorPagingData<SnPost>> build({
|
||||
String? pubName,
|
||||
@@ -43,6 +44,7 @@ abstract class _$PostListNotifier
|
||||
int? type,
|
||||
List<String>? categories,
|
||||
List<String>? tags,
|
||||
bool shuffle = false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,6 +65,7 @@ class PostListNotifierFamily
|
||||
int? type,
|
||||
List<String>? categories,
|
||||
List<String>? tags,
|
||||
bool shuffle = false,
|
||||
}) {
|
||||
return PostListNotifierProvider(
|
||||
pubName: pubName,
|
||||
@@ -70,6 +73,7 @@ class PostListNotifierFamily
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,6 +87,7 @@ class PostListNotifierFamily
|
||||
type: provider.type,
|
||||
categories: provider.categories,
|
||||
tags: provider.tags,
|
||||
shuffle: provider.shuffle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,6 +120,7 @@ class PostListNotifierProvider
|
||||
int? type,
|
||||
List<String>? categories,
|
||||
List<String>? tags,
|
||||
bool shuffle = false,
|
||||
}) : this._internal(
|
||||
() =>
|
||||
PostListNotifier()
|
||||
@@ -122,7 +128,8 @@ class PostListNotifierProvider
|
||||
..realm = realm
|
||||
..type = type
|
||||
..categories = categories
|
||||
..tags = tags,
|
||||
..tags = tags
|
||||
..shuffle = shuffle,
|
||||
from: postListNotifierProvider,
|
||||
name: r'postListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
@@ -137,6 +144,7 @@ class PostListNotifierProvider
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
);
|
||||
|
||||
PostListNotifierProvider._internal(
|
||||
@@ -151,6 +159,7 @@ class PostListNotifierProvider
|
||||
required this.type,
|
||||
required this.categories,
|
||||
required this.tags,
|
||||
required this.shuffle,
|
||||
}) : super.internal();
|
||||
|
||||
final String? pubName;
|
||||
@@ -158,6 +167,7 @@ class PostListNotifierProvider
|
||||
final int? type;
|
||||
final List<String>? categories;
|
||||
final List<String>? tags;
|
||||
final bool shuffle;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnPost>> runNotifierBuild(
|
||||
@@ -169,6 +179,7 @@ class PostListNotifierProvider
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -183,7 +194,8 @@ class PostListNotifierProvider
|
||||
..realm = realm
|
||||
..type = type
|
||||
..categories = categories
|
||||
..tags = tags,
|
||||
..tags = tags
|
||||
..shuffle = shuffle,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
@@ -194,6 +206,7 @@ class PostListNotifierProvider
|
||||
type: type,
|
||||
categories: categories,
|
||||
tags: tags,
|
||||
shuffle: shuffle,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -214,7 +227,8 @@ class PostListNotifierProvider
|
||||
other.realm == realm &&
|
||||
other.type == type &&
|
||||
other.categories == categories &&
|
||||
other.tags == tags;
|
||||
other.tags == tags &&
|
||||
other.shuffle == shuffle;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -225,6 +239,7 @@ class PostListNotifierProvider
|
||||
hash = _SystemHash.combine(hash, type.hashCode);
|
||||
hash = _SystemHash.combine(hash, categories.hashCode);
|
||||
hash = _SystemHash.combine(hash, tags.hashCode);
|
||||
hash = _SystemHash.combine(hash, shuffle.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
@@ -248,6 +263,9 @@ mixin PostListNotifierRef
|
||||
|
||||
/// The parameter `tags` of this provider.
|
||||
List<String>? get tags;
|
||||
|
||||
/// The parameter `shuffle` of this provider.
|
||||
bool get shuffle;
|
||||
}
|
||||
|
||||
class _PostListNotifierProviderElement
|
||||
@@ -270,6 +288,8 @@ class _PostListNotifierProviderElement
|
||||
(origin as PostListNotifierProvider).categories;
|
||||
@override
|
||||
List<String>? get tags => (origin as PostListNotifierProvider).tags;
|
||||
@override
|
||||
bool get shuffle => (origin as PostListNotifierProvider).shuffle;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
108
lib/widgets/post/post_shuffle.dart
Normal file
108
lib/widgets/post/post_shuffle.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_card_swiper/flutter_card_swiper.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:island/widgets/post/post_list.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class PostShuffleScreen extends HookConsumerWidget {
|
||||
const PostShuffleScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final postListState = ref.watch(postListNotifierProvider(shuffle: true));
|
||||
final postListNotifier = ref.watch(
|
||||
postListNotifierProvider(shuffle: true).notifier,
|
||||
);
|
||||
|
||||
final cardSwiperController = useMemoized(() => CardSwiperController(), []);
|
||||
|
||||
useEffect(() {
|
||||
return cardSwiperController.dispose;
|
||||
}, []);
|
||||
|
||||
const kBottomControlHeight = 96.0;
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('postShuffle').tr()),
|
||||
body: Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom:
|
||||
kBottomControlHeight + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
child:
|
||||
(postListState.value?.items.length ?? 0) > 0
|
||||
? CardSwiper(
|
||||
controller: cardSwiperController,
|
||||
cardsCount: postListState.value!.items.length,
|
||||
cardBuilder: (
|
||||
context,
|
||||
index,
|
||||
horizontalOffsetPercentage,
|
||||
verticalOffsetPercentage,
|
||||
) {
|
||||
return Center(
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
child: PostActionableItem(
|
||||
item: postListState.value!.items[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
onEnd: () {
|
||||
if (postListState.value?.hasMore ?? true) {
|
||||
postListNotifier.fetch(
|
||||
cursor: postListState.value?.nextCursor,
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
height: kBottomControlHeight,
|
||||
child:
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
cardSwiperController.undo();
|
||||
},
|
||||
icon: const Icon(Symbols.arrow_left_alt),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
cardSwiperController.swipe(CardSwiperDirection.right);
|
||||
},
|
||||
icon: const Icon(Symbols.arrow_right_alt),
|
||||
),
|
||||
],
|
||||
).padding(all: 8).center(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
52
pubspec.lock
52
pubspec.lock
@@ -565,10 +565,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: ef7d2a085c1b1d69d17b6842d0734aad90156de08df6bd3c12496d0bd6ddf8e2
|
||||
sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.3.1"
|
||||
version: "10.3.2"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -734,6 +734,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
flutter_card_swiper:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_card_swiper
|
||||
sha256: "1eacbfab31b572223042e03409726553aec431abe48af48c8d591d376d070d3d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.2"
|
||||
flutter_colorpicker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -754,10 +762,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_hooks
|
||||
sha256: c3df76c62bb3a9f9bee75c57cdab40abab6123b734c1cd7e9b26a5dbd436eceb
|
||||
sha256: "8ae1f090e5f4ef5cfa6670ce1ab5dddadd33f3533a7f9ba19d9f958aa2a89f42"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.21.3"
|
||||
version: "0.21.3+1"
|
||||
flutter_inappwebview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1137,10 +1145,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: "8b1f37dfaf6e958c6b872322db06f946509433bec3de753c3491a42ae9ec2b48"
|
||||
sha256: ced3fdc143c1437234ac3b8e985f3286cf138968bb83ca9a6f94d22f2951c6b9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "16.1.0"
|
||||
version: "16.2.0"
|
||||
google_fonts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1497,10 +1505,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: material_symbols_icons
|
||||
sha256: ef20d86fb34c2b59eb7553c4d795bb8a7ec8c890c53ffd3148c64f7adc46ae50
|
||||
sha256: b1342194e859b2774f920b484c46f54a37a845488e23d570385fbe3ede92ee9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2858.1"
|
||||
version: "4.2867.0"
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1841,10 +1849,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.1.5+1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1897,42 +1905,42 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: record
|
||||
sha256: "3d08502b77edf2a864aa6e4cd7874b983d42a80f3689431da053cc5e85c1ad21"
|
||||
sha256: "9dbc6ff3e784612f90a9b001373c45ff76b7a08abd2bd9fdf72c242320c8911c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.1.1"
|
||||
record_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_android
|
||||
sha256: "8b170e33d9866f9b51e01a767d7e1ecb97b9ecd629950bd87a47c79359ec57f8"
|
||||
sha256: "8361a791c9a3fa5c065f0b8b5adb10f12531f8538c86b19474cf7b56ea80d426"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.4.1"
|
||||
record_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_ios
|
||||
sha256: ad97d0a75933c44bcf5aff648e86e32fc05eb61f8fbef190f14968c8eaf86692
|
||||
sha256: "895c9467faec72d8e718a3142b51114958f42f18053836a8b484a74f9372f51a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
record_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_linux
|
||||
sha256: "785e8e8d6db109aa606d0669d95aaae416458aaa39782bb0abe0bee74eee17d7"
|
||||
sha256: "235b1f1fb84e810f8149cc0c2c731d7d697f8d1c333b32cb820c449bf7bb72d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
record_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_macos
|
||||
sha256: f1399bca76a1634da109e5b0cba764ed8332a2b4da49c704c66d2c553405ed81
|
||||
sha256: "2849068bb59072f300ad63ed146e543d66afaef8263edba4de4834fc7c8d4d35"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
record_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1953,10 +1961,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_windows
|
||||
sha256: "85a22fc97f6d73ecd67c8ba5f2f472b74ef1d906f795b7970f771a0914167e99"
|
||||
sha256: "223258060a1d25c62bae18282c16783f28581ec19401d17e56b5205b9f039d78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
version: "1.0.7"
|
||||
relative_time:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
11
pubspec.yaml
11
pubspec.yaml
@@ -36,10 +36,10 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_hooks: ^0.21.3
|
||||
flutter_hooks: ^0.21.3+1
|
||||
hooks_riverpod: ^2.6.1
|
||||
bitsdojo_window: ^0.1.6
|
||||
go_router: ^16.1.0
|
||||
go_router: ^16.2.0
|
||||
styled_widget: ^0.4.1
|
||||
shared_preferences: ^2.5.3
|
||||
flutter_riverpod: ^2.6.1
|
||||
@@ -73,7 +73,7 @@ dependencies:
|
||||
git: https://github.com/LittleSheep2Code/tus_client.git
|
||||
cross_file: ^0.3.4+2
|
||||
image_picker: ^1.2.0
|
||||
file_picker: ^10.3.1
|
||||
file_picker: ^10.3.2
|
||||
riverpod_annotation: ^2.6.1
|
||||
image_picker_platform_interface: ^2.11.0
|
||||
image_picker_android: ^0.8.13
|
||||
@@ -83,7 +83,7 @@ dependencies:
|
||||
flutter_udid: ^4.0.0
|
||||
firebase_core: ^4.0.0
|
||||
web_socket_channel: ^3.0.3
|
||||
material_symbols_icons: ^4.2858.1
|
||||
material_symbols_icons: ^4.2867.0
|
||||
drift: ^2.28.1
|
||||
drift_flutter: ^0.2.5
|
||||
path: ^1.9.1
|
||||
@@ -107,7 +107,7 @@ dependencies:
|
||||
livekit_client: ^2.5.0+hotfix.1
|
||||
pasteboard: ^0.4.0
|
||||
flutter_colorpicker: ^1.1.0
|
||||
record: ^6.1.0
|
||||
record: ^6.1.1
|
||||
qr_flutter: ^4.1.0
|
||||
flutter_otp_text_field: ^1.5.1+1
|
||||
palette_generator: ^0.3.3+7
|
||||
@@ -138,6 +138,7 @@ dependencies:
|
||||
firebase_analytics: ^12.0.0
|
||||
material_color_utilities: ^0.11.1
|
||||
screenshot: ^3.0.0
|
||||
flutter_card_swiper: ^7.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Reference in New Issue
Block a user