Compare commits
	
		
			16 Commits
		
	
	
		
			3.2.0+128
			...
			596d212593
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 596d212593 | |||
| 54f290327e | |||
| 16f248ceab | |||
| 856d811187 | |||
| d07b194c04 | |||
| 2554b58be6 | |||
| a627b5838e | |||
| c479a9f381 | |||
| 02057e663b | |||
| 6501594100 | |||
| c6599edc3d | |||
| 709a0620b6 | |||
| f9b2a96c7c | |||
| 4dca6189cb | |||
| c7f5b63fe5 | |||
| 96c2f45c85 | 
| @@ -386,6 +386,7 @@ | |||||||
|   "postSettings": "Settings", |   "postSettings": "Settings", | ||||||
|   "postPublisherUnselected": "Publisher Unspecified", |   "postPublisherUnselected": "Publisher Unspecified", | ||||||
|   "postType": "Post Type", |   "postType": "Post Type", | ||||||
|  |   "postTypePost": "Post", | ||||||
|   "articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.", |   "articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.", | ||||||
|   "postVisibility": "Post Visibility", |   "postVisibility": "Post Visibility", | ||||||
|   "postVisibilityPublic": "Public", |   "postVisibilityPublic": "Public", | ||||||
| @@ -867,7 +868,7 @@ | |||||||
|   "failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.", |   "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.", |   "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", |   "postDetail": "Post Detail", | ||||||
|   "postCount": { |   "postCount": { | ||||||
|     "zero": "No posts", |     "zero": "No posts", | ||||||
|     "one": "{} post", |     "one": "{} post", | ||||||
| @@ -883,6 +884,7 @@ | |||||||
|   "stellarProgram": "Stellar Program", |   "stellarProgram": "Stellar Program", | ||||||
|   "socialCredits": "Social Credits", |   "socialCredits": "Social Credits", | ||||||
|   "credits": "Credits", |   "credits": "Credits", | ||||||
|  |   "creditsStatus": "Credits Status", | ||||||
|   "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.", |   "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", |   "socialCreditsLevelPoor": "Poor", | ||||||
|   "socialCreditsLevelNormal": "Normal", |   "socialCreditsLevelNormal": "Normal", | ||||||
| @@ -926,5 +928,21 @@ | |||||||
|   "newSecretGenerated": "New Secret Generated", |   "newSecretGenerated": "New Secret Generated", | ||||||
|   "copySecretHint": "Please copy this secret and store it somewhere safe. You will not be able to see it again.", |   "copySecretHint": "Please copy this secret and store it somewhere safe. You will not be able to see it again.", | ||||||
|   "expiresIn": "Expires In (seconds)", |   "expiresIn": "Expires In (seconds)", | ||||||
|   "isOidc": "OIDC Compliant" |   "isOidc": "OIDC Compliant", | ||||||
|  |   "pinPost": "Pin Post", | ||||||
|  |   "unpinPost": "Unpin Post", | ||||||
|  |   "pinnedPost": "Pinned", | ||||||
|  |   "publisherPage": "Publisher Page", | ||||||
|  |   "realmPage": "Realm Page", | ||||||
|  |   "replyPage": "Reply Page", | ||||||
|  |   "pinPostPublisherHint": "Pin this post to your publisher page", | ||||||
|  |   "pinPostRealmHint": "Pin this post to the realm page", | ||||||
|  |   "pinPostRealmDisabledHint": "This post doesn't belong to any realm", | ||||||
|  |   "pinPostReplyHint": "Pin this post to the reply page", | ||||||
|  |   "pinPostReplyDisabledHint": "This post is not a reply", | ||||||
|  |   "pin": "Pin", | ||||||
|  |   "unpinPostHint": "Are you sure you want to unpin this post?", | ||||||
|  |   "all": "All", | ||||||
|  |   "statusPresent": "Present", | ||||||
|  |   "accountAutomated": "Automated" | ||||||
| } | } | ||||||
| @@ -829,7 +829,7 @@ | |||||||
|   "failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试", |   "failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试", | ||||||
|   "failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。", |   "failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。", | ||||||
|   "okay": "了解", |   "okay": "了解", | ||||||
|   "postDetails": "帖子详情", |   "postDetail": "帖子详情", | ||||||
|   "mimeType": "类型", |   "mimeType": "类型", | ||||||
|   "fileSize": "大小", |   "fileSize": "大小", | ||||||
|   "fileHash": "哈希", |   "fileHash": "哈希", | ||||||
| @@ -855,5 +855,7 @@ | |||||||
|   "newSecretGenerated": "已生成新密钥", |   "newSecretGenerated": "已生成新密钥", | ||||||
|   "copySecretHint": "请复制此密钥并将其存放在安全的地方。您将无法再次看到它。", |   "copySecretHint": "请复制此密钥并将其存放在安全的地方。您将无法再次看到它。", | ||||||
|   "expiresIn": "过期时间(秒)", |   "expiresIn": "过期时间(秒)", | ||||||
|   "isOidc": "OIDC 兼容" |   "isOidc": "OIDC 兼容", | ||||||
|  |   "statusPresent": "至今", | ||||||
|  |   "accountAutomated": "机器人" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -169,12 +169,12 @@ class IslandApp extends HookConsumerWidget { | |||||||
|     final theme = ref.watch(themeProvider); |     final theme = ref.watch(themeProvider); | ||||||
|  |  | ||||||
|     void handleMessage(RemoteMessage notification) { |     void handleMessage(RemoteMessage notification) { | ||||||
|       if (notification.data['action_uri'] != null) { |       if (notification.data['meta']?['action_uri'] != null) { | ||||||
|         var uri = notification.data['action_uri'] as String; |         var uri = notification.data['meta']['action_uri'] as String; | ||||||
|         if (uri.startsWith('/')) { |         if (uri.startsWith('/')) { | ||||||
|           // In-app routes |           // In-app routes | ||||||
|           final router = ref.read(routerProvider); |           final router = ref.read(routerProvider); | ||||||
|           router.go(notification.data['action_uri']); |           router.push(notification.data['meta']['action_uri']); | ||||||
|         } else { |         } else { | ||||||
|           // External links |           // External links | ||||||
|           launchUrlString(uri); |           launchUrlString(uri); | ||||||
| @@ -186,27 +186,6 @@ class IslandApp extends HookConsumerWidget { | |||||||
|       if (!kIsWeb && Platform.isLinux) { |       if (!kIsWeb && Platform.isLinux) { | ||||||
|         return null; |         return null; | ||||||
|       } |       } | ||||||
|       const channel = MethodChannel('dev.solsynth.solian/notifications'); |  | ||||||
|  |  | ||||||
|       Future<void> handleInitialLink() async { |  | ||||||
|         final String? link = await channel.invokeMethod('initialLink'); |  | ||||||
|         if (link != null) { |  | ||||||
|           final router = ref.read(routerProvider); |  | ||||||
|           router.go(link); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (!kIsWeb && Platform.isAndroid) { |  | ||||||
|         handleInitialLink(); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       channel.setMethodCallHandler((call) async { |  | ||||||
|         if (call.method == 'newLink') { |  | ||||||
|           final String link = call.arguments; |  | ||||||
|           final router = ref.read(routerProvider); |  | ||||||
|           router.go(link); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|       // When the app is opened from a terminated state. |       // When the app is opened from a terminated state. | ||||||
|       FirebaseMessaging.instance.getInitialMessage().then((message) { |       FirebaseMessaging.instance.getInitialMessage().then((message) { | ||||||
|   | |||||||
| @@ -71,6 +71,8 @@ sealed class SnAccountProfile with _$SnAccountProfile { | |||||||
|     SnAccountBadge? activeBadge, |     SnAccountBadge? activeBadge, | ||||||
|     required int experience, |     required int experience, | ||||||
|     required int level, |     required int level, | ||||||
|  |     @Default(100) double socialCredits, | ||||||
|  |     @Default(0) int socialCreditsLevel, | ||||||
|     required double levelingProgress, |     required double levelingProgress, | ||||||
|     required SnCloudFile? picture, |     required SnCloudFile? picture, | ||||||
|     required SnCloudFile? background, |     required SnCloudFile? background, | ||||||
|   | |||||||
| @@ -613,7 +613,7 @@ as String, | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAccountProfile { | mixin _$SnAccountProfile { | ||||||
|  |  | ||||||
|  String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get socialCredits; int get socialCreditsLevel; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @@ -626,16 +626,16 @@ $SnAccountProfileCopyWith<SnAccountProfile> get copyWith => _$SnAccountProfileCo | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -646,7 +646,7 @@ abstract mixin class $SnAccountProfileCopyWith<$Res>  { | |||||||
|   factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl; |   factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -663,7 +663,7 @@ class _$SnAccountProfileCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -680,6 +680,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last | |||||||
| as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | ||||||
| as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable | ||||||
| as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | ||||||
| as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -817,10 +819,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile() when $default != null: | case _SnAccountProfile() when $default != null: | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -838,10 +840,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile(): | case _SnAccountProfile(): | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);} | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -855,10 +857,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile() when $default != null: | case _SnAccountProfile() when $default != null: | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -870,7 +872,7 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnAccountProfile implements SnAccountProfile { | class _SnAccountProfile implements SnAccountProfile { | ||||||
|   const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final  List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links; |   const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final  List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, this.socialCredits = 100, this.socialCreditsLevel = 0, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links; | ||||||
|   factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json); |   factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -894,6 +896,8 @@ class _SnAccountProfile implements SnAccountProfile { | |||||||
| @override final  SnAccountBadge? activeBadge; | @override final  SnAccountBadge? activeBadge; | ||||||
| @override final  int experience; | @override final  int experience; | ||||||
| @override final  int level; | @override final  int level; | ||||||
|  | @override@JsonKey() final  double socialCredits; | ||||||
|  | @override@JsonKey() final  int socialCreditsLevel; | ||||||
| @override final  double levelingProgress; | @override final  double levelingProgress; | ||||||
| @override final  SnCloudFile? picture; | @override final  SnCloudFile? picture; | ||||||
| @override final  SnCloudFile? background; | @override final  SnCloudFile? background; | ||||||
| @@ -915,16 +919,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -935,7 +939,7 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> implements $SnAccountProfi | |||||||
|   factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl; |   factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -952,7 +956,7 @@ class __$SnAccountProfileCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_SnAccountProfile( |   return _then(_SnAccountProfile( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -969,6 +973,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last | |||||||
| as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | ||||||
| as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable | ||||||
| as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | ||||||
| as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||||
|   | |||||||
| @@ -86,6 +86,8 @@ _SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) => | |||||||
|               ), |               ), | ||||||
|       experience: (json['experience'] as num).toInt(), |       experience: (json['experience'] as num).toInt(), | ||||||
|       level: (json['level'] as num).toInt(), |       level: (json['level'] as num).toInt(), | ||||||
|  |       socialCredits: (json['social_credits'] as num?)?.toDouble() ?? 100, | ||||||
|  |       socialCreditsLevel: (json['social_credits_level'] as num?)?.toInt() ?? 0, | ||||||
|       levelingProgress: (json['leveling_progress'] as num).toDouble(), |       levelingProgress: (json['leveling_progress'] as num).toDouble(), | ||||||
|       picture: |       picture: | ||||||
|           json['picture'] == null |           json['picture'] == null | ||||||
| @@ -128,6 +130,8 @@ Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) => | |||||||
|       'active_badge': instance.activeBadge?.toJson(), |       'active_badge': instance.activeBadge?.toJson(), | ||||||
|       'experience': instance.experience, |       'experience': instance.experience, | ||||||
|       'level': instance.level, |       'level': instance.level, | ||||||
|  |       'social_credits': instance.socialCredits, | ||||||
|  |       'social_credits_level': instance.socialCreditsLevel, | ||||||
|       'leveling_progress': instance.levelingProgress, |       'leveling_progress': instance.levelingProgress, | ||||||
|       'picture': instance.picture?.toJson(), |       'picture': instance.picture?.toJson(), | ||||||
|       'background': instance.background?.toJson(), |       'background': instance.background?.toJson(), | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ sealed class SnEventCalendarEntry with _$SnEventCalendarEntry { | |||||||
|   const factory SnEventCalendarEntry({ |   const factory SnEventCalendarEntry({ | ||||||
|     required DateTime date, |     required DateTime date, | ||||||
|     required SnCheckInResult? checkInResult, |     required SnCheckInResult? checkInResult, | ||||||
|     required List<dynamic> statuses, |     required List<SnAccountStatus> statuses, | ||||||
|   }) = _SnEventCalendarEntry; |   }) = _SnEventCalendarEntry; | ||||||
|  |  | ||||||
|   factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => |   factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -861,7 +861,7 @@ as String, | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnEventCalendarEntry { | mixin _$SnEventCalendarEntry { | ||||||
|  |  | ||||||
|  DateTime get date; SnCheckInResult? get checkInResult; List<dynamic> get statuses; |  DateTime get date; SnCheckInResult? get checkInResult; List<SnAccountStatus> get statuses; | ||||||
| /// Create a copy of SnEventCalendarEntry | /// Create a copy of SnEventCalendarEntry | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @@ -894,7 +894,7 @@ abstract mixin class $SnEventCalendarEntryCopyWith<$Res>  { | |||||||
|   factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl; |   factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses |  DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -916,7 +916,7 @@ class _$SnEventCalendarEntryCopyWithImpl<$Res> | |||||||
| date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable | as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>, | as List<SnAccountStatus>, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| /// Create a copy of SnEventCalendarEntry | /// Create a copy of SnEventCalendarEntry | ||||||
| @@ -1010,7 +1010,7 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry() when $default != null: | case _SnEventCalendarEntry() when $default != null: | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);case _: | return $default(_that.date,_that.checkInResult,_that.statuses);case _: | ||||||
| @@ -1031,7 +1031,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry(): | case _SnEventCalendarEntry(): | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);} | return $default(_that.date,_that.checkInResult,_that.statuses);} | ||||||
| @@ -1048,7 +1048,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);} | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry() when $default != null: | case _SnEventCalendarEntry() when $default != null: | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);case _: | return $default(_that.date,_that.checkInResult,_that.statuses);case _: | ||||||
| @@ -1063,13 +1063,13 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _: | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnEventCalendarEntry implements SnEventCalendarEntry { | class _SnEventCalendarEntry implements SnEventCalendarEntry { | ||||||
|   const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<dynamic> statuses}): _statuses = statuses; |   const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<SnAccountStatus> statuses}): _statuses = statuses; | ||||||
|   factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json); |   factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json); | ||||||
|  |  | ||||||
| @override final  DateTime date; | @override final  DateTime date; | ||||||
| @override final  SnCheckInResult? checkInResult; | @override final  SnCheckInResult? checkInResult; | ||||||
|  final  List<dynamic> _statuses; |  final  List<SnAccountStatus> _statuses; | ||||||
| @override List<dynamic> get statuses { | @override List<SnAccountStatus> get statuses { | ||||||
|   if (_statuses is EqualUnmodifiableListView) return _statuses; |   if (_statuses is EqualUnmodifiableListView) return _statuses; | ||||||
|   // ignore: implicit_dynamic_type |   // ignore: implicit_dynamic_type | ||||||
|   return EqualUnmodifiableListView(_statuses); |   return EqualUnmodifiableListView(_statuses); | ||||||
| @@ -1109,7 +1109,7 @@ abstract mixin class _$SnEventCalendarEntryCopyWith<$Res> implements $SnEventCal | |||||||
|   factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl; |   factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses |  DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1131,7 +1131,7 @@ class __$SnEventCalendarEntryCopyWithImpl<$Res> | |||||||
| date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable | as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>, | as List<SnAccountStatus>, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -87,7 +87,10 @@ _SnEventCalendarEntry _$SnEventCalendarEntryFromJson( | |||||||
|           : SnCheckInResult.fromJson( |           : SnCheckInResult.fromJson( | ||||||
|             json['check_in_result'] as Map<String, dynamic>, |             json['check_in_result'] as Map<String, dynamic>, | ||||||
|           ), |           ), | ||||||
|   statuses: json['statuses'] as List<dynamic>, |   statuses: | ||||||
|  |       (json['statuses'] as List<dynamic>) | ||||||
|  |           .map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>)) | ||||||
|  |           .toList(), | ||||||
| ); | ); | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnEventCalendarEntryToJson( | Map<String, dynamic> _$SnEventCalendarEntryToJson( | ||||||
| @@ -95,5 +98,5 @@ Map<String, dynamic> _$SnEventCalendarEntryToJson( | |||||||
| ) => <String, dynamic>{ | ) => <String, dynamic>{ | ||||||
|   'date': instance.date.toIso8601String(), |   'date': instance.date.toIso8601String(), | ||||||
|   'check_in_result': instance.checkInResult?.toJson(), |   'check_in_result': instance.checkInResult?.toJson(), | ||||||
|   'statuses': instance.statuses, |   'statuses': instance.statuses.map((e) => e.toJson()).toList(), | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ sealed class SnPost with _$SnPost { | |||||||
|     @Default(0) int upvotes, |     @Default(0) int upvotes, | ||||||
|     @Default(0) int downvotes, |     @Default(0) int downvotes, | ||||||
|     @Default(0) int repliesCount, |     @Default(0) int repliesCount, | ||||||
|  |     int? pinMode, | ||||||
|     String? threadedPostId, |     String? threadedPostId, | ||||||
|     SnPost? threadedPost, |     SnPost? threadedPost, | ||||||
|     String? repliedPostId, |     String? repliedPostId, | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnPost { | mixin _$SnPost { | ||||||
|  |  | ||||||
|  String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated; |  String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated; | ||||||
| /// Create a copy of SnPost | /// Create a copy of SnPost | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]); | int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; |   return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -48,7 +48,7 @@ abstract mixin class $SnPostCopyWith<$Res>  { | |||||||
|   factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; |   factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated |  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPost | /// Create a copy of SnPost | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable | as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -83,7 +83,8 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: | |||||||
| as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -242,10 +243,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  int? pinMode,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPost() when $default != null: | case _SnPost() when $default != null: | ||||||
| return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -263,10 +264,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  int? pinMode,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPost(): | case _SnPost(): | ||||||
| return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);} | return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -280,10 +281,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String? title,  String? description,  String? language,  DateTime? editedAt,  DateTime? publishedAt,  int visibility,  String? content,  String? slug,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  int? pinMode,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  String? realmId,  SnRealm? realm,  List<SnCloudFile> attachments,  SnPublisher publisher,  Map<String, int> reactionsCount,  Map<String, bool> reactionsMade,  List<dynamic> reactions,  List<SnPostTag> tags,  List<SnPostCategory> categories,  List<dynamic> collections,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  bool isTruncated)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPost() when $default != null: | case _SnPost() when $default != null: | ||||||
| return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -295,7 +296,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnPost implements SnPost { | class _SnPost implements SnPost { | ||||||
|   const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final  List<SnCloudFile> attachments = const [], required this.publisher, final  Map<String, int> reactionsCount = const {}, final  Map<String, bool> reactionsMade = const {}, final  List<dynamic> reactions = const [], final  List<SnPostTag> tags = const [], final  List<SnPostCategory> categories = const [], final  List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; |   const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final  List<SnCloudFile> attachments = const [], required this.publisher, final  Map<String, int> reactionsCount = const {}, final  Map<String, bool> reactionsMade = const {}, final  List<dynamic> reactions = const [], final  List<SnPostTag> tags = const [], final  List<SnPostCategory> categories = const [], final  List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; | ||||||
|   factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); |   factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -322,6 +323,7 @@ class _SnPost implements SnPost { | |||||||
| @override@JsonKey() final  int upvotes; | @override@JsonKey() final  int upvotes; | ||||||
| @override@JsonKey() final  int downvotes; | @override@JsonKey() final  int downvotes; | ||||||
| @override@JsonKey() final  int repliesCount; | @override@JsonKey() final  int repliesCount; | ||||||
|  | @override final  int? pinMode; | ||||||
| @override final  String? threadedPostId; | @override final  String? threadedPostId; | ||||||
| @override final  SnPost? threadedPost; | @override final  SnPost? threadedPost; | ||||||
| @override final  String? repliedPostId; | @override final  String? repliedPostId; | ||||||
| @@ -398,16 +400,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]); | int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; |   return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -418,7 +420,7 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> { | |||||||
|   factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; |   factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated |  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -435,7 +437,7 @@ class __$SnPostCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPost | /// Create a copy of SnPost | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { | ||||||
|   return _then(_SnPost( |   return _then(_SnPost( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable | as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -453,7 +455,8 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: | |||||||
| as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost( | |||||||
|   upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, |   upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, | ||||||
|   downvotes: (json['downvotes'] as num?)?.toInt() ?? 0, |   downvotes: (json['downvotes'] as num?)?.toInt() ?? 0, | ||||||
|   repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0, |   repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0, | ||||||
|  |   pinMode: (json['pin_mode'] as num?)?.toInt(), | ||||||
|   threadedPostId: json['threaded_post_id'] as String?, |   threadedPostId: json['threaded_post_id'] as String?, | ||||||
|   threadedPost: |   threadedPost: | ||||||
|       json['threaded_post'] == null |       json['threaded_post'] == null | ||||||
| @@ -109,6 +110,7 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{ | |||||||
|   'upvotes': instance.upvotes, |   'upvotes': instance.upvotes, | ||||||
|   'downvotes': instance.downvotes, |   'downvotes': instance.downvotes, | ||||||
|   'replies_count': instance.repliesCount, |   'replies_count': instance.repliesCount, | ||||||
|  |   'pin_mode': instance.pinMode, | ||||||
|   'threaded_post_id': instance.threadedPostId, |   'threaded_post_id': instance.threadedPostId, | ||||||
|   'threaded_post': instance.threadedPost?.toJson(), |   'threaded_post': instance.threadedPost?.toJson(), | ||||||
|   'replied_post_id': instance.repliedPostId, |   'replied_post_id': instance.repliedPostId, | ||||||
|   | |||||||
| @@ -279,6 +279,24 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|               if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName), |               if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|  |         Tooltip( | ||||||
|  |           message: 'creditsStatus'.tr(), | ||||||
|  |           child: Row( | ||||||
|  |             spacing: 6, | ||||||
|  |             children: [ | ||||||
|  |               Icon(Symbols.star, size: 17, fill: 1).padding(right: 2), | ||||||
|  |               Text('${data.profile.socialCredits.toStringAsFixed(2)} pts'), | ||||||
|  |               Text('·').bold(), | ||||||
|  |               switch (data.profile.socialCreditsLevel) { | ||||||
|  |                 -1 => Text('socialCreditsLevelPoor').tr(), | ||||||
|  |                 0 => Text('socialCreditsLevelNormal').tr(), | ||||||
|  |                 1 => Text('socialCreditsLevelGood').tr(), | ||||||
|  |                 2 => Text('socialCreditsLevelExcellent').tr(), | ||||||
|  |                 _ => Text('unknown').tr(), | ||||||
|  |               }, | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|       ]; |       ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -72,6 +72,207 @@ class _AppLifecycleObserver extends WidgetsBindingObserver { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class _PublicRoomPreview extends HookConsumerWidget { | ||||||
|  |   final String id; | ||||||
|  |   final SnChatRoom room; | ||||||
|  |  | ||||||
|  |   const _PublicRoomPreview({required this.id, required this.room}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final messages = ref.watch(messagesNotifierProvider(id)); | ||||||
|  |     final messagesNotifier = ref.read(messagesNotifierProvider(id).notifier); | ||||||
|  |     final scrollController = useScrollController(); | ||||||
|  |  | ||||||
|  |     final listController = useMemoized(() => ListController(), []); | ||||||
|  |  | ||||||
|  |     var isLoading = false; | ||||||
|  |  | ||||||
|  |     // Add scroll listener for pagination | ||||||
|  |     useEffect(() { | ||||||
|  |       void onScroll() { | ||||||
|  |         if (scrollController.position.pixels >= | ||||||
|  |             scrollController.position.maxScrollExtent - 200) { | ||||||
|  |           if (isLoading) return; | ||||||
|  |           isLoading = true; | ||||||
|  |           messagesNotifier.loadMore().then((_) => isLoading = false); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       scrollController.addListener(onScroll); | ||||||
|  |       return () => scrollController.removeListener(onScroll); | ||||||
|  |     }, [scrollController]); | ||||||
|  |  | ||||||
|  |     Widget chatMessageListWidget(List<LocalChatMessage> messageList) => | ||||||
|  |         SuperListView.builder( | ||||||
|  |           listController: listController, | ||||||
|  |           padding: EdgeInsets.symmetric(vertical: 16), | ||||||
|  |           controller: scrollController, | ||||||
|  |           reverse: true, // Show newest messages at the bottom | ||||||
|  |           itemCount: messageList.length, | ||||||
|  |           findChildIndexCallback: (key) { | ||||||
|  |             final valueKey = key as ValueKey; | ||||||
|  |             final messageId = valueKey.value as String; | ||||||
|  |             return messageList.indexWhere((m) => m.id == messageId); | ||||||
|  |           }, | ||||||
|  |           extentEstimation: (_, _) => 40, | ||||||
|  |           itemBuilder: (context, index) { | ||||||
|  |             final message = messageList[index]; | ||||||
|  |             final nextMessage = | ||||||
|  |                 index < messageList.length - 1 ? messageList[index + 1] : null; | ||||||
|  |             final isLastInGroup = | ||||||
|  |                 nextMessage == null || | ||||||
|  |                 nextMessage.senderId != message.senderId || | ||||||
|  |                 nextMessage.createdAt | ||||||
|  |                         .difference(message.createdAt) | ||||||
|  |                         .inMinutes | ||||||
|  |                         .abs() > | ||||||
|  |                     3; | ||||||
|  |  | ||||||
|  |             return MessageItem( | ||||||
|  |               message: message, | ||||||
|  |               isCurrentUser: false, // User is not a member, so not current user | ||||||
|  |               onAction: null, // No actions allowed in preview mode | ||||||
|  |               onJump: (_) {}, // No jump functionality in preview | ||||||
|  |               progress: null, | ||||||
|  |               showAvatar: isLastInGroup, | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |     final compactHeader = isWideScreen(context); | ||||||
|  |  | ||||||
|  |     Widget comfortHeaderWidget() => Column( | ||||||
|  |       spacing: 4, | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         SizedBox( | ||||||
|  |           height: 26, | ||||||
|  |           width: 26, | ||||||
|  |           child: | ||||||
|  |               (room.type == 1 && room.picture?.id == null) | ||||||
|  |                   ? SplitAvatarWidget( | ||||||
|  |                     filesId: | ||||||
|  |                         room.members! | ||||||
|  |                             .map((e) => e.account.profile.picture?.id) | ||||||
|  |                             .toList(), | ||||||
|  |                   ) | ||||||
|  |                   : room.picture?.id != null | ||||||
|  |                   ? ProfilePictureWidget( | ||||||
|  |                     fileId: room.picture?.id, | ||||||
|  |                     fallbackIcon: Symbols.chat, | ||||||
|  |                   ) | ||||||
|  |                   : CircleAvatar( | ||||||
|  |                     child: Text( | ||||||
|  |                       room.name![0].toUpperCase(), | ||||||
|  |                       style: const TextStyle(fontSize: 12), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |         ), | ||||||
|  |         Text( | ||||||
|  |           (room.type == 1 && room.name == null) | ||||||
|  |               ? room.members!.map((e) => e.account.nick).join(', ') | ||||||
|  |               : room.name!, | ||||||
|  |         ).fontSize(15), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     Widget compactHeaderWidget() => Row( | ||||||
|  |       spacing: 8, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         SizedBox( | ||||||
|  |           height: 26, | ||||||
|  |           width: 26, | ||||||
|  |           child: | ||||||
|  |               (room.type == 1 && room.picture?.id == null) | ||||||
|  |                   ? SplitAvatarWidget( | ||||||
|  |                     filesId: | ||||||
|  |                         room.members! | ||||||
|  |                             .map((e) => e.account.profile.picture?.id) | ||||||
|  |                             .toList(), | ||||||
|  |                   ) | ||||||
|  |                   : room.picture?.id != null | ||||||
|  |                   ? ProfilePictureWidget( | ||||||
|  |                     fileId: room.picture?.id, | ||||||
|  |                     fallbackIcon: Symbols.chat, | ||||||
|  |                   ) | ||||||
|  |                   : CircleAvatar( | ||||||
|  |                     child: Text( | ||||||
|  |                       room.name![0].toUpperCase(), | ||||||
|  |                       style: const TextStyle(fontSize: 12), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |         ), | ||||||
|  |         Text( | ||||||
|  |           (room.type == 1 && room.name == null) | ||||||
|  |               ? room.members!.map((e) => e.account.nick).join(', ') | ||||||
|  |               : room.name!, | ||||||
|  |         ).fontSize(19), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         leading: !compactHeader ? const Center(child: PageBackButton()) : null, | ||||||
|  |         automaticallyImplyLeading: false, | ||||||
|  |         toolbarHeight: compactHeader ? null : 64, | ||||||
|  |         title: compactHeader ? compactHeaderWidget() : comfortHeaderWidget(), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Icons.more_vert), | ||||||
|  |             onPressed: () { | ||||||
|  |               context.pushNamed('chatDetail', pathParameters: {'id': id}); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |           const Gap(8), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |       body: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |         children: [ | ||||||
|  |           Expanded( | ||||||
|  |             child: messages.when( | ||||||
|  |               data: | ||||||
|  |                   (messageList) => | ||||||
|  |                       messageList.isEmpty | ||||||
|  |                           ? Center(child: Text('No messages yet'.tr())) | ||||||
|  |                           : chatMessageListWidget(messageList), | ||||||
|  |               loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |               error: | ||||||
|  |                   (error, _) => ResponseErrorWidget( | ||||||
|  |                     error: error, | ||||||
|  |                     onRetry: () => messagesNotifier.loadInitial(), | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           // Join button at the bottom for public rooms | ||||||
|  |           Container( | ||||||
|  |             padding: const EdgeInsets.all(16), | ||||||
|  |             child: FilledButton.tonalIcon( | ||||||
|  |               onPressed: () async { | ||||||
|  |                 try { | ||||||
|  |                   showLoadingModal(context); | ||||||
|  |                   final apiClient = ref.read(apiClientProvider); | ||||||
|  |                   await apiClient.post('/sphere/chat/${room.id}/members/me'); | ||||||
|  |                   ref.invalidate(chatroomIdentityProvider(id)); | ||||||
|  |                 } catch (err) { | ||||||
|  |                   showErrorAlert(err); | ||||||
|  |                 } finally { | ||||||
|  |                   if (context.mounted) hideLoadingModal(context); | ||||||
|  |                 } | ||||||
|  |               }, | ||||||
|  |               label: Text('chatJoin').tr(), | ||||||
|  |               icon: const Icon(Icons.add), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| @riverpod | @riverpod | ||||||
| class MessagesNotifier extends _$MessagesNotifier { | class MessagesNotifier extends _$MessagesNotifier { | ||||||
|   late final Dio _apiClient; |   late final Dio _apiClient; | ||||||
| @@ -96,17 +297,24 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     _database = ref.watch(databaseProvider); |     _database = ref.watch(databaseProvider); | ||||||
|     final room = await ref.watch(chatroomProvider(roomId).future); |     final room = await ref.watch(chatroomProvider(roomId).future); | ||||||
|     final identity = await ref.watch(chatroomIdentityProvider(roomId).future); |     final identity = await ref.watch(chatroomIdentityProvider(roomId).future); | ||||||
|     if (room == null || identity == null) { |  | ||||||
|       throw Exception('Room or identity not found'); |     if (room == null) { | ||||||
|  |       throw Exception('Room not found'); | ||||||
|     } |     } | ||||||
|     _room = room; |     _room = room; | ||||||
|  |  | ||||||
|  |     // Allow building even if identity is null for public rooms | ||||||
|  |     if (identity != null) { | ||||||
|       _identity = identity; |       _identity = identity; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     developer.log( |     developer.log( | ||||||
|       'MessagesNotifier built for room $roomId', |       'MessagesNotifier built for room $roomId', | ||||||
|       name: 'MessagesNotifier', |       name: 'MessagesNotifier', | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     // Only setup sync and lifecycle listeners if user is a member | ||||||
|  |     if (identity != null) { | ||||||
|       ref.listen(appLifecycleStateProvider, (_, next) { |       ref.listen(appLifecycleStateProvider, (_, next) { | ||||||
|         if (next.hasValue && next.value == AppLifecycleState.resumed) { |         if (next.hasValue && next.value == AppLifecycleState.resumed) { | ||||||
|           developer.log( |           developer.log( | ||||||
| @@ -116,6 +324,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|           syncMessages(); |           syncMessages(); | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return await loadInitial(); |     return await loadInitial(); | ||||||
|   } |   } | ||||||
| @@ -455,9 +664,12 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|  |  | ||||||
|       final currentMessages = state.value ?? []; |       final currentMessages = state.value ?? []; | ||||||
|       if (editingTo != null) { |       if (editingTo != null) { | ||||||
|         final newMessages = currentMessages |         final newMessages = | ||||||
|  |             currentMessages | ||||||
|                 .where((m) => m.id != localMessage.id) // remove pending message |                 .where((m) => m.id != localMessage.id) // remove pending message | ||||||
|             .map((m) => m.id == editingTo.id ? updatedMessage : m) // update original message |                 .map( | ||||||
|  |                   (m) => m.id == editingTo.id ? updatedMessage : m, | ||||||
|  |                 ) // update original message | ||||||
|                 .toList(); |                 .toList(); | ||||||
|         state = AsyncValue.data(newMessages); |         state = AsyncValue.data(newMessages); | ||||||
|       } else { |       } else { | ||||||
| @@ -734,6 +946,13 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|       ); |       ); | ||||||
|     } else if (chatIdentity.value == null) { |     } else if (chatIdentity.value == null) { | ||||||
|       // Identity was not found, user was not joined |       // Identity was not found, user was not joined | ||||||
|  |       return chatRoom.when( | ||||||
|  |         data: (room) { | ||||||
|  |           if (room!.isPublic) { | ||||||
|  |             // Show public room preview with messages but no input | ||||||
|  |             return _PublicRoomPreview(id: id, room: room); | ||||||
|  |           } else { | ||||||
|  |             // Show regular "not joined" screen for private rooms | ||||||
|             return AppScaffold( |             return AppScaffold( | ||||||
|               appBar: AppBar(leading: const PageBackButton()), |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|               body: Center( |               body: Center( | ||||||
| @@ -745,14 +964,14 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|                         mainAxisAlignment: MainAxisAlignment.center, |                         mainAxisAlignment: MainAxisAlignment.center, | ||||||
|                         children: [ |                         children: [ | ||||||
|                           Icon( |                           Icon( | ||||||
|                       chatRoom.value?.isCommunity == true |                             room.isCommunity == true | ||||||
|                                 ? Symbols.person_add |                                 ? Symbols.person_add | ||||||
|                                 : Symbols.person_remove, |                                 : Symbols.person_remove, | ||||||
|                             size: 36, |                             size: 36, | ||||||
|                             fill: 1, |                             fill: 1, | ||||||
|                           ).padding(bottom: 4), |                           ).padding(bottom: 4), | ||||||
|                           Text('chatNotJoined').tr(), |                           Text('chatNotJoined').tr(), | ||||||
|                     if (chatRoom.value?.isCommunity != true) |                           if (room.isCommunity != true) | ||||||
|                             Text( |                             Text( | ||||||
|                               'chatUnableJoin', |                               'chatUnableJoin', | ||||||
|                               textAlign: TextAlign.center, |                               textAlign: TextAlign.center, | ||||||
| @@ -763,19 +982,16 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|                                 try { |                                 try { | ||||||
|                                   showLoadingModal(context); |                                   showLoadingModal(context); | ||||||
|                                   final apiClient = ref.read(apiClientProvider); |                                   final apiClient = ref.read(apiClientProvider); | ||||||
|                             if (chatRoom.value == null) { |  | ||||||
|                               hideLoadingModal(context); |  | ||||||
|                               return; |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                                   await apiClient.post( |                                   await apiClient.post( | ||||||
|                               '/sphere/chat/${chatRoom.value!.id}/members/me', |                                     '/sphere/chat/${room.id}/members/me', | ||||||
|                                   ); |                                   ); | ||||||
|                                   ref.invalidate(chatroomIdentityProvider(id)); |                                   ref.invalidate(chatroomIdentityProvider(id)); | ||||||
|                                 } catch (err) { |                                 } catch (err) { | ||||||
|                                   showErrorAlert(err); |                                   showErrorAlert(err); | ||||||
|                                 } finally { |                                 } finally { | ||||||
|                             if (context.mounted) hideLoadingModal(context); |                                   if (context.mounted) { | ||||||
|  |                                     hideLoadingModal(context); | ||||||
|  |                                   } | ||||||
|                                 } |                                 } | ||||||
|                               }, |                               }, | ||||||
|                               label: Text('chatJoin').tr(), |                               label: Text('chatJoin').tr(), | ||||||
| @@ -787,6 +1003,22 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|               ), |               ), | ||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|  |         }, | ||||||
|  |         loading: | ||||||
|  |             () => AppScaffold( | ||||||
|  |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|  |               body: CircularProgressIndicator().center(), | ||||||
|  |             ), | ||||||
|  |         error: | ||||||
|  |             (error, _) => AppScaffold( | ||||||
|  |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|  |               body: ResponseErrorWidget( | ||||||
|  |                 error: error, | ||||||
|  |                 onRetry: () => ref.refresh(chatroomProvider(id)), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     final messages = ref.watch(messagesNotifierProvider(id)); |     final messages = ref.watch(messagesNotifierProvider(id)); | ||||||
|     final messagesNotifier = ref.read(messagesNotifierProvider(id).notifier); |     final messagesNotifier = ref.read(messagesNotifierProvider(id).notifier); | ||||||
| @@ -1549,7 +1781,7 @@ class _ChatInput extends HookConsumerWidget { | |||||||
|                   children: [ |                   children: [ | ||||||
|                     IconButton( |                     IconButton( | ||||||
|                       tooltip: 'stickers'.tr(), |                       tooltip: 'stickers'.tr(), | ||||||
|                       icon: const Icon(Symbols.emoji_symbols), |                       icon: const Icon(Symbols.add_reaction), | ||||||
|                       onPressed: () { |                       onPressed: () { | ||||||
|                         final size = MediaQuery.of(context).size; |                         final size = MediaQuery.of(context).size; | ||||||
|                         showStickerPickerPopover( |                         showStickerPickerPopover( | ||||||
| @@ -1659,8 +1891,13 @@ class _ChatInput extends HookConsumerWidget { | |||||||
|                           horizontal: 12, |                           horizontal: 12, | ||||||
|                           vertical: 4, |                           vertical: 4, | ||||||
|                         ), |                         ), | ||||||
|  |                         counterText: | ||||||
|  |                             messageController.text.length > 1024 | ||||||
|  |                                 ? '${messageController.text.length}/4096' | ||||||
|  |                                 : null, | ||||||
|                       ), |                       ), | ||||||
|                       maxLines: null, |                       maxLines: 3, | ||||||
|  |                       minLines: 1, | ||||||
|                       onTapOutside: |                       onTapOutside: | ||||||
|                           (_) => FocusManager.instance.primaryFocus?.unfocus(), |                           (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||||
|                     ), |                     ), | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'room.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$messagesNotifierHash() => r'32afe6ea24086d869cc47bd3389c8fd734409ca0'; | String _$messagesNotifierHash() => r'dda98f5bf525f3b2bc0a7c89bc6eaa3c8b95f142'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; | |||||||
| import 'package:island/models/chat.dart'; | import 'package:island/models/chat.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/screens/chat/chat.dart'; | import 'package:island/screens/chat/chat.dart'; | ||||||
|  | import 'package:island/widgets/account/account_pfc.dart'; | ||||||
| import 'package:island/widgets/account/account_picker.dart'; | import 'package:island/widgets/account/account_picker.dart'; | ||||||
| import 'package:island/widgets/account/status.dart'; | import 'package:island/widgets/account/status.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| @@ -666,9 +667,12 @@ class _ChatMemberListSheet extends HookConsumerWidget { | |||||||
|                     final member = data.items[index]; |                     final member = data.items[index]; | ||||||
|                     return ListTile( |                     return ListTile( | ||||||
|                       contentPadding: EdgeInsets.only(left: 16, right: 12), |                       contentPadding: EdgeInsets.only(left: 16, right: 12), | ||||||
|                       leading: ProfilePictureWidget( |                       leading: AccountPfcGestureDetector( | ||||||
|  |                         uname: member.account.name, | ||||||
|  |                         child: ProfilePictureWidget( | ||||||
|                           fileId: member.account.profile.picture?.id, |                           fileId: member.account.profile.picture?.id, | ||||||
|                         ), |                         ), | ||||||
|  |                       ), | ||||||
|                       title: Row( |                       title: Row( | ||||||
|                         spacing: 6, |                         spacing: 6, | ||||||
|                         children: [ |                         children: [ | ||||||
|   | |||||||
| @@ -137,6 +137,7 @@ class ArticlesScreen extends ConsumerWidget { | |||||||
|         return DefaultTabController( |         return DefaultTabController( | ||||||
|           length: feeds.length + 1, |           length: feeds.length + 1, | ||||||
|           child: AppScaffold( |           child: AppScaffold( | ||||||
|  |             isNoBackground: false, | ||||||
|             appBar: AppBar( |             appBar: AppBar( | ||||||
|               title: const Text('Articles'), |               title: const Text('Articles'), | ||||||
|               bottom: TabBar( |               bottom: TabBar( | ||||||
| @@ -192,11 +193,13 @@ class ArticlesScreen extends ConsumerWidget { | |||||||
|       }, |       }, | ||||||
|       loading: |       loading: | ||||||
|           () => AppScaffold( |           () => AppScaffold( | ||||||
|  |             isNoBackground: false, | ||||||
|             appBar: AppBar(title: const Text('Articles')), |             appBar: AppBar(title: const Text('Articles')), | ||||||
|             body: const Center(child: CircularProgressIndicator()), |             body: const Center(child: CircularProgressIndicator()), | ||||||
|           ), |           ), | ||||||
|       error: |       error: | ||||||
|           (err, stack) => AppScaffold( |           (err, stack) => AppScaffold( | ||||||
|  |             isNoBackground: false, | ||||||
|             appBar: AppBar(title: const Text('Articles')), |             appBar: AppBar(title: const Text('Articles')), | ||||||
|             body: Center(child: Text('Error: $err')), |             body: Center(child: Text('Error: $err')), | ||||||
|           ), |           ), | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import 'package:island/pods/network.dart'; | |||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/post/post_list.dart'; | import 'package:island/widgets/post/post_list.dart'; | ||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/material_symbols_icons.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
| @@ -27,6 +28,49 @@ Future<SnPostTag> postTag(Ref ref, String slug) async { | |||||||
|   return SnPostTag.fromJson(resp.data); |   return SnPostTag.fromJson(resp.data); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<bool> postCategorySubscriptionStatus( | ||||||
|  |   Ref ref, | ||||||
|  |   String slug, | ||||||
|  |   bool isCategory, | ||||||
|  | ) async { | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   try { | ||||||
|  |     final resp = await apiClient.get( | ||||||
|  |       '/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/subscription', | ||||||
|  |     ); | ||||||
|  |     return resp.statusCode == 200; | ||||||
|  |   } catch (_) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Future<void> _subscribeToCategoryOrTag( | ||||||
|  |   WidgetRef ref, { | ||||||
|  |   required String slug, | ||||||
|  |   required bool isCategory, | ||||||
|  | }) async { | ||||||
|  |   final apiClient = ref.read(apiClientProvider); | ||||||
|  |   await apiClient.post( | ||||||
|  |     '/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/subscribe', | ||||||
|  |   ); | ||||||
|  |   // Invalidate the subscription status to refresh it | ||||||
|  |   ref.invalidate(postCategorySubscriptionStatusProvider(slug, isCategory)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Future<void> _unsubscribeFromCategoryOrTag( | ||||||
|  |   WidgetRef ref, { | ||||||
|  |   required String slug, | ||||||
|  |   required bool isCategory, | ||||||
|  | }) async { | ||||||
|  |   final apiClient = ref.read(apiClientProvider); | ||||||
|  |   await apiClient.post( | ||||||
|  |     '/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/unsubscribe', | ||||||
|  |   ); | ||||||
|  |   // Invalidate the subscription status to refresh it | ||||||
|  |   ref.invalidate(postCategorySubscriptionStatusProvider(slug, isCategory)); | ||||||
|  | } | ||||||
|  |  | ||||||
| class PostCategoryDetailScreen extends HookConsumerWidget { | class PostCategoryDetailScreen extends HookConsumerWidget { | ||||||
|   final String slug; |   final String slug; | ||||||
|   final bool isCategory; |   final bool isCategory; | ||||||
| @@ -41,6 +85,9 @@ class PostCategoryDetailScreen extends HookConsumerWidget { | |||||||
|     final postCategory = |     final postCategory = | ||||||
|         isCategory ? ref.watch(postCategoryProvider(slug)) : null; |         isCategory ? ref.watch(postCategoryProvider(slug)) : null; | ||||||
|     final postTag = isCategory ? null : ref.watch(postTagProvider(slug)); |     final postTag = isCategory ? null : ref.watch(postTagProvider(slug)); | ||||||
|  |     final subscriptionStatus = ref.watch( | ||||||
|  |       postCategorySubscriptionStatusProvider(slug, isCategory), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     final postFilterTitle = |     final postFilterTitle = | ||||||
|         isCategory |         isCategory | ||||||
| @@ -50,58 +97,159 @@ class PostCategoryDetailScreen extends HookConsumerWidget { | |||||||
|     return AppScaffold( |     return AppScaffold( | ||||||
|       isNoBackground: false, |       isNoBackground: false, | ||||||
|       appBar: AppBar(title: Text(postFilterTitle).tr()), |       appBar: AppBar(title: Text(postFilterTitle).tr()), | ||||||
|       body: Column( |       body: Expanded( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|         children: [ |  | ||||||
|           if (isCategory) |  | ||||||
|             postCategory!.when( |  | ||||||
|               data: |  | ||||||
|                   (category) => Column( |  | ||||||
|                     crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                     children: [ |  | ||||||
|                       Text(category.categoryDisplayTitle).bold().fontSize(15), |  | ||||||
|                       Text('A category'), |  | ||||||
|                     ], |  | ||||||
|                   ).padding(horizontal: 24, vertical: 16), |  | ||||||
|               error: |  | ||||||
|                   (error, _) => ResponseErrorWidget( |  | ||||||
|                     error: error, |  | ||||||
|                     onRetry: () => ref.invalidate(postCategoryProvider(slug)), |  | ||||||
|                   ), |  | ||||||
|               loading: () => ResponseLoadingWidget(), |  | ||||||
|             ) |  | ||||||
|           else |  | ||||||
|             postTag!.when( |  | ||||||
|               data: |  | ||||||
|                   (tag) => Column( |  | ||||||
|                     crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                     children: [ |  | ||||||
|                       Text(tag.name ?? '#${tag.slug}').bold().fontSize(15), |  | ||||||
|                       Text('A tag'), |  | ||||||
|                     ], |  | ||||||
|                   ).padding(horizontal: 24, vertical: 16), |  | ||||||
|               error: |  | ||||||
|                   (error, _) => ResponseErrorWidget( |  | ||||||
|                     error: error, |  | ||||||
|                     onRetry: () => ref.invalidate(postTagProvider(slug)), |  | ||||||
|                   ), |  | ||||||
|               loading: () => ResponseLoadingWidget(), |  | ||||||
|             ), |  | ||||||
|           const Divider(height: 1), |  | ||||||
|           Expanded( |  | ||||||
|         child: CustomScrollView( |         child: CustomScrollView( | ||||||
|           slivers: [ |           slivers: [ | ||||||
|  |             if (isCategory) | ||||||
|  |               SliverToBoxAdapter( | ||||||
|  |                 child: Center( | ||||||
|  |                   child: ConstrainedBox( | ||||||
|  |                     constraints: const BoxConstraints(maxWidth: 540), | ||||||
|  |                     child: Card( | ||||||
|  |                       margin: EdgeInsets.only(top: 8), | ||||||
|  |                       child: postCategory!.when( | ||||||
|  |                         data: | ||||||
|  |                             (category) => Column( | ||||||
|  |                               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                               children: [ | ||||||
|  |                                 Text( | ||||||
|  |                                   category.categoryDisplayTitle, | ||||||
|  |                                 ).bold().fontSize(15), | ||||||
|  |                                 Text('A category'), | ||||||
|  |                                 const Gap(8), | ||||||
|  |                                 subscriptionStatus.when( | ||||||
|  |                                   data: | ||||||
|  |                                       (isSubscribed) => | ||||||
|  |                                           isSubscribed | ||||||
|  |                                               ? FilledButton.icon( | ||||||
|  |                                                 onPressed: () async { | ||||||
|  |                                                   await _unsubscribeFromCategoryOrTag( | ||||||
|  |                                                     ref, | ||||||
|  |                                                     slug: slug, | ||||||
|  |                                                     isCategory: isCategory, | ||||||
|  |                                                   ); | ||||||
|  |                                                 }, | ||||||
|  |                                                 icon: const Icon( | ||||||
|  |                                                   Symbols.remove_circle, | ||||||
|  |                                                 ), | ||||||
|  |                                                 label: Text('unsubscribe'.tr()), | ||||||
|  |                                               ) | ||||||
|  |                                               : FilledButton.icon( | ||||||
|  |                                                 onPressed: () async { | ||||||
|  |                                                   await _subscribeToCategoryOrTag( | ||||||
|  |                                                     ref, | ||||||
|  |                                                     slug: slug, | ||||||
|  |                                                     isCategory: isCategory, | ||||||
|  |                                                   ); | ||||||
|  |                                                 }, | ||||||
|  |                                                 icon: const Icon( | ||||||
|  |                                                   Symbols.add_circle, | ||||||
|  |                                                 ), | ||||||
|  |                                                 label: Text('subscribe'.tr()), | ||||||
|  |                                               ), | ||||||
|  |                                   error: | ||||||
|  |                                       (error, _) => Text( | ||||||
|  |                                         'Error loading subscription status', | ||||||
|  |                                       ), | ||||||
|  |                                   loading: | ||||||
|  |                                       () => | ||||||
|  |                                           CircularProgressIndicator().center(), | ||||||
|  |                                 ), | ||||||
|  |                               ], | ||||||
|  |                             ).padding(horizontal: 24, vertical: 16), | ||||||
|  |                         error: | ||||||
|  |                             (error, _) => ResponseErrorWidget( | ||||||
|  |                               error: error, | ||||||
|  |                               onRetry: | ||||||
|  |                                   () => ref.invalidate( | ||||||
|  |                                     postCategoryProvider(slug), | ||||||
|  |                                   ), | ||||||
|  |                             ), | ||||||
|  |                         loading: () => ResponseLoadingWidget(), | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             else | ||||||
|  |               SliverToBoxAdapter( | ||||||
|  |                 child: Center( | ||||||
|  |                   child: ConstrainedBox( | ||||||
|  |                     constraints: const BoxConstraints(maxWidth: 540), | ||||||
|  |                     child: Card( | ||||||
|  |                       margin: EdgeInsets.only(top: 8), | ||||||
|  |                       child: postTag!.when( | ||||||
|  |                         data: | ||||||
|  |                             (tag) => Column( | ||||||
|  |                               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                               children: [ | ||||||
|  |                                 Text( | ||||||
|  |                                   tag.name ?? '#${tag.slug}', | ||||||
|  |                                 ).bold().fontSize(15), | ||||||
|  |                                 Text('A tag'), | ||||||
|  |                                 const Gap(8), | ||||||
|  |                                 subscriptionStatus.when( | ||||||
|  |                                   data: | ||||||
|  |                                       (isSubscribed) => | ||||||
|  |                                           isSubscribed | ||||||
|  |                                               ? FilledButton.icon( | ||||||
|  |                                                 onPressed: () async { | ||||||
|  |                                                   await _unsubscribeFromCategoryOrTag( | ||||||
|  |                                                     ref, | ||||||
|  |                                                     slug: slug, | ||||||
|  |                                                     isCategory: isCategory, | ||||||
|  |                                                   ); | ||||||
|  |                                                 }, | ||||||
|  |                                                 icon: const Icon( | ||||||
|  |                                                   Symbols.add_circle, | ||||||
|  |                                                 ), | ||||||
|  |                                                 label: Text('unsubscribe'.tr()), | ||||||
|  |                                               ) | ||||||
|  |                                               : FilledButton.icon( | ||||||
|  |                                                 onPressed: () async { | ||||||
|  |                                                   await _subscribeToCategoryOrTag( | ||||||
|  |                                                     ref, | ||||||
|  |                                                     slug: slug, | ||||||
|  |                                                     isCategory: isCategory, | ||||||
|  |                                                   ); | ||||||
|  |                                                 }, | ||||||
|  |                                                 icon: const Icon( | ||||||
|  |                                                   Symbols.remove_circle, | ||||||
|  |                                                 ), | ||||||
|  |                                                 label: Text('subscribe'.tr()), | ||||||
|  |                                               ), | ||||||
|  |                                   error: | ||||||
|  |                                       (error, _) => Text( | ||||||
|  |                                         'Error loading subscription status', | ||||||
|  |                                       ), | ||||||
|  |                                   loading: | ||||||
|  |                                       () => | ||||||
|  |                                           CircularProgressIndicator().center(), | ||||||
|  |                                 ), | ||||||
|  |                               ], | ||||||
|  |                             ).padding(horizontal: 24, vertical: 16), | ||||||
|  |                         error: | ||||||
|  |                             (error, _) => ResponseErrorWidget( | ||||||
|  |                               error: error, | ||||||
|  |                               onRetry: | ||||||
|  |                                   () => ref.invalidate(postTagProvider(slug)), | ||||||
|  |                             ), | ||||||
|  |                         loading: () => ResponseLoadingWidget(), | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|             const SliverGap(4), |             const SliverGap(4), | ||||||
|             SliverPostList( |             SliverPostList( | ||||||
|               categories: isCategory ? [slug] : null, |               categories: isCategory ? [slug] : null, | ||||||
|               tags: isCategory ? null : [slug], |               tags: isCategory ? null : [slug], | ||||||
|  |               maxWidth: 540 + 16, | ||||||
|             ), |             ), | ||||||
|             SliverGap(MediaQuery.of(context).padding.bottom + 8), |             SliverGap(MediaQuery.of(context).padding.bottom + 8), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|         ], |  | ||||||
|       ), |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -266,5 +266,146 @@ class _PostTagProviderElement | |||||||
|   String get slug => (origin as PostTagProvider).slug; |   String get slug => (origin as PostTagProvider).slug; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | String _$postCategorySubscriptionStatusHash() => | ||||||
|  |     r'407dc7fcaeffc461b591b4ee2418811aa4f0a63f'; | ||||||
|  |  | ||||||
|  | /// See also [postCategorySubscriptionStatus]. | ||||||
|  | @ProviderFor(postCategorySubscriptionStatus) | ||||||
|  | const postCategorySubscriptionStatusProvider = | ||||||
|  |     PostCategorySubscriptionStatusFamily(); | ||||||
|  |  | ||||||
|  | /// See also [postCategorySubscriptionStatus]. | ||||||
|  | class PostCategorySubscriptionStatusFamily extends Family<AsyncValue<bool>> { | ||||||
|  |   /// See also [postCategorySubscriptionStatus]. | ||||||
|  |   const PostCategorySubscriptionStatusFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [postCategorySubscriptionStatus]. | ||||||
|  |   PostCategorySubscriptionStatusProvider call(String slug, bool isCategory) { | ||||||
|  |     return PostCategorySubscriptionStatusProvider(slug, isCategory); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   PostCategorySubscriptionStatusProvider getProviderOverride( | ||||||
|  |     covariant PostCategorySubscriptionStatusProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.slug, provider.isCategory); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'postCategorySubscriptionStatusProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [postCategorySubscriptionStatus]. | ||||||
|  | class PostCategorySubscriptionStatusProvider | ||||||
|  |     extends AutoDisposeFutureProvider<bool> { | ||||||
|  |   /// See also [postCategorySubscriptionStatus]. | ||||||
|  |   PostCategorySubscriptionStatusProvider(String slug, bool isCategory) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => postCategorySubscriptionStatus( | ||||||
|  |           ref as PostCategorySubscriptionStatusRef, | ||||||
|  |           slug, | ||||||
|  |           isCategory, | ||||||
|  |         ), | ||||||
|  |         from: postCategorySubscriptionStatusProvider, | ||||||
|  |         name: r'postCategorySubscriptionStatusProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$postCategorySubscriptionStatusHash, | ||||||
|  |         dependencies: PostCategorySubscriptionStatusFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: | ||||||
|  |             PostCategorySubscriptionStatusFamily._allTransitiveDependencies, | ||||||
|  |         slug: slug, | ||||||
|  |         isCategory: isCategory, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   PostCategorySubscriptionStatusProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.slug, | ||||||
|  |     required this.isCategory, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String slug; | ||||||
|  |   final bool isCategory; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<bool> Function(PostCategorySubscriptionStatusRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: PostCategorySubscriptionStatusProvider._internal( | ||||||
|  |         (ref) => create(ref as PostCategorySubscriptionStatusRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         slug: slug, | ||||||
|  |         isCategory: isCategory, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<bool> createElement() { | ||||||
|  |     return _PostCategorySubscriptionStatusProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is PostCategorySubscriptionStatusProvider && | ||||||
|  |         other.slug == slug && | ||||||
|  |         other.isCategory == isCategory; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, slug.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, isCategory.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin PostCategorySubscriptionStatusRef on AutoDisposeFutureProviderRef<bool> { | ||||||
|  |   /// The parameter `slug` of this provider. | ||||||
|  |   String get slug; | ||||||
|  |  | ||||||
|  |   /// The parameter `isCategory` of this provider. | ||||||
|  |   bool get isCategory; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _PostCategorySubscriptionStatusProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<bool> | ||||||
|  |     with PostCategorySubscriptionStatusRef { | ||||||
|  |   _PostCategorySubscriptionStatusProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get slug => (origin as PostCategorySubscriptionStatusProvider).slug; | ||||||
|  |   @override | ||||||
|  |   bool get isCategory => | ||||||
|  |       (origin as PostCategorySubscriptionStatusProvider).isCategory; | ||||||
|  | } | ||||||
|  |  | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
|   | |||||||
| @@ -288,7 +288,11 @@ class PublisherProfileScreen extends HookConsumerWidget { | |||||||
|         controller: categoryTabController, |         controller: categoryTabController, | ||||||
|         dividerColor: Colors.transparent, |         dividerColor: Colors.transparent, | ||||||
|         splashBorderRadius: const BorderRadius.all(Radius.circular(8)), |         splashBorderRadius: const BorderRadius.all(Radius.circular(8)), | ||||||
|         tabs: [Tab(text: 'All'), Tab(text: 'Posts'), Tab(text: 'Articles')], |         tabs: [ | ||||||
|  |           Tab(text: 'all'.tr()), | ||||||
|  |           Tab(text: 'postTypePost'.tr()), | ||||||
|  |           Tab(text: 'postArticle'.tr()), | ||||||
|  |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
| @@ -345,12 +349,14 @@ class PublisherProfileScreen extends HookConsumerWidget { | |||||||
|                           child: CustomScrollView( |                           child: CustomScrollView( | ||||||
|                             slivers: [ |                             slivers: [ | ||||||
|                               SliverGap(16), |                               SliverGap(16), | ||||||
|  |                               SliverPostList(pubName: name, pinned: true), | ||||||
|                               SliverToBoxAdapter( |                               SliverToBoxAdapter( | ||||||
|                                 child: publisherCategoryTabWidget(), |                                 child: publisherCategoryTabWidget(), | ||||||
|                               ), |                               ), | ||||||
|                               SliverPostList( |                               SliverPostList( | ||||||
|                                 key: ValueKey(categoryTab.value), |                                 key: ValueKey(categoryTab.value), | ||||||
|                                 pubName: name, |                                 pubName: name, | ||||||
|  |                                 pinned: false, | ||||||
|                                 type: switch (categoryTab.value) { |                                 type: switch (categoryTab.value) { | ||||||
|                                   1 => 0, |                                   1 => 0, | ||||||
|                                   2 => 1, |                                   2 => 1, | ||||||
| @@ -433,10 +439,12 @@ class PublisherProfileScreen extends HookConsumerWidget { | |||||||
|                           child: publisherVerificationWidget(data), |                           child: publisherVerificationWidget(data), | ||||||
|                         ), |                         ), | ||||||
|                         SliverToBoxAdapter(child: publisherBioWidget(data)), |                         SliverToBoxAdapter(child: publisherBioWidget(data)), | ||||||
|  |                         SliverPostList(pubName: name, pinned: true), | ||||||
|                         SliverToBoxAdapter(child: publisherCategoryTabWidget()), |                         SliverToBoxAdapter(child: publisherCategoryTabWidget()), | ||||||
|                         SliverPostList( |                         SliverPostList( | ||||||
|                           key: ValueKey(categoryTab.value), |                           key: ValueKey(categoryTab.value), | ||||||
|                           pubName: name, |                           pubName: name, | ||||||
|  |                           pinned: false, | ||||||
|                           type: switch (categoryTab.value) { |                           type: switch (categoryTab.value) { | ||||||
|                             1 => 0, |                             1 => 0, | ||||||
|                             2 => 1, |                             2 => 1, | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:island/models/chat.dart'; | import 'package:island/models/chat.dart'; | ||||||
| import 'package:island/services/color.dart'; | import 'package:island/services/color.dart'; | ||||||
| import 'package:island/services/responsive.dart'; | import 'package:island/services/responsive.dart'; | ||||||
|  | import 'package:island/widgets/account/account_pfc.dart'; | ||||||
| import 'package:island/widgets/account/status.dart'; | import 'package:island/widgets/account/status.dart'; | ||||||
| import 'package:island/widgets/post/post_list.dart'; | import 'package:island/widgets/post/post_list.dart'; | ||||||
| import 'package:palette_generator/palette_generator.dart'; | import 'package:palette_generator/palette_generator.dart'; | ||||||
| @@ -244,7 +245,10 @@ class RealmDetailScreen extends HookConsumerWidget { | |||||||
|                         Flexible( |                         Flexible( | ||||||
|                           flex: 3, |                           flex: 3, | ||||||
|                           child: CustomScrollView( |                           child: CustomScrollView( | ||||||
|                             slivers: [SliverPostList(realm: slug)], |                             slivers: [ | ||||||
|  |                               SliverPostList(realm: slug, pinned: true), | ||||||
|  |                               SliverPostList(realm: slug, pinned: false), | ||||||
|  |                             ], | ||||||
|                           ), |                           ), | ||||||
|                         ), |                         ), | ||||||
|                         Flexible( |                         Flexible( | ||||||
| @@ -359,7 +363,8 @@ class RealmDetailScreen extends HookConsumerWidget { | |||||||
|                         SliverToBoxAdapter( |                         SliverToBoxAdapter( | ||||||
|                           child: realmChatRoomListWidget(realm), |                           child: realmChatRoomListWidget(realm), | ||||||
|                         ), |                         ), | ||||||
|                         SliverPostList(realm: slug), |                         SliverPostList(realm: slug, pinned: true), | ||||||
|  |                         SliverPostList(realm: slug, pinned: false), | ||||||
|                       ], |                       ], | ||||||
|                     ), |                     ), | ||||||
|       ), |       ), | ||||||
| @@ -654,9 +659,12 @@ class _RealmMemberListSheet extends HookConsumerWidget { | |||||||
|                 final member = data.items[index]; |                 final member = data.items[index]; | ||||||
|                 return ListTile( |                 return ListTile( | ||||||
|                   contentPadding: EdgeInsets.only(left: 16, right: 12), |                   contentPadding: EdgeInsets.only(left: 16, right: 12), | ||||||
|                   leading: ProfilePictureWidget( |                   leading: AccountPfcGestureDetector( | ||||||
|  |                     uname: member.account!.name, | ||||||
|  |                     child: ProfilePictureWidget( | ||||||
|                       fileId: member.account!.profile.picture?.id, |                       fileId: member.account!.profile.picture?.id, | ||||||
|                     ), |                     ), | ||||||
|  |                   ), | ||||||
|                   title: Row( |                   title: Row( | ||||||
|                     spacing: 6, |                     spacing: 6, | ||||||
|                     children: [ |                     children: [ | ||||||
|   | |||||||
| @@ -42,6 +42,16 @@ class AccountName extends StatelessWidget { | |||||||
|           StellarMembershipMark(membership: account.perkSubscription!), |           StellarMembershipMark(membership: account.perkSubscription!), | ||||||
|         if (account.profile.verification != null) |         if (account.profile.verification != null) | ||||||
|           VerificationMark(mark: account.profile.verification!), |           VerificationMark(mark: account.profile.verification!), | ||||||
|  |         if (account.automatedId != null) | ||||||
|  |           Tooltip( | ||||||
|  |             message: 'accountAutomated'.tr(), | ||||||
|  |             child: Icon( | ||||||
|  |               Symbols.smart_toy, | ||||||
|  |               size: 16, | ||||||
|  |               color: nameStyle.color, | ||||||
|  |               fill: 1, | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -141,7 +151,7 @@ class VerificationStatusCard extends StatelessWidget { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Column( |     return Column( | ||||||
|       crossAxisAlignment: CrossAxisAlignment.start, |       crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|       children: [ |       children: [ | ||||||
|         Icon( |         Icon( | ||||||
|           mark.type == 4 |           mark.type == 4 | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| import 'dart:math' as math; | import 'dart:math' as math; | ||||||
|  |  | ||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:flutter_popup_card/flutter_popup_card.dart'; | import 'package:flutter_popup_card/flutter_popup_card.dart'; | ||||||
| @@ -74,7 +75,42 @@ class AccountProfileCard extends HookConsumerWidget { | |||||||
|                         uname: data.name, |                         uname: data.name, | ||||||
|                         padding: EdgeInsets.zero, |                         padding: EdgeInsets.zero, | ||||||
|                       ), |                       ), | ||||||
|                       if (data.profile.timeZone.isNotEmpty) |                       Tooltip( | ||||||
|  |                         message: 'creditsStatus'.tr(), | ||||||
|  |                         child: Row( | ||||||
|  |                           spacing: 6, | ||||||
|  |                           children: [ | ||||||
|  |                             Icon( | ||||||
|  |                               Symbols.star, | ||||||
|  |                               size: 17, | ||||||
|  |                               fill: 1, | ||||||
|  |                             ).padding(right: 2), | ||||||
|  |                             Text( | ||||||
|  |                               '${data.profile.socialCredits.toStringAsFixed(2)} pts', | ||||||
|  |                             ).fontSize(12), | ||||||
|  |                             switch (data.profile.socialCreditsLevel) { | ||||||
|  |                               -1 => Text('socialCreditsLevelPoor').tr(), | ||||||
|  |                               0 => Text('socialCreditsLevelNormal').tr(), | ||||||
|  |                               1 => Text('socialCreditsLevelGood').tr(), | ||||||
|  |                               2 => Text('socialCreditsLevelExcellent').tr(), | ||||||
|  |                               _ => Text('unknown').tr(), | ||||||
|  |                             }.fontSize(12), | ||||||
|  |                           ], | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       if (data.automatedId != null) | ||||||
|  |                         Row( | ||||||
|  |                           spacing: 6, | ||||||
|  |                           children: [ | ||||||
|  |                             Icon( | ||||||
|  |                               Symbols.smart_toy, | ||||||
|  |                               size: 17, | ||||||
|  |                               fill: 1, | ||||||
|  |                             ).padding(right: 2), | ||||||
|  |                             Text('accountAutomated').tr().fontSize(12), | ||||||
|  |                           ], | ||||||
|  |                         ), | ||||||
|  |                       if (data.profile.timeZone.isNotEmpty && !kIsWeb) | ||||||
|                         Row( |                         Row( | ||||||
|                           spacing: 6, |                           spacing: 6, | ||||||
|                           children: [ |                           children: [ | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ import 'package:easy_localization/easy_localization.dart'; | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/models/activity.dart'; | import 'package:island/models/activity.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| import 'package:island/widgets/account/event_details_widget.dart'; | import 'package:island/widgets/account/event_details_widget.dart'; | ||||||
| import 'package:table_calendar/table_calendar.dart'; | import 'package:table_calendar/table_calendar.dart'; | ||||||
| @@ -87,25 +89,57 @@ class EventCalendarWidget extends HookConsumerWidget { | |||||||
|               return Center(child: Text(text)); |               return Center(child: Text(text)); | ||||||
|             }, |             }, | ||||||
|             markerBuilder: (context, day, events) { |             markerBuilder: (context, day, events) { | ||||||
|               var checkInResult = |               final checkInResult = | ||||||
|                   events.whereType<SnCheckInResult>().firstOrNull; |                   events.whereType<SnCheckInResult>().firstOrNull; | ||||||
|  |               final statuses = events.whereType<SnAccountStatus>().toList(); | ||||||
|  |  | ||||||
|  |               final textColor = | ||||||
|  |                   isSameDay(selectedDay.value, day) | ||||||
|  |                       ? Colors.white | ||||||
|  |                       : isSameDay(DateTime.now(), day) | ||||||
|  |                       ? Colors.white | ||||||
|  |                       : Theme.of(context).colorScheme.onSurface; | ||||||
|  |  | ||||||
|  |               final shadow = | ||||||
|  |                   isSameDay(selectedDay.value, day) || | ||||||
|  |                           isSameDay(DateTime.now(), day) | ||||||
|  |                       ? [ | ||||||
|  |                         Shadow( | ||||||
|  |                           color: Colors.black.withOpacity(0.5), | ||||||
|  |                           offset: const Offset(0, 1), | ||||||
|  |                           blurRadius: 4, | ||||||
|  |                         ), | ||||||
|  |                       ] | ||||||
|  |                       : null; | ||||||
|  |  | ||||||
|               if (checkInResult != null) { |               if (checkInResult != null) { | ||||||
|                 return Positioned( |                 return Positioned( | ||||||
|                   top: 32, |                   top: 32, | ||||||
|                   child: Text( |                   child: Row( | ||||||
|  |                     spacing: 2, | ||||||
|  |                     children: [ | ||||||
|  |                       Text( | ||||||
|                         'checkInResultT${checkInResult.level}'.tr(), |                         'checkInResultT${checkInResult.level}'.tr(), | ||||||
|                         style: TextStyle( |                         style: TextStyle( | ||||||
|                           fontSize: 9, |                           fontSize: 9, | ||||||
|                       color: |                           color: textColor, | ||||||
|                           isSameDay(selectedDay.value, day) |                           shadows: shadow, | ||||||
|                               ? Theme.of(context).colorScheme.onPrimaryContainer |  | ||||||
|                               : isSameDay(DateTime.now(), day) |  | ||||||
|                               ? Theme.of( |  | ||||||
|                                 context, |  | ||||||
|                               ).colorScheme.onSecondaryContainer |  | ||||||
|                               : Theme.of(context).colorScheme.onSurface, |  | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|  |                       if (statuses.isNotEmpty) ...[ | ||||||
|  |                         Icon( | ||||||
|  |                           switch (statuses.first.attitude) { | ||||||
|  |                             0 => Symbols.sentiment_satisfied, | ||||||
|  |                             2 => Symbols.sentiment_dissatisfied, | ||||||
|  |                             _ => Symbols.sentiment_neutral, | ||||||
|  |                           }, | ||||||
|  |                           size: 12, | ||||||
|  |                           color: textColor, | ||||||
|  |                           shadows: shadow, | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|                 ); |                 ); | ||||||
|               } |               } | ||||||
|               return null; |               return null; | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:island/models/activity.dart'; | import 'package:island/models/activity.dart'; | ||||||
|  | import 'package:island/services/time.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
| @@ -53,6 +54,33 @@ class EventDetailsWidget extends StatelessWidget { | |||||||
|                     ), |                     ), | ||||||
|                   ], |                   ], | ||||||
|                 ).padding(top: 8), |                 ).padding(top: 8), | ||||||
|  |               if (event!.statuses.isNotEmpty) ...[ | ||||||
|  |                 const Gap(16), | ||||||
|  |                 Text('statusLabel').tr().fontSize(16).bold(), | ||||||
|  |               ], | ||||||
|  |               for (final status in event!.statuses) ...[ | ||||||
|  |                 Row( | ||||||
|  |                   spacing: 8, | ||||||
|  |                   children: [ | ||||||
|  |                     Icon(switch (status.attitude) { | ||||||
|  |                       0 => Symbols.sentiment_satisfied, | ||||||
|  |                       2 => Symbols.sentiment_dissatisfied, | ||||||
|  |                       _ => Symbols.sentiment_neutral, | ||||||
|  |                     }), | ||||||
|  |                     Expanded( | ||||||
|  |                       child: Column( | ||||||
|  |                         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                         children: [ | ||||||
|  |                           Text(status.label), | ||||||
|  |                           Text( | ||||||
|  |                             '${status.createdAt.formatSystem()} - ${status.clearedAt?.formatSystem() ?? 'present'.tr()}', | ||||||
|  |                           ).fontSize(11).opacity(0.8), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ).padding(vertical: 8), | ||||||
|  |               ], | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|         if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true)) |         if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true)) | ||||||
|   | |||||||
| @@ -1,9 +1,12 @@ | |||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
|  | import 'dart:io'; | ||||||
| import 'dart:math' as math; | import 'dart:math' as math; | ||||||
| import 'dart:ui'; | import 'dart:ui'; | ||||||
|  |  | ||||||
| import 'package:dismissible_page/dismissible_page.dart'; | import 'package:dismissible_page/dismissible_page.dart'; | ||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:file_saver/file_saver.dart'; | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
| import 'package:flutter_blurhash/flutter_blurhash.dart'; | import 'package:flutter_blurhash/flutter_blurhash.dart'; | ||||||
| @@ -321,7 +324,7 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|     Future<void> saveToGallery() async { |     Future<void> saveToGallery() async { | ||||||
|       try { |       try { | ||||||
|         // Show loading indicator |         // Show loading indicator | ||||||
|         showSnackBar('Saving image to gallery...'); |         showSnackBar('Saving image...'); | ||||||
|  |  | ||||||
|         // Get the image URL |         // Get the image URL | ||||||
|         final client = ref.watch(apiClientProvider); |         final client = ref.watch(apiClientProvider); | ||||||
| @@ -339,10 +342,18 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|           filePath, |           filePath, | ||||||
|           queryParameters: {'original': true}, |           queryParameters: {'original': true}, | ||||||
|         ); |         ); | ||||||
|  |         if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) { | ||||||
|  |           // Save to gallery | ||||||
|           await Gal.putImage(filePath, album: 'Solar Network'); |           await Gal.putImage(filePath, album: 'Solar Network'); | ||||||
|  |  | ||||||
|           // Show success message |           // Show success message | ||||||
|           showSnackBar('Image saved to gallery'); |           showSnackBar('Image saved to gallery'); | ||||||
|  |         } else { | ||||||
|  |           await FileSaver.instance.saveFile( | ||||||
|  |             name: item.name.isEmpty ? '${item.id}.$extName' : item.name, | ||||||
|  |             file: File(filePath), | ||||||
|  |           ); | ||||||
|  |           showSnackBar('Image saved to $filePath'); | ||||||
|  |         } | ||||||
|       } catch (e) { |       } catch (e) { | ||||||
|         showErrorAlert(e); |         showErrorAlert(e); | ||||||
|       } |       } | ||||||
| @@ -437,7 +448,24 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|                     ).padding(horizontal: 24, vertical: 16), |                     ).padding(horizontal: 24, vertical: 16), | ||||||
|                     const Divider(height: 1), |                     const Divider(height: 1), | ||||||
|                     ListTile( |                     ListTile( | ||||||
|                       leading: const Icon(Icons.file_present), |                       leading: const Icon(Symbols.tag), | ||||||
|  |                       title: Text('ID').tr(), | ||||||
|  |                       subtitle: Text( | ||||||
|  |                         item.id, | ||||||
|  |                         maxLines: 1, | ||||||
|  |                         overflow: TextOverflow.ellipsis, | ||||||
|  |                       ), | ||||||
|  |                       contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                       trailing: IconButton( | ||||||
|  |                         icon: const Icon(Icons.copy), | ||||||
|  |                         onPressed: () { | ||||||
|  |                           Clipboard.setData(ClipboardData(text: item.id)); | ||||||
|  |                           showSnackBar('File ID copied to clipboard'); | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     ListTile( | ||||||
|  |                       leading: const Icon(Symbols.file_present), | ||||||
|                       title: Text('Name').tr(), |                       title: Text('Name').tr(), | ||||||
|                       subtitle: Text( |                       subtitle: Text( | ||||||
|                         item.name, |                         item.name, | ||||||
| @@ -623,6 +651,10 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     final shadow = [ | ||||||
|  |       Shadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(1.0, 1.0)), | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|     return DismissiblePage( |     return DismissiblePage( | ||||||
|       isFullScreen: true, |       isFullScreen: true, | ||||||
|       backgroundColor: Colors.transparent, |       backgroundColor: Colors.transparent, | ||||||
| @@ -660,17 +692,12 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|               children: [ |               children: [ | ||||||
|                 Row( |                 Row( | ||||||
|                   children: [ |                   children: [ | ||||||
|  |                     if (!kIsWeb) | ||||||
|                       IconButton( |                       IconButton( | ||||||
|                         icon: Icon( |                         icon: Icon( | ||||||
|                           Icons.save_alt, |                           Icons.save_alt, | ||||||
|                           color: Colors.white, |                           color: Colors.white, | ||||||
|                         shadows: [ |                           shadows: shadow, | ||||||
|                           Shadow( |  | ||||||
|                             color: Colors.black54, |  | ||||||
|                             blurRadius: 5.0, |  | ||||||
|                             offset: Offset(1.0, 1.0), |  | ||||||
|                           ), |  | ||||||
|                         ], |  | ||||||
|                         ), |                         ), | ||||||
|                         onPressed: () async { |                         onPressed: () async { | ||||||
|                           saveToGallery(); |                           saveToGallery(); | ||||||
| @@ -683,29 +710,13 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|                       icon: Icon( |                       icon: Icon( | ||||||
|                         showOriginal.value ? Symbols.hd : Symbols.sd, |                         showOriginal.value ? Symbols.hd : Symbols.sd, | ||||||
|                         color: Colors.white, |                         color: Colors.white, | ||||||
|                         shadows: [ |                         shadows: shadow, | ||||||
|                           Shadow( |  | ||||||
|                             color: Colors.black54, |  | ||||||
|                             blurRadius: 5.0, |  | ||||||
|                             offset: Offset(1.0, 1.0), |  | ||||||
|                           ), |  | ||||||
|                         ], |  | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
|                 IconButton( |                 IconButton( | ||||||
|                   icon: Icon( |                   icon: Icon(Icons.close, color: Colors.white, shadows: shadow), | ||||||
|                     Icons.close, |  | ||||||
|                     color: Colors.white, |  | ||||||
|                     shadows: [ |  | ||||||
|                       Shadow( |  | ||||||
|                         color: Colors.black54, |  | ||||||
|                         blurRadius: 5.0, |  | ||||||
|                         offset: Offset(1.0, 1.0), |  | ||||||
|                       ), |  | ||||||
|                     ], |  | ||||||
|                   ), |  | ||||||
|                   onPressed: () => Navigator.of(context).pop(), |                   onPressed: () => Navigator.of(context).pop(), | ||||||
|                 ), |                 ), | ||||||
|               ], |               ], | ||||||
| @@ -722,26 +733,24 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|                   icon: Icon( |                   icon: Icon( | ||||||
|                     Icons.info_outline, |                     Icons.info_outline, | ||||||
|                     color: Colors.white, |                     color: Colors.white, | ||||||
|                     shadows: [ |                     shadows: shadow, | ||||||
|                       Shadow( |  | ||||||
|                         color: Colors.black54, |  | ||||||
|                         blurRadius: 5.0, |  | ||||||
|                         offset: Offset(1.0, 1.0), |  | ||||||
|                       ), |  | ||||||
|                     ], |  | ||||||
|                   ), |                   ), | ||||||
|                   onPressed: showInfoSheet, |                   onPressed: showInfoSheet, | ||||||
|                 ), |                 ), | ||||||
|                 Spacer(), |                 Spacer(), | ||||||
|                 IconButton( |                 IconButton( | ||||||
|                   icon: Icon(Icons.remove, color: Colors.white), |                   icon: Icon( | ||||||
|  |                     Icons.remove, | ||||||
|  |                     color: Colors.white, | ||||||
|  |                     shadows: shadow, | ||||||
|  |                   ), | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     photoViewController.scale = |                     photoViewController.scale = | ||||||
|                         (photoViewController.scale ?? 1) - 0.05; |                         (photoViewController.scale ?? 1) - 0.05; | ||||||
|                   }, |                   }, | ||||||
|                 ), |                 ), | ||||||
|                 IconButton( |                 IconButton( | ||||||
|                   icon: Icon(Icons.add, color: Colors.white), |                   icon: Icon(Icons.add, color: Colors.white, shadows: shadow), | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     photoViewController.scale = |                     photoViewController.scale = | ||||||
|                         (photoViewController.scale ?? 1) + 0.05; |                         (photoViewController.scale ?? 1) + 0.05; | ||||||
| @@ -752,13 +761,7 @@ class CloudFileZoomIn extends HookConsumerWidget { | |||||||
|                   icon: Icon( |                   icon: Icon( | ||||||
|                     Icons.rotate_left, |                     Icons.rotate_left, | ||||||
|                     color: Colors.white, |                     color: Colors.white, | ||||||
|                     shadows: [ |                     shadows: shadow, | ||||||
|                       Shadow( |  | ||||||
|                         color: Colors.black54, |  | ||||||
|                         blurRadius: 5.0, |  | ||||||
|                         offset: Offset(1.0, 1.0), |  | ||||||
|                       ), |  | ||||||
|                     ], |  | ||||||
|                   ), |                   ), | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     rotation.value = (rotation.value - 1) % 4; |                     rotation.value = (rotation.value - 1) % 4; | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ import 'package:island/screens/posts/compose.dart'; | |||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/content/markdown.dart'; | import 'package:island/widgets/content/markdown.dart'; | ||||||
| import 'package:island/widgets/post/post_item_screenshot.dart'; | import 'package:island/widgets/post/post_item_screenshot.dart'; | ||||||
|  | import 'package:island/widgets/post/post_pin_sheet.dart'; | ||||||
| import 'package:island/widgets/post/post_shared.dart'; | import 'package:island/widgets/post/post_shared.dart'; | ||||||
| import 'package:island/widgets/safety/abuse_report_helper.dart'; | import 'package:island/widgets/safety/abuse_report_helper.dart'; | ||||||
| import 'package:island/widgets/share/share_sheet.dart'; | import 'package:island/widgets/share/share_sheet.dart'; | ||||||
| @@ -202,6 +203,45 @@ class PostActionableItem extends HookConsumerWidget { | |||||||
|                 ); |                 ); | ||||||
|               }, |               }, | ||||||
|             ), |             ), | ||||||
|  |             if (isAuthor && item.pinMode == null) | ||||||
|  |               MenuAction( | ||||||
|  |                 title: 'pinPost'.tr(), | ||||||
|  |                 image: MenuImage.icon(Symbols.keep), | ||||||
|  |                 callback: () { | ||||||
|  |                   showModalBottomSheet( | ||||||
|  |                     context: context, | ||||||
|  |                     isScrollControlled: true, | ||||||
|  |                     builder: (context) => PostPinSheet(post: item), | ||||||
|  |                   ).then((value) { | ||||||
|  |                     if (value is int) { | ||||||
|  |                       onUpdate?.call(item.copyWith(pinMode: value)); | ||||||
|  |                     } | ||||||
|  |                   }); | ||||||
|  |                 }, | ||||||
|  |               ) | ||||||
|  |             else if (isAuthor && item.pinMode != null) | ||||||
|  |               MenuAction( | ||||||
|  |                 title: 'unpinPost'.tr(), | ||||||
|  |                 image: MenuImage.icon(Symbols.keep_off), | ||||||
|  |                 callback: () { | ||||||
|  |                   showConfirmAlert('unpinPostHint'.tr(), 'unpinPost'.tr()).then( | ||||||
|  |                     (confirm) async { | ||||||
|  |                       if (confirm) { | ||||||
|  |                         final client = ref.watch(apiClientProvider); | ||||||
|  |                         try { | ||||||
|  |                           if (context.mounted) showLoadingModal(context); | ||||||
|  |                           await client.delete('/sphere/posts/${item.id}/pin'); | ||||||
|  |                           onUpdate?.call(item.copyWith(pinMode: null)); | ||||||
|  |                         } catch (err) { | ||||||
|  |                           showErrorAlert(err); | ||||||
|  |                         } finally { | ||||||
|  |                           if (context.mounted) hideLoadingModal(context); | ||||||
|  |                         } | ||||||
|  |                       } | ||||||
|  |                     }, | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|             MenuSeparator(), |             MenuSeparator(), | ||||||
|             MenuAction( |             MenuAction( | ||||||
|               title: 'share'.tr(), |               title: 'share'.tr(), | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ class PostListNotifier extends _$PostListNotifier | |||||||
|     int? type, |     int? type, | ||||||
|     List<String>? categories, |     List<String>? categories, | ||||||
|     List<String>? tags, |     List<String>? tags, | ||||||
|  |     bool? pinned, | ||||||
|     bool shuffle = false, |     bool shuffle = false, | ||||||
|   }) { |   }) { | ||||||
|     return fetch(cursor: null); |     return fetch(cursor: null); | ||||||
| @@ -40,6 +41,7 @@ class PostListNotifier extends _$PostListNotifier | |||||||
|       if (tags != null) 'tags': tags, |       if (tags != null) 'tags': tags, | ||||||
|       if (categories != null) 'categories': categories, |       if (categories != null) 'categories': categories, | ||||||
|       if (shuffle) 'shuffle': true, |       if (shuffle) 'shuffle': true, | ||||||
|  |       if (pinned != null) 'pinned': pinned, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     final response = await client.get( |     final response = await client.get( | ||||||
| @@ -77,12 +79,14 @@ class SliverPostList extends HookConsumerWidget { | |||||||
|   final List<String>? categories; |   final List<String>? categories; | ||||||
|   final List<String>? tags; |   final List<String>? tags; | ||||||
|   final bool shuffle; |   final bool shuffle; | ||||||
|  |   final bool? pinned; | ||||||
|   final PostItemType itemType; |   final PostItemType itemType; | ||||||
|   final Color? backgroundColor; |   final Color? backgroundColor; | ||||||
|   final EdgeInsets? padding; |   final EdgeInsets? padding; | ||||||
|   final bool isOpenable; |   final bool isOpenable; | ||||||
|   final Function? onRefresh; |   final Function? onRefresh; | ||||||
|   final Function(SnPost)? onUpdate; |   final Function(SnPost)? onUpdate; | ||||||
|  |   final double? maxWidth; | ||||||
|  |  | ||||||
|   const SliverPostList({ |   const SliverPostList({ | ||||||
|     super.key, |     super.key, | ||||||
| @@ -92,43 +96,31 @@ class SliverPostList extends HookConsumerWidget { | |||||||
|     this.categories, |     this.categories, | ||||||
|     this.tags, |     this.tags, | ||||||
|     this.shuffle = false, |     this.shuffle = false, | ||||||
|  |     this.pinned, | ||||||
|     this.itemType = PostItemType.regular, |     this.itemType = PostItemType.regular, | ||||||
|     this.backgroundColor, |     this.backgroundColor, | ||||||
|     this.padding, |     this.padding, | ||||||
|     this.isOpenable = true, |     this.isOpenable = true, | ||||||
|     this.onRefresh, |     this.onRefresh, | ||||||
|     this.onUpdate, |     this.onUpdate, | ||||||
|  |     this.maxWidth, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final provider = postListNotifierProvider( | ||||||
|  |       pubName: pubName, | ||||||
|  |       realm: realm, | ||||||
|  |       type: type, | ||||||
|  |       categories: categories, | ||||||
|  |       tags: tags, | ||||||
|  |       shuffle: shuffle, | ||||||
|  |       pinned: pinned, | ||||||
|  |     ); | ||||||
|     return PagingHelperSliverView( |     return PagingHelperSliverView( | ||||||
|       provider: postListNotifierProvider( |       provider: provider, | ||||||
|         pubName: pubName, |       futureRefreshable: provider.future, | ||||||
|         realm: realm, |       notifierRefreshable: provider.notifier, | ||||||
|         type: type, |  | ||||||
|         categories: categories, |  | ||||||
|         tags: tags, |  | ||||||
|         shuffle: shuffle, |  | ||||||
|       ), |  | ||||||
|       futureRefreshable: |  | ||||||
|           postListNotifierProvider( |  | ||||||
|             pubName: pubName, |  | ||||||
|             realm: realm, |  | ||||||
|             type: type, |  | ||||||
|             categories: categories, |  | ||||||
|             tags: tags, |  | ||||||
|             shuffle: shuffle, |  | ||||||
|           ).future, |  | ||||||
|       notifierRefreshable: |  | ||||||
|           postListNotifierProvider( |  | ||||||
|             pubName: pubName, |  | ||||||
|             realm: realm, |  | ||||||
|             type: type, |  | ||||||
|             categories: categories, |  | ||||||
|             tags: tags, |  | ||||||
|             shuffle: shuffle, |  | ||||||
|           ).notifier, |  | ||||||
|       contentBuilder: |       contentBuilder: | ||||||
|           (data, widgetCount, endItemView) => SliverList.builder( |           (data, widgetCount, endItemView) => SliverList.builder( | ||||||
|             itemCount: widgetCount, |             itemCount: widgetCount, | ||||||
| @@ -139,6 +131,15 @@ class SliverPostList extends HookConsumerWidget { | |||||||
|  |  | ||||||
|               final post = data.items[index]; |               final post = data.items[index]; | ||||||
|  |  | ||||||
|  |               if (maxWidth != null) { | ||||||
|  |                 return Center( | ||||||
|  |                   child: ConstrainedBox( | ||||||
|  |                     constraints: BoxConstraints(maxWidth: maxWidth!), | ||||||
|  |                     child: _buildPostItem(post), | ||||||
|  |                   ), | ||||||
|  |                 ); | ||||||
|  |               } | ||||||
|  |  | ||||||
|               return _buildPostItem(post); |               return _buildPostItem(post); | ||||||
|             }, |             }, | ||||||
|           ), |           ), | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'post_list.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$postListNotifierHash() => r'faa0b939fae56367ff120ce63d9deb17b1995c9c'; | String _$postListNotifierHash() => r'3c0a8154ded4bcd8f5456f7a4ea2e542f57efa85'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
| @@ -36,6 +36,7 @@ abstract class _$PostListNotifier | |||||||
|   late final int? type; |   late final int? type; | ||||||
|   late final List<String>? categories; |   late final List<String>? categories; | ||||||
|   late final List<String>? tags; |   late final List<String>? tags; | ||||||
|  |   late final bool? pinned; | ||||||
|   late final bool shuffle; |   late final bool shuffle; | ||||||
|  |  | ||||||
|   FutureOr<CursorPagingData<SnPost>> build({ |   FutureOr<CursorPagingData<SnPost>> build({ | ||||||
| @@ -44,6 +45,7 @@ abstract class _$PostListNotifier | |||||||
|     int? type, |     int? type, | ||||||
|     List<String>? categories, |     List<String>? categories, | ||||||
|     List<String>? tags, |     List<String>? tags, | ||||||
|  |     bool? pinned, | ||||||
|     bool shuffle = false, |     bool shuffle = false, | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| @@ -65,6 +67,7 @@ class PostListNotifierFamily | |||||||
|     int? type, |     int? type, | ||||||
|     List<String>? categories, |     List<String>? categories, | ||||||
|     List<String>? tags, |     List<String>? tags, | ||||||
|  |     bool? pinned, | ||||||
|     bool shuffle = false, |     bool shuffle = false, | ||||||
|   }) { |   }) { | ||||||
|     return PostListNotifierProvider( |     return PostListNotifierProvider( | ||||||
| @@ -73,6 +76,7 @@ class PostListNotifierFamily | |||||||
|       type: type, |       type: type, | ||||||
|       categories: categories, |       categories: categories, | ||||||
|       tags: tags, |       tags: tags, | ||||||
|  |       pinned: pinned, | ||||||
|       shuffle: shuffle, |       shuffle: shuffle, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -87,6 +91,7 @@ class PostListNotifierFamily | |||||||
|       type: provider.type, |       type: provider.type, | ||||||
|       categories: provider.categories, |       categories: provider.categories, | ||||||
|       tags: provider.tags, |       tags: provider.tags, | ||||||
|  |       pinned: provider.pinned, | ||||||
|       shuffle: provider.shuffle, |       shuffle: provider.shuffle, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -120,6 +125,7 @@ class PostListNotifierProvider | |||||||
|     int? type, |     int? type, | ||||||
|     List<String>? categories, |     List<String>? categories, | ||||||
|     List<String>? tags, |     List<String>? tags, | ||||||
|  |     bool? pinned, | ||||||
|     bool shuffle = false, |     bool shuffle = false, | ||||||
|   }) : this._internal( |   }) : this._internal( | ||||||
|          () => |          () => | ||||||
| @@ -129,6 +135,7 @@ class PostListNotifierProvider | |||||||
|                ..type = type |                ..type = type | ||||||
|                ..categories = categories |                ..categories = categories | ||||||
|                ..tags = tags |                ..tags = tags | ||||||
|  |                ..pinned = pinned | ||||||
|                ..shuffle = shuffle, |                ..shuffle = shuffle, | ||||||
|          from: postListNotifierProvider, |          from: postListNotifierProvider, | ||||||
|          name: r'postListNotifierProvider', |          name: r'postListNotifierProvider', | ||||||
| @@ -144,6 +151,7 @@ class PostListNotifierProvider | |||||||
|          type: type, |          type: type, | ||||||
|          categories: categories, |          categories: categories, | ||||||
|          tags: tags, |          tags: tags, | ||||||
|  |          pinned: pinned, | ||||||
|          shuffle: shuffle, |          shuffle: shuffle, | ||||||
|        ); |        ); | ||||||
|  |  | ||||||
| @@ -159,6 +167,7 @@ class PostListNotifierProvider | |||||||
|     required this.type, |     required this.type, | ||||||
|     required this.categories, |     required this.categories, | ||||||
|     required this.tags, |     required this.tags, | ||||||
|  |     required this.pinned, | ||||||
|     required this.shuffle, |     required this.shuffle, | ||||||
|   }) : super.internal(); |   }) : super.internal(); | ||||||
|  |  | ||||||
| @@ -167,6 +176,7 @@ class PostListNotifierProvider | |||||||
|   final int? type; |   final int? type; | ||||||
|   final List<String>? categories; |   final List<String>? categories; | ||||||
|   final List<String>? tags; |   final List<String>? tags; | ||||||
|  |   final bool? pinned; | ||||||
|   final bool shuffle; |   final bool shuffle; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -179,6 +189,7 @@ class PostListNotifierProvider | |||||||
|       type: type, |       type: type, | ||||||
|       categories: categories, |       categories: categories, | ||||||
|       tags: tags, |       tags: tags, | ||||||
|  |       pinned: pinned, | ||||||
|       shuffle: shuffle, |       shuffle: shuffle, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -195,6 +206,7 @@ class PostListNotifierProvider | |||||||
|               ..type = type |               ..type = type | ||||||
|               ..categories = categories |               ..categories = categories | ||||||
|               ..tags = tags |               ..tags = tags | ||||||
|  |               ..pinned = pinned | ||||||
|               ..shuffle = shuffle, |               ..shuffle = shuffle, | ||||||
|         from: from, |         from: from, | ||||||
|         name: null, |         name: null, | ||||||
| @@ -206,6 +218,7 @@ class PostListNotifierProvider | |||||||
|         type: type, |         type: type, | ||||||
|         categories: categories, |         categories: categories, | ||||||
|         tags: tags, |         tags: tags, | ||||||
|  |         pinned: pinned, | ||||||
|         shuffle: shuffle, |         shuffle: shuffle, | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
| @@ -228,6 +241,7 @@ class PostListNotifierProvider | |||||||
|         other.type == type && |         other.type == type && | ||||||
|         other.categories == categories && |         other.categories == categories && | ||||||
|         other.tags == tags && |         other.tags == tags && | ||||||
|  |         other.pinned == pinned && | ||||||
|         other.shuffle == shuffle; |         other.shuffle == shuffle; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -239,6 +253,7 @@ class PostListNotifierProvider | |||||||
|     hash = _SystemHash.combine(hash, type.hashCode); |     hash = _SystemHash.combine(hash, type.hashCode); | ||||||
|     hash = _SystemHash.combine(hash, categories.hashCode); |     hash = _SystemHash.combine(hash, categories.hashCode); | ||||||
|     hash = _SystemHash.combine(hash, tags.hashCode); |     hash = _SystemHash.combine(hash, tags.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, pinned.hashCode); | ||||||
|     hash = _SystemHash.combine(hash, shuffle.hashCode); |     hash = _SystemHash.combine(hash, shuffle.hashCode); | ||||||
|  |  | ||||||
|     return _SystemHash.finish(hash); |     return _SystemHash.finish(hash); | ||||||
| @@ -264,6 +279,9 @@ mixin PostListNotifierRef | |||||||
|   /// The parameter `tags` of this provider. |   /// The parameter `tags` of this provider. | ||||||
|   List<String>? get tags; |   List<String>? get tags; | ||||||
|  |  | ||||||
|  |   /// The parameter `pinned` of this provider. | ||||||
|  |   bool? get pinned; | ||||||
|  |  | ||||||
|   /// The parameter `shuffle` of this provider. |   /// The parameter `shuffle` of this provider. | ||||||
|   bool get shuffle; |   bool get shuffle; | ||||||
| } | } | ||||||
| @@ -289,6 +307,8 @@ class _PostListNotifierProviderElement | |||||||
|   @override |   @override | ||||||
|   List<String>? get tags => (origin as PostListNotifierProvider).tags; |   List<String>? get tags => (origin as PostListNotifierProvider).tags; | ||||||
|   @override |   @override | ||||||
|  |   bool? get pinned => (origin as PostListNotifierProvider).pinned; | ||||||
|  |   @override | ||||||
|   bool get shuffle => (origin as PostListNotifierProvider).shuffle; |   bool get shuffle => (origin as PostListNotifierProvider).shuffle; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										124
									
								
								lib/widgets/post/post_pin_sheet.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								lib/widgets/post/post_pin_sheet.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/post.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
|  | import 'package:island/widgets/content/sheet.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | class PostPinSheet extends HookConsumerWidget { | ||||||
|  |   final SnPost post; | ||||||
|  |   const PostPinSheet({super.key, required this.post}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final mode = useState(0); | ||||||
|  |  | ||||||
|  |     Future<void> pinPost() async { | ||||||
|  |       try { | ||||||
|  |         showLoadingModal(context); | ||||||
|  |         final client = ref.watch(apiClientProvider); | ||||||
|  |         await client.post( | ||||||
|  |           '/sphere/posts/${post.id}/pin', | ||||||
|  |           data: {'mode': mode.value}, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if (context.mounted) Navigator.of(context).pop(mode.value); | ||||||
|  |       } catch (e) { | ||||||
|  |         showErrorAlert(e); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return SheetScaffold( | ||||||
|  |       titleText: 'pinPost'.tr(), | ||||||
|  |       heightFactor: 0.6, | ||||||
|  |       child: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |         children: [ | ||||||
|  |           // Publisher page pin option (always available) | ||||||
|  |           ListTile( | ||||||
|  |             leading: Radio<int>( | ||||||
|  |               value: 0, | ||||||
|  |               groupValue: mode.value, | ||||||
|  |               onChanged: (value) { | ||||||
|  |                 mode.value = value!; | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |             title: Text('publisherPage'.tr()), | ||||||
|  |             subtitle: Text('pinPostPublisherHint'.tr()), | ||||||
|  |             onTap: () { | ||||||
|  |               mode.value = 0; | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |  | ||||||
|  |           // Realm page pin option (show always, but disabled when not available) | ||||||
|  |           ListTile( | ||||||
|  |             leading: Radio<int>( | ||||||
|  |               value: 1, | ||||||
|  |               groupValue: mode.value, | ||||||
|  |               onChanged: | ||||||
|  |                   post.realmId != null && post.realmId!.isNotEmpty | ||||||
|  |                       ? (value) { | ||||||
|  |                         mode.value = value!; | ||||||
|  |                       } | ||||||
|  |                       : null, | ||||||
|  |             ), | ||||||
|  |             title: Text('realmPage'.tr()), | ||||||
|  |             subtitle: | ||||||
|  |                 post.realmId != null && post.realmId!.isNotEmpty | ||||||
|  |                     ? Text('pinPostRealmHint'.tr()) | ||||||
|  |                     : Text('pinPostRealmDisabledHint'.tr()), | ||||||
|  |             onTap: | ||||||
|  |                 post.realmId != null && post.realmId!.isNotEmpty | ||||||
|  |                     ? () { | ||||||
|  |                       mode.value = 1; | ||||||
|  |                     } | ||||||
|  |                     : null, | ||||||
|  |             enabled: post.realmId != null && post.realmId!.isNotEmpty, | ||||||
|  |           ), | ||||||
|  |  | ||||||
|  |           // Reply page pin option (show always, but disabled when not available) | ||||||
|  |           // Disabled for now because im being lazy | ||||||
|  |           // ListTile( | ||||||
|  |           //   leading: Radio<int>( | ||||||
|  |           //     value: 2, | ||||||
|  |           //     groupValue: mode.value, | ||||||
|  |           //     onChanged: | ||||||
|  |           //         post.repliedPostId != null && post.repliedPostId!.isNotEmpty | ||||||
|  |           //             ? (value) { | ||||||
|  |           //               mode.value = value!; | ||||||
|  |           //             } | ||||||
|  |           //             : null, | ||||||
|  |           //   ), | ||||||
|  |           //   title: Text('replyPage'.tr()), | ||||||
|  |           //   subtitle: | ||||||
|  |           //       post.repliedPostId != null && post.repliedPostId!.isNotEmpty | ||||||
|  |           //           ? Text('pinPostReplyHint'.tr()) | ||||||
|  |           //           : Text('pinPostReplyDisabledHint'.tr()), | ||||||
|  |           //   onTap: | ||||||
|  |           //       post.repliedPostId != null && post.repliedPostId!.isNotEmpty | ||||||
|  |           //           ? () { | ||||||
|  |           //             mode.value = 2; | ||||||
|  |           //           } | ||||||
|  |           //           : null, | ||||||
|  |           //   enabled: | ||||||
|  |           //       post.repliedPostId != null && post.repliedPostId!.isNotEmpty, | ||||||
|  |           // ), | ||||||
|  |           const SizedBox(height: 16), | ||||||
|  |  | ||||||
|  |           // Pin button | ||||||
|  |           FilledButton.icon( | ||||||
|  |             onPressed: pinPost, | ||||||
|  |             icon: const Icon(Symbols.keep), | ||||||
|  |             label: Text('pin'.tr()), | ||||||
|  |           ).padding(horizontal: 24), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -545,7 +545,17 @@ class PostHeader extends StatelessWidget { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Row( |     return Column( | ||||||
|  |       children: [ | ||||||
|  |         if (item.pinMode != null) | ||||||
|  |           Row( | ||||||
|  |             spacing: 4, | ||||||
|  |             children: [ | ||||||
|  |               const Icon(Symbols.keep, size: 15, fill: 1), | ||||||
|  |               Text('pinnedPost').tr().fontSize(13), | ||||||
|  |             ], | ||||||
|  |           ).opacity(0.8).padding(horizontal: 8, bottom: 4), | ||||||
|  |         Row( | ||||||
|           crossAxisAlignment: CrossAxisAlignment.center, |           crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|           spacing: 12, |           spacing: 12, | ||||||
|           children: [ |           children: [ | ||||||
| @@ -619,10 +629,10 @@ class PostHeader extends StatelessWidget { | |||||||
|                     children: [ |                     children: [ | ||||||
|                       Text( |                       Text( | ||||||
|                         !isFullPost && isRelativeTime |                         !isFullPost && isRelativeTime | ||||||
|                         ? (item.publishedAt ?? item.createdAt)!.formatRelative( |                             ? (item.publishedAt ?? item.createdAt)! | ||||||
|                           context, |                                 .formatRelative(context) | ||||||
|                         ) |                             : (item.publishedAt ?? item.createdAt)! | ||||||
|                         : (item.publishedAt ?? item.createdAt)!.formatSystem(), |                                 .formatSystem(), | ||||||
|                       ).fontSize(10), |                       ).fontSize(10), | ||||||
|                       if (item.editedAt != null) |                       if (item.editedAt != null) | ||||||
|                         Text( |                         Text( | ||||||
| @@ -647,6 +657,8 @@ class PostHeader extends StatelessWidget { | |||||||
|             ), |             ), | ||||||
|             if (trailing != null) trailing!, |             if (trailing != null) trailing!, | ||||||
|           ], |           ], | ||||||
|  |         ), | ||||||
|  |       ], | ||||||
|     ).padding(horizontal: renderingPadding.horizontal, bottom: 4); |     ).padding(horizontal: renderingPadding.horizontal, bottom: 4); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| #include "generated_plugin_registrant.h" | #include "generated_plugin_registrant.h" | ||||||
|  |  | ||||||
| #include <bitsdojo_window_linux/bitsdojo_window_plugin.h> | #include <bitsdojo_window_linux/bitsdojo_window_plugin.h> | ||||||
|  | #include <file_saver/file_saver_plugin.h> | ||||||
| #include <file_selector_linux/file_selector_plugin.h> | #include <file_selector_linux/file_selector_plugin.h> | ||||||
| #include <flutter_platform_alert/flutter_platform_alert_plugin.h> | #include <flutter_platform_alert/flutter_platform_alert_plugin.h> | ||||||
| #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> | #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> | ||||||
| @@ -28,6 +29,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { | |||||||
|   g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = |   g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = | ||||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); |       fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); | ||||||
|   bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); |   bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); | ||||||
|  |   g_autoptr(FlPluginRegistrar) file_saver_registrar = | ||||||
|  |       fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin"); | ||||||
|  |   file_saver_plugin_register_with_registrar(file_saver_registrar); | ||||||
|   g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = |   g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = | ||||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); |       fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); | ||||||
|   file_selector_plugin_register_with_registrar(file_selector_linux_registrar); |   file_selector_plugin_register_with_registrar(file_selector_linux_registrar); | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
|  |  | ||||||
| list(APPEND FLUTTER_PLUGIN_LIST | list(APPEND FLUTTER_PLUGIN_LIST | ||||||
|   bitsdojo_window_linux |   bitsdojo_window_linux | ||||||
|  |   file_saver | ||||||
|   file_selector_linux |   file_selector_linux | ||||||
|   flutter_platform_alert |   flutter_platform_alert | ||||||
|   flutter_secure_storage_linux |   flutter_secure_storage_linux | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import bitsdojo_window_macos | |||||||
| import connectivity_plus | import connectivity_plus | ||||||
| import device_info_plus | import device_info_plus | ||||||
| import file_picker | import file_picker | ||||||
|  | import file_saver | ||||||
| import file_selector_macos | import file_selector_macos | ||||||
| import firebase_analytics | import firebase_analytics | ||||||
| import firebase_core | import firebase_core | ||||||
| @@ -45,6 +46,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | |||||||
|   ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) |   ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) | ||||||
|   DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) |   DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) | ||||||
|   FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) |   FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) | ||||||
|  |   FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin")) | ||||||
|   FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) |   FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) | ||||||
|   FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin")) |   FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin")) | ||||||
|   FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) |   FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) | ||||||
|   | |||||||
| @@ -9,6 +9,8 @@ PODS: | |||||||
|     - FlutterMacOS |     - FlutterMacOS | ||||||
|   - file_picker (0.0.1): |   - file_picker (0.0.1): | ||||||
|     - FlutterMacOS |     - FlutterMacOS | ||||||
|  |   - file_saver (0.0.1): | ||||||
|  |     - FlutterMacOS | ||||||
|   - file_selector_macos (0.0.1): |   - file_selector_macos (0.0.1): | ||||||
|     - FlutterMacOS |     - FlutterMacOS | ||||||
|   - Firebase/CoreOnly (12.0.0): |   - Firebase/CoreOnly (12.0.0): | ||||||
| @@ -249,6 +251,7 @@ DEPENDENCIES: | |||||||
|   - croppy (from `Flutter/ephemeral/.symlinks/plugins/croppy/macos`) |   - croppy (from `Flutter/ephemeral/.symlinks/plugins/croppy/macos`) | ||||||
|   - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) |   - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) | ||||||
|   - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) |   - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) | ||||||
|  |   - file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`) | ||||||
|   - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) |   - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) | ||||||
|   - firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`) |   - firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`) | ||||||
|   - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) |   - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) | ||||||
| @@ -315,6 +318,8 @@ EXTERNAL SOURCES: | |||||||
|     :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos |     :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos | ||||||
|   file_picker: |   file_picker: | ||||||
|     :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos |     :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos | ||||||
|  |   file_saver: | ||||||
|  |     :path: Flutter/ephemeral/.symlinks/plugins/file_saver/macos | ||||||
|   file_selector_macos: |   file_selector_macos: | ||||||
|     :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos |     :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos | ||||||
|   firebase_analytics: |   firebase_analytics: | ||||||
| @@ -384,6 +389,7 @@ SPEC CHECKSUMS: | |||||||
|   croppy: d9bfc8c02f3cd1851f669a421df298a474b78f43 |   croppy: d9bfc8c02f3cd1851f669a421df298a474b78f43 | ||||||
|   device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 |   device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 | ||||||
|   file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a |   file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a | ||||||
|  |   file_saver: e35bd97de451dde55ff8c38862ed7ad0f3418d0f | ||||||
|   file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 |   file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 | ||||||
|   Firebase: 800d487043c0557d9faed71477a38d9aafb08a41 |   Firebase: 800d487043c0557d9faed71477a38d9aafb08a41 | ||||||
|   firebase_analytics: 53f0dc87ad10f56a6df8746da60d8a5fe41f886f |   firebase_analytics: 53f0dc87ad10f56a6df8746da60d8a5fe41f886f | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -569,6 +569,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "10.3.2" |     version: "10.3.2" | ||||||
|  |   file_saver: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: file_saver | ||||||
|  |       sha256: "9d93db09bd4da9e43238f9dd485360fc51a5c138eea5ef5f407ec56e58079ac0" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.3.1" | ||||||
|   file_selector_linux: |   file_selector_linux: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -1921,10 +1929,10 @@ packages: | |||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: record_ios |       name: record_ios | ||||||
|       sha256: "895c9467faec72d8e718a3142b51114958f42f18053836a8b484a74f9372f51a" |       sha256: "13e241ed9cbc220534a40ae6b66222e21288db364d96dd66fb762ebd3cb77c71" | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.1.1" |     version: "1.1.2" | ||||||
|   record_linux: |   record_linux: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -2041,10 +2049,10 @@ packages: | |||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: screen_brightness_android |       name: screen_brightness_android | ||||||
|       sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed |       sha256: d34f5321abd03bc3474f4c381f53d189117eba0b039eac1916aa92cca5fd0a96 | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "2.1.2" |     version: "2.1.3" | ||||||
|   screen_brightness_platform_interface: |   screen_brightness_platform_interface: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -2640,10 +2648,10 @@ packages: | |||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: watcher |       name: watcher | ||||||
|       sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" |       sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c" | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.1.2" |     version: "1.1.3" | ||||||
|   waveform_flutter: |   waveform_flutter: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|  |  | ||||||
| #include <bitsdojo_window_windows/bitsdojo_window_plugin.h> | #include <bitsdojo_window_windows/bitsdojo_window_plugin.h> | ||||||
| #include <connectivity_plus/connectivity_plus_windows_plugin.h> | #include <connectivity_plus/connectivity_plus_windows_plugin.h> | ||||||
|  | #include <file_saver/file_saver_plugin.h> | ||||||
| #include <file_selector_windows/file_selector_windows.h> | #include <file_selector_windows/file_selector_windows.h> | ||||||
| #include <firebase_core/firebase_core_plugin_c_api.h> | #include <firebase_core/firebase_core_plugin_c_api.h> | ||||||
| #include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> | #include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> | ||||||
| @@ -35,6 +36,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { | |||||||
|       registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); |       registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); | ||||||
|   ConnectivityPlusWindowsPluginRegisterWithRegistrar( |   ConnectivityPlusWindowsPluginRegisterWithRegistrar( | ||||||
|       registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); |       registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); | ||||||
|  |   FileSaverPluginRegisterWithRegistrar( | ||||||
|  |       registry->GetRegistrarForPlugin("FileSaverPlugin")); | ||||||
|   FileSelectorWindowsRegisterWithRegistrar( |   FileSelectorWindowsRegisterWithRegistrar( | ||||||
|       registry->GetRegistrarForPlugin("FileSelectorWindows")); |       registry->GetRegistrarForPlugin("FileSelectorWindows")); | ||||||
|   FirebaseCorePluginCApiRegisterWithRegistrar( |   FirebaseCorePluginCApiRegisterWithRegistrar( | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| list(APPEND FLUTTER_PLUGIN_LIST | list(APPEND FLUTTER_PLUGIN_LIST | ||||||
|   bitsdojo_window_windows |   bitsdojo_window_windows | ||||||
|   connectivity_plus |   connectivity_plus | ||||||
|  |   file_saver | ||||||
|   file_selector_windows |   file_selector_windows | ||||||
|   firebase_core |   firebase_core | ||||||
|   flutter_inappwebview_windows |   flutter_inappwebview_windows | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user