Compare commits

..

5 Commits

Author SHA1 Message Date
LittleSheep
461f32545a 💄 Optimized profile page background image 2025-06-11 00:20:21 +08:00
LittleSheep
36b9026e9e Verification mark 2025-06-11 00:09:19 +08:00
LittleSheep
78f258dcea 🎨 Fix some warnings in the code 2025-06-10 23:29:32 +08:00
LittleSheep
044fb983d6 Chat break and notify level 2025-06-10 01:09:28 +08:00
LittleSheep
2a7876e22f 🐛 Optimized typing indicator 2025-06-09 23:50:19 +08:00
26 changed files with 780 additions and 134 deletions

View File

@@ -282,6 +282,7 @@
"one": "{} unread message",
"other": "{} unread messages"
},
"chatBreakNone": "None",
"settingsRealmCompactView": "Compact Realm View",
"settingsMixedFeed": "Mixed Feed",
"settingsAutoTranslate": "Auto Translate",
@@ -396,5 +397,20 @@
"contactMethodPrimary": "Primary",
"contactMethodSetPrimary": "Set as Primary",
"contactMethodSetPrimaryHint": "Set this contact method as your primary contact method for account recovery and notifications",
"contactMethodDeleteHint": "Are you sure to delete this contact method? This action cannot be undone."
"contactMethodDeleteHint": "Are you sure to delete this contact method? This action cannot be undone.",
"chatNotifyLevel": "Notify Level",
"chatNotifyLevelDescription": "Decide how many notifications you will receive.",
"chatNotifyLevelAll": "All",
"chatNotifyLevelMention": "Mentions",
"chatNotifyLevelNone": "None",
"chatNotifyLevelUpdated": "The notify level has been updated to {}.",
"chatBreak": "Take a Break",
"chatBreakDescription": "Set a time, before that time, your notification level will be metions only, to take a break of the current topic they're talking about.",
"chatBreakClear": "Clear the break time",
"chatBreakHour": "{} break",
"chatBreakDay": "{} day break",
"chatBreakSet": "Break set for {}",
"chatBreakCleared": "Chat break has been cleared.",
"chatBreakCustom": "Custom duration",
"chatBreakEnterMinutes": "Enter minutes"
}

View File

@@ -291,5 +291,21 @@
"postVisibilityPublic": "公开",
"postVisibilityFriends": "仅好友可见",
"postVisibilityUnlisted": "不公开",
"postVisibilityPrivate": "私密"
"postVisibilityPrivate": "私密",
"chatNotifyLevel": "通知级别",
"chatNotifyLevelDescription": "决定您将收到多少通知。",
"chatNotifyLevelAll": "全部",
"chatNotifyLevelMention": "提及",
"chatNotifyLevelNone": "无",
"chatNotifyLevelUpdated": "通知级别已更新为 {}。",
"chatBreak": "暂停聊天",
"chatBreakDescription": "设置一个时间,在该时间之前,您的通知级别将仅为提及,以暂时休息当前讨论的话题。",
"chatBreakClear": "清除暂停时间",
"chatBreakHour": "暂停 {} 分钟",
"chatBreakDay": "暂停 {} 天",
"chatBreakSet": "已设置暂停 {}",
"chatBreakCleared": "聊天暂停已清除。",
"chatBreakCustom": "自定义时长",
"chatBreakEnterMinutes": "输入分钟数",
"chatBreakNone": "无"
}

View File

@@ -68,7 +68,7 @@
"createRealmHint": "結識志同道合的朋友、建立社群等等。",
"editRealm": "編輯領域",
"deleteRealm": "刪除領域",
"deleteRealmHint": "確定要刪除此領域嗎?這也將刪除領域下的所有頻道、發佈者和貼文。",
"deleteRealmHint": "確定要刪除此領域嗎?這也將刪除領域下的所有頻道、發佈者和貼文。",
"explore": "探索",
"account": "帳號",
"name": "名稱",
@@ -291,5 +291,21 @@
"postVisibilityPublic": "公開",
"postVisibilityFriends": "僅好友可見",
"postVisibilityUnlisted": "不公開",
"postVisibilityPrivate": "私密"
"postVisibilityPrivate": "私密",
"chatNotifyLevel": "通知等級",
"chatNotifyLevelDescription": "決定您將收到多少通知。",
"chatNotifyLevelAll": "全部",
"chatNotifyLevelMention": "提及",
"chatNotifyLevelNone": "無",
"chatNotifyLevelUpdated": "通知等級已更新為 {}。",
"chatBreak": "暫停聊天",
"chatBreakDescription": "設定一個時間,在該時間之前,您的通知等級將僅為提及,以暫時休息當前討論的話題。",
"chatBreakClear": "清除暫停時間",
"chatBreakHour": "暫停 {} 分鐘",
"chatBreakDay": "暫停 {} 天",
"chatBreakSet": "已設定暫停 {}",
"chatBreakCleared": "聊天暫停已清除。",
"chatBreakCustom": "自訂時長",
"chatBreakEnterMinutes": "輸入分鐘數",
"chatBreakNone": "無"
}

View File

@@ -1,6 +1,3 @@
import 'dart:convert';
import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:island/database/drift_db.dart';
import 'package:island/database/message.dart';
@@ -48,13 +45,6 @@ class MessageRepository {
},
);
for (final item in resp.data['changes']) {
if (item['message']['sender']['account'] == null)
log(jsonEncode(item['message']['sender']['account']));
// if (item['message'] != null &&
// item['message']['sender']['account'] == null) {
// }
}
final response = MessageSyncResponse.fromJson(resp.data);
for (final change in response.changes) {
switch (change.action) {

View File

@@ -1,6 +1,3 @@
import 'dart:convert';
import 'dart:developer';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart';
import 'package:island/models/realm.dart';
@@ -90,7 +87,10 @@ sealed class SnChatMember with _$SnChatMember {
required int role,
required int notify,
required DateTime? joinedAt,
required DateTime? breakUntil,
required DateTime? timeoutUntil,
required bool isBot,
// Frontend data
DateTime? lastTyped,
}) = _SnChatMember;

View File

@@ -663,7 +663,8 @@ $SnChatMemberCopyWith<$Res> get sender {
/// @nodoc
mixin _$SnChatMember {
DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; bool get isBot; DateTime? get lastTyped;
DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; DateTime? get breakUntil; DateTime? get timeoutUntil; bool get isBot;// Frontend data
DateTime? get lastTyped;
/// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -676,16 +677,16 @@ $SnChatMemberCopyWith<SnChatMember> get copyWith => _$SnChatMemberCopyWithImpl<S
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,isBot,lastTyped);
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped);
@override
String toString() {
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, isBot: $isBot, lastTyped: $lastTyped)';
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)';
}
@@ -696,7 +697,7 @@ abstract mixin class $SnChatMemberCopyWith<$Res> {
factory $SnChatMemberCopyWith(SnChatMember value, $Res Function(SnChatMember) _then) = _$SnChatMemberCopyWithImpl;
@useResult
$Res call({
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, bool isBot, DateTime? lastTyped
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped
});
@@ -713,7 +714,7 @@ class _$SnChatMemberCopyWithImpl<$Res>
/// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? isBot = null,Object? lastTyped = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) {
return _then(_self.copyWith(
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
@@ -727,6 +728,8 @@ as SnAccount,nick: freezed == nick ? _self.nick : nick // ignore: cast_nullable_
as String?,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable
as int,notify: null == notify ? _self.notify : notify // ignore: cast_nullable_to_non_nullable
as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable
as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable
as DateTime?,
@@ -761,7 +764,7 @@ $SnAccountCopyWith<$Res> get account {
@JsonSerializable()
class _SnChatMember implements SnChatMember {
const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.isBot, this.lastTyped});
const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.breakUntil, required this.timeoutUntil, required this.isBot, this.lastTyped});
factory _SnChatMember.fromJson(Map<String, dynamic> json) => _$SnChatMemberFromJson(json);
@override final DateTime createdAt;
@@ -776,7 +779,10 @@ class _SnChatMember implements SnChatMember {
@override final int role;
@override final int notify;
@override final DateTime? joinedAt;
@override final DateTime? breakUntil;
@override final DateTime? timeoutUntil;
@override final bool isBot;
// Frontend data
@override final DateTime? lastTyped;
/// Create a copy of SnChatMember
@@ -792,16 +798,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,isBot,lastTyped);
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped);
@override
String toString() {
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, isBot: $isBot, lastTyped: $lastTyped)';
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)';
}
@@ -812,7 +818,7 @@ abstract mixin class _$SnChatMemberCopyWith<$Res> implements $SnChatMemberCopyWi
factory _$SnChatMemberCopyWith(_SnChatMember value, $Res Function(_SnChatMember) _then) = __$SnChatMemberCopyWithImpl;
@override @useResult
$Res call({
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, bool isBot, DateTime? lastTyped
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped
});
@@ -829,7 +835,7 @@ class __$SnChatMemberCopyWithImpl<$Res>
/// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? isBot = null,Object? lastTyped = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) {
return _then(_SnChatMember(
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
@@ -843,6 +849,8 @@ as SnAccount,nick: freezed == nick ? _self.nick : nick // ignore: cast_nullable_
as String?,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable
as int,notify: null == notify ? _self.notify : notify // ignore: cast_nullable_to_non_nullable
as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable
as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable
as DateTime?,

View File

@@ -166,6 +166,14 @@ _SnChatMember _$SnChatMemberFromJson(Map<String, dynamic> json) =>
json['joined_at'] == null
? null
: DateTime.parse(json['joined_at'] as String),
breakUntil:
json['break_until'] == null
? null
: DateTime.parse(json['break_until'] as String),
timeoutUntil:
json['timeout_until'] == null
? null
: DateTime.parse(json['timeout_until'] as String),
isBot: json['is_bot'] as bool,
lastTyped:
json['last_typed'] == null
@@ -187,6 +195,8 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) =>
'role': instance.role,
'notify': instance.notify,
'joined_at': instance.joinedAt?.toIso8601String(),
'break_until': instance.breakUntil?.toIso8601String(),
'timeout_until': instance.timeoutUntil?.toIso8601String(),
'is_bot': instance.isBot,
'last_typed': instance.lastTyped?.toIso8601String(),
};

View File

@@ -59,6 +59,7 @@ sealed class SnPublisher with _$SnPublisher {
required DateTime updatedAt,
required DateTime? deletedAt,
required String? realmId,
required SnVerificationMark? verification,
}) = _SnPublisher;
factory SnPublisher.fromJson(Map<String, dynamic> json) =>

View File

@@ -370,7 +370,7 @@ $SnPublisherCopyWith<$Res> get publisher {
/// @nodoc
mixin _$SnPublisher {
String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get realmId;
String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get realmId; SnVerificationMark? get verification;
/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -383,16 +383,16 @@ $SnPublisherCopyWith<SnPublisher> get copyWith => _$SnPublisherCopyWithImpl<SnPu
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId));
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId);
int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification);
@override
String toString() {
return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId)';
return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)';
}
@@ -403,11 +403,11 @@ abstract mixin class $SnPublisherCopyWith<$Res> {
factory $SnPublisherCopyWith(SnPublisher value, $Res Function(SnPublisher) _then) = _$SnPublisherCopyWithImpl;
@useResult
$Res call({
String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId
String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification
});
$SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnAccountCopyWith<$Res>? get account;
$SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnAccountCopyWith<$Res>? get account;$SnVerificationMarkCopyWith<$Res>? get verification;
}
/// @nodoc
@@ -420,7 +420,7 @@ class _$SnPublisherCopyWithImpl<$Res>
/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
@@ -435,7 +435,8 @@ as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore:
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
as String?,
as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable
as SnVerificationMark?,
));
}
/// Create a copy of SnPublisher
@@ -474,6 +475,18 @@ $SnAccountCopyWith<$Res>? get account {
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value));
});
}/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnVerificationMarkCopyWith<$Res>? get verification {
if (_self.verification == null) {
return null;
}
return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) {
return _then(_self.copyWith(verification: value));
});
}
}
@@ -482,7 +495,7 @@ $SnAccountCopyWith<$Res>? get account {
@JsonSerializable()
class _SnPublisher implements SnPublisher {
const _SnPublisher({required this.id, required this.type, required this.name, required this.nick, this.bio = '', required this.picture, required this.background, required this.account, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.realmId});
const _SnPublisher({required this.id, required this.type, required this.name, required this.nick, this.bio = '', required this.picture, required this.background, required this.account, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.realmId, required this.verification});
factory _SnPublisher.fromJson(Map<String, dynamic> json) => _$SnPublisherFromJson(json);
@override final String id;
@@ -498,6 +511,7 @@ class _SnPublisher implements SnPublisher {
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
@override final String? realmId;
@override final SnVerificationMark? verification;
/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@@ -512,16 +526,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId);
int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification);
@override
String toString() {
return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId)';
return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)';
}
@@ -532,11 +546,11 @@ abstract mixin class _$SnPublisherCopyWith<$Res> implements $SnPublisherCopyWith
factory _$SnPublisherCopyWith(_SnPublisher value, $Res Function(_SnPublisher) _then) = __$SnPublisherCopyWithImpl;
@override @useResult
$Res call({
String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId
String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification
});
@override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnAccountCopyWith<$Res>? get account;
@override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnAccountCopyWith<$Res>? get account;@override $SnVerificationMarkCopyWith<$Res>? get verification;
}
/// @nodoc
@@ -549,7 +563,7 @@ class __$SnPublisherCopyWithImpl<$Res>
/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) {
return _then(_SnPublisher(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
@@ -564,7 +578,8 @@ as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore:
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
as String?,
as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable
as SnVerificationMark?,
));
}
@@ -604,6 +619,18 @@ $SnAccountCopyWith<$Res>? get account {
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value));
});
}/// Create a copy of SnPublisher
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnVerificationMarkCopyWith<$Res>? get verification {
if (_self.verification == null) {
return null;
}
return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) {
return _then(_self.copyWith(verification: value));
});
}
}

View File

@@ -120,6 +120,12 @@ _SnPublisher _$SnPublisherFromJson(Map<String, dynamic> json) => _SnPublisher(
? null
: DateTime.parse(json['deleted_at'] as String),
realmId: json['realm_id'] as String?,
verification:
json['verification'] == null
? null
: SnVerificationMark.fromJson(
json['verification'] as Map<String, dynamic>,
),
);
Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
@@ -137,6 +143,7 @@ Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'realm_id': instance.realmId,
'verification': instance.verification?.toJson(),
};
_SnPublisherStats _$SnPublisherStatsFromJson(Map<String, dynamic> json) =>

View File

@@ -36,6 +36,7 @@ sealed class SnAccountProfile with _$SnAccountProfile {
required double levelingProgress,
required SnCloudFile? picture,
required SnCloudFile? background,
required SnVerificationMark? verification,
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
@@ -123,3 +124,16 @@ sealed class SnNotification with _$SnNotification {
factory SnNotification.fromJson(Map<String, dynamic> json) =>
_$SnNotificationFromJson(json);
}
@freezed
sealed class SnVerificationMark with _$SnVerificationMark {
const factory SnVerificationMark({
required int type,
required String? title,
required String? description,
required String? verifiedBy,
}) = _SnVerificationMark;
factory SnVerificationMark.fromJson(Map<String, dynamic> json) =>
_$SnVerificationMarkFromJson(json);
}

View File

@@ -200,7 +200,7 @@ $SnAccountProfileCopyWith<$Res> get profile {
/// @nodoc
mixin _$SnAccountProfile {
String get id; String? get firstName; String? get middleName; String? get lastName; String get bio; int get experience; int get level; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
String get id; String? get firstName; String? get middleName; String? get lastName; String get bio; 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;
/// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -213,16 +213,16 @@ $SnAccountProfileCopyWith<SnAccountProfile> get copyWith => _$SnAccountProfileCo
@override
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.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.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.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));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,experience,level,levelingProgress,picture,background,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
@@ -233,11 +233,11 @@ abstract mixin class $SnAccountProfileCopyWith<$Res> {
factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl;
@useResult
$Res call({
String id, String? firstName, String? middleName, String? lastName, String bio, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String? firstName, String? middleName, String? lastName, String bio, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
$SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;
$SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnVerificationMarkCopyWith<$Res>? get verification;
}
/// @nodoc
@@ -250,7 +250,7 @@ class _$SnAccountProfileCopyWithImpl<$Res>
/// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = null,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = null,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,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
@@ -262,7 +262,8 @@ as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_no
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 SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable
as SnVerificationMark?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
@@ -292,6 +293,18 @@ $SnCloudFileCopyWith<$Res>? get background {
return $SnCloudFileCopyWith<$Res>(_self.background!, (value) {
return _then(_self.copyWith(background: value));
});
}/// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnVerificationMarkCopyWith<$Res>? get verification {
if (_self.verification == null) {
return null;
}
return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) {
return _then(_self.copyWith(verification: value));
});
}
}
@@ -300,7 +313,7 @@ $SnCloudFileCopyWith<$Res>? get background {
@JsonSerializable()
class _SnAccountProfile implements SnAccountProfile {
const _SnAccountProfile({required this.id, required this.firstName, required this.middleName, required this.lastName, this.bio = '', required this.experience, required this.level, required this.levelingProgress, required this.picture, required this.background, required this.createdAt, required this.updatedAt, required this.deletedAt});
const _SnAccountProfile({required this.id, required this.firstName, required this.middleName, required this.lastName, this.bio = '', 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});
factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json);
@override final String id;
@@ -313,6 +326,7 @@ class _SnAccountProfile implements SnAccountProfile {
@override final double levelingProgress;
@override final SnCloudFile? picture;
@override final SnCloudFile? background;
@override final SnVerificationMark? verification;
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
@@ -330,16 +344,16 @@ Map<String, dynamic> toJson() {
@override
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.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.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.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));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,experience,level,levelingProgress,picture,background,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
@@ -350,11 +364,11 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> implements $SnAccountProfi
factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl;
@override @useResult
$Res call({
String id, String? firstName, String? middleName, String? lastName, String bio, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String? firstName, String? middleName, String? lastName, String bio, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
@override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;
@override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnVerificationMarkCopyWith<$Res>? get verification;
}
/// @nodoc
@@ -367,7 +381,7 @@ class __$SnAccountProfileCopyWithImpl<$Res>
/// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = null,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = null,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,}) {
return _then(_SnAccountProfile(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
@@ -379,7 +393,8 @@ as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_no
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 SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable
as SnVerificationMark?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
@@ -410,6 +425,18 @@ $SnCloudFileCopyWith<$Res>? get background {
return $SnCloudFileCopyWith<$Res>(_self.background!, (value) {
return _then(_self.copyWith(background: value));
});
}/// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnVerificationMarkCopyWith<$Res>? get verification {
if (_self.verification == null) {
return null;
}
return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) {
return _then(_self.copyWith(verification: value));
});
}
}
@@ -1072,6 +1099,148 @@ as String,
}
}
/// @nodoc
mixin _$SnVerificationMark {
int get type; String? get title; String? get description; String? get verifiedBy;
/// Create a copy of SnVerificationMark
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnVerificationMarkCopyWith<SnVerificationMark> get copyWith => _$SnVerificationMarkCopyWithImpl<SnVerificationMark>(this as SnVerificationMark, _$identity);
/// Serializes this SnVerificationMark to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnVerificationMark&&(identical(other.type, type) || other.type == type)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.verifiedBy, verifiedBy) || other.verifiedBy == verifiedBy));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,title,description,verifiedBy);
@override
String toString() {
return 'SnVerificationMark(type: $type, title: $title, description: $description, verifiedBy: $verifiedBy)';
}
}
/// @nodoc
abstract mixin class $SnVerificationMarkCopyWith<$Res> {
factory $SnVerificationMarkCopyWith(SnVerificationMark value, $Res Function(SnVerificationMark) _then) = _$SnVerificationMarkCopyWithImpl;
@useResult
$Res call({
int type, String? title, String? description, String? verifiedBy
});
}
/// @nodoc
class _$SnVerificationMarkCopyWithImpl<$Res>
implements $SnVerificationMarkCopyWith<$Res> {
_$SnVerificationMarkCopyWithImpl(this._self, this._then);
final SnVerificationMark _self;
final $Res Function(SnVerificationMark) _then;
/// Create a copy of SnVerificationMark
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? title = freezed,Object? description = freezed,Object? verifiedBy = freezed,}) {
return _then(_self.copyWith(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as int,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,verifiedBy: freezed == verifiedBy ? _self.verifiedBy : verifiedBy // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
/// @nodoc
@JsonSerializable()
class _SnVerificationMark implements SnVerificationMark {
const _SnVerificationMark({required this.type, required this.title, required this.description, required this.verifiedBy});
factory _SnVerificationMark.fromJson(Map<String, dynamic> json) => _$SnVerificationMarkFromJson(json);
@override final int type;
@override final String? title;
@override final String? description;
@override final String? verifiedBy;
/// Create a copy of SnVerificationMark
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnVerificationMarkCopyWith<_SnVerificationMark> get copyWith => __$SnVerificationMarkCopyWithImpl<_SnVerificationMark>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnVerificationMarkToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnVerificationMark&&(identical(other.type, type) || other.type == type)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.verifiedBy, verifiedBy) || other.verifiedBy == verifiedBy));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,title,description,verifiedBy);
@override
String toString() {
return 'SnVerificationMark(type: $type, title: $title, description: $description, verifiedBy: $verifiedBy)';
}
}
/// @nodoc
abstract mixin class _$SnVerificationMarkCopyWith<$Res> implements $SnVerificationMarkCopyWith<$Res> {
factory _$SnVerificationMarkCopyWith(_SnVerificationMark value, $Res Function(_SnVerificationMark) _then) = __$SnVerificationMarkCopyWithImpl;
@override @useResult
$Res call({
int type, String? title, String? description, String? verifiedBy
});
}
/// @nodoc
class __$SnVerificationMarkCopyWithImpl<$Res>
implements _$SnVerificationMarkCopyWith<$Res> {
__$SnVerificationMarkCopyWithImpl(this._self, this._then);
final _SnVerificationMark _self;
final $Res Function(_SnVerificationMark) _then;
/// Create a copy of SnVerificationMark
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? title = freezed,Object? description = freezed,Object? verifiedBy = freezed,}) {
return _then(_SnVerificationMark(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as int,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,verifiedBy: freezed == verifiedBy ? _self.verifiedBy : verifiedBy // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
// dart format on

View File

@@ -60,6 +60,12 @@ _SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) =>
: SnCloudFile.fromJson(
json['background'] as Map<String, dynamic>,
),
verification:
json['verification'] == null
? null
: SnVerificationMark.fromJson(
json['verification'] as Map<String, dynamic>,
),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
@@ -80,6 +86,7 @@ Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) =>
'leveling_progress': instance.levelingProgress,
'picture': instance.picture?.toJson(),
'background': instance.background?.toJson(),
'verification': instance.verification?.toJson(),
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
@@ -226,3 +233,19 @@ Map<String, dynamic> _$SnNotificationToJson(_SnNotification instance) =>
'viewed_at': instance.viewedAt?.toIso8601String(),
'account_id': instance.accountId,
};
_SnVerificationMark _$SnVerificationMarkFromJson(Map<String, dynamic> json) =>
_SnVerificationMark(
type: (json['type'] as num).toInt(),
title: json['title'] as String?,
description: json['description'] as String?,
verifiedBy: json['verified_by'] as String?,
);
Map<String, dynamic> _$SnVerificationMarkToJson(_SnVerificationMark instance) =>
<String, dynamic>{
'type': instance.type,
'title': instance.title,
'description': instance.description,
'verified_by': instance.verifiedBy,
};

View File

@@ -11,6 +11,7 @@ import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart';
import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/account/leveling_progress.dart';
import 'package:island/widgets/app_scaffold.dart';
@@ -83,7 +84,7 @@ class AccountScreen extends HookConsumerWidget {
child: AspectRatio(
aspectRatio: 16 / 7,
child: CloudImageWidget(
fileId: user.value!.profile.background!.id,
file: user.value?.profile.background,
fit: BoxFit.cover,
),
),
@@ -94,7 +95,7 @@ class AccountScreen extends HookConsumerWidget {
children: [
GestureDetector(
child: ProfilePictureWidget(
fileId: user.value?.profile.picture?.id,
file: user.value?.profile.picture,
radius: 24,
),
onTap: () {
@@ -112,7 +113,13 @@ class AccountScreen extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(user.value!.nick).bold().fontSize(16),
AccountName(
account: user.value!,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text('@${user.value!.name}'),
],
),

View File

@@ -86,7 +86,7 @@ class AccountSettingsScreen extends HookConsumerWidget {
).push(MaterialPageRoute(builder: (context) => CaptchaScreen()));
if (captchaTk == null) return;
try {
showLoadingModal(context);
if (context.mounted) showLoadingModal(context);
final userInfo = ref.read(userInfoProvider);
final client = ref.read(apiClientProvider);
await client.post(

View File

@@ -65,23 +65,32 @@ class AccountProfileScreen extends HookConsumerWidget {
expandedHeight: 180,
pinned: true,
leading: PageBackButton(shadows: [iconShadow]),
flexibleSpace: FlexibleSpaceBar(
background:
data.profile.background?.id != null
? CloudImageWidget(
fileId: data.profile.background!.id,
)
: Container(
color:
Theme.of(context).appBarTheme.backgroundColor,
),
title: Text(
data.nick,
style: TextStyle(
color: Theme.of(context).appBarTheme.foregroundColor,
shadows: [iconShadow],
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
Theme.of(context).appBarTheme.foregroundColor,
shadows: [iconShadow],
),
),
),
],
),
),
SliverToBoxAdapter(
@@ -91,7 +100,7 @@ class AccountProfileScreen extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ProfilePictureWidget(
fileId: data.profile.picture?.id,
file: data.profile.picture,
radius: 32,
),
const Gap(20),

View File

@@ -337,7 +337,7 @@ class ChatRoomScreen extends HookConsumerWidget {
),
);
typingDebouncer.value = Timer(const Duration(milliseconds: 1000), () {
typingDebouncer.value = Timer(const Duration(milliseconds: 850), () {
typingDebouncer.value = null;
});
}
@@ -384,9 +384,11 @@ class ChatRoomScreen extends HookConsumerWidget {
if (!pkt.type.startsWith('messages')) return;
if (['messages.read'].contains(pkt.type)) return;
if (pkt.type == 'messages.typing') {
if (pkt.type == 'messages.typing' && pkt.data?['sender'] != null) {
if (pkt.data?['sender_id'] == chatIdentity.value?.id) return;
final sender = SnChatMember.fromJson(
pkt.data!['sender'],
pkt.data?['sender'],
).copyWith(lastTyped: DateTime.now());
// Check if the sender is already in the typing list
@@ -733,7 +735,7 @@ class ChatRoomScreen extends HookConsumerWidget {
mainAxisSize: MainAxisSize.min,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
duration: const Duration(milliseconds: 150),
switchInCurve: Curves.fastEaseInToSlowEaseOut,
switchOutCurve: Curves.fastEaseInToSlowEaseOut,
transitionBuilder: (
@@ -800,7 +802,7 @@ class ChatRoomScreen extends HookConsumerWidget {
),
)
: const SizedBox.shrink(
key: ValueKey('no_typing'),
key: ValueKey('typing-indicator-none'),
),
),
_ChatInput(

View File

@@ -14,7 +14,7 @@ import 'package:island/widgets/account/account_picker.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/content/paging_helper_ext.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
@@ -31,6 +31,206 @@ class ChatDetailScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final roomState = ref.watch(chatroomProvider(id));
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
const kNotifyLevelText = [
'chatNotifyLevelAll',
'chatNotifyLevelMention',
'chatNotifyLevelNone',
];
void setNotifyLevel(int level) async {
try {
final client = ref.watch(apiClientProvider);
await client.patch(
'/chat/$id/members/me/notify',
data: {'notify_level': level},
);
ref.invalidate(chatroomIdentityProvider(id));
if (context.mounted) {
showSnackBar(
context,
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
);
}
} catch (err) {
showErrorAlert(err);
}
}
void setChatBreak(DateTime until) async {
try {
final client = ref.watch(apiClientProvider);
await client.patch(
'/chat/$id/members/me/notify',
data: {'break_until': until.toUtc().toIso8601String()},
);
ref.invalidate(chatroomProvider(id));
} catch (err) {
showErrorAlert(err);
}
}
void showNotifyLevelBottomSheet(SnChatMember identity) {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder:
(context) => SheetScaffold(
height: 320,
titleText: 'chatNotifyLevel'.tr(),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: const Text('chatNotifyLevelAll').tr(),
subtitle: const Text('chatNotifyLevelDescription').tr(),
leading: const Icon(Icons.notifications_active),
selected: identity.notify == 0,
onTap: () {
setNotifyLevel(0);
Navigator.pop(context);
},
),
ListTile(
title: const Text('chatNotifyLevelMention').tr(),
subtitle: const Text('chatNotifyLevelDescription').tr(),
leading: const Icon(Icons.alternate_email),
selected: identity.notify == 1,
onTap: () {
setNotifyLevel(1);
Navigator.pop(context);
},
),
ListTile(
title: const Text('chatNotifyLevelNone').tr(),
subtitle: const Text('chatNotifyLevelDescription').tr(),
leading: const Icon(Icons.notifications_off),
selected: identity.notify == 2,
onTap: () {
setNotifyLevel(2);
Navigator.pop(context);
},
),
],
),
),
);
}
void showChatBreakDialog() {
final now = DateTime.now();
final durationController = TextEditingController();
showDialog(
context: context,
builder:
(context) => AlertDialog(
title: const Text('chatBreak').tr(),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('chatBreakDescription').tr(),
const Gap(16),
ListTile(
title: const Text('Clear').tr(),
subtitle: const Text('chatBreakClear').tr(),
leading: const Icon(Icons.notifications_active),
onTap: () {
setChatBreak(now);
Navigator.pop(context);
if (context.mounted) {
showSnackBar(context, 'chatBreakCleared'.tr());
}
},
),
ListTile(
title: const Text('5m'),
subtitle: const Text('chatBreakHour').tr(args: ['5m']),
leading: const Icon(Symbols.circle),
onTap: () {
setChatBreak(now.add(const Duration(minutes: 5)));
Navigator.pop(context);
if (context.mounted) {
showSnackBar(context, 'chatBreakSet'.tr(args: ['5m']));
}
},
),
ListTile(
title: const Text('10m'),
subtitle: const Text('chatBreakHour').tr(args: ['10m']),
leading: const Icon(Symbols.circle),
onTap: () {
setChatBreak(now.add(const Duration(minutes: 10)));
Navigator.pop(context);
if (context.mounted) {
showSnackBar(context, 'chatBreakSet'.tr(args: ['10m']));
}
},
),
ListTile(
title: const Text('15m'),
subtitle: const Text('chatBreakHour').tr(args: ['15m']),
leading: const Icon(Symbols.timer_3),
onTap: () {
setChatBreak(now.add(const Duration(minutes: 15)));
Navigator.pop(context);
if (context.mounted) {
showSnackBar(context, 'chatBreakSet'.tr(args: ['15m']));
}
},
),
ListTile(
title: const Text('30m'),
subtitle: const Text('chatBreakHour').tr(args: ['30m']),
leading: const Icon(Symbols.timer),
onTap: () {
setChatBreak(now.add(const Duration(minutes: 30)));
Navigator.pop(context);
if (context.mounted) {
showSnackBar(context, 'chatBreakSet'.tr(args: ['30m']));
}
},
),
const Gap(8),
TextField(
controller: durationController,
decoration: InputDecoration(
labelText: 'Custom (minutes)'.tr(),
hintText: 'Enter minutes'.tr(),
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: const Icon(Icons.check),
onPressed: () {
final minutes = int.tryParse(durationController.text);
if (minutes != null && minutes > 0) {
setChatBreak(now.add(Duration(minutes: minutes)));
Navigator.pop(context);
if (context.mounted) {
showSnackBar(
context,
'chatBreakSet'.tr(args: ['${minutes}m']),
);
}
}
},
),
),
keyboardType: TextInputType.number,
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('cancel').tr(),
),
],
),
);
}
const iconShadow = Shadow(
color: Colors.black54,
@@ -114,17 +314,59 @@ class ChatDetailScreen extends HookConsumerWidget {
],
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
currentRoom.description ?? 'descriptionNone'.tr(),
style: const TextStyle(fontSize: 16),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
currentRoom.description ?? 'descriptionNone'.tr(),
style: const TextStyle(fontSize: 16),
).padding(all: 24),
const Divider(height: 1),
roomIdentity.when(
data:
(identity) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
contentPadding: EdgeInsets.symmetric(
horizontal: 24,
),
leading: const Icon(Symbols.notifications),
trailing: const Icon(Symbols.chevron_right),
title: const Text('chatNotifyLevel').tr(),
subtitle: Text(
kNotifyLevelText[identity!.notify].tr(),
),
onTap:
() =>
showNotifyLevelBottomSheet(identity),
),
ListTile(
contentPadding: EdgeInsets.symmetric(
horizontal: 24,
),
leading: const Icon(Icons.timer),
trailing: const Icon(Symbols.chevron_right),
title: const Text('chatBreak').tr(),
subtitle:
identity.breakUntil != null &&
identity.breakUntil!.isAfter(
DateTime.now(),
)
? Text(
DateFormat(
'yyyy-MM-dd HH:mm',
).format(identity.breakUntil!),
)
: const Text('chatBreakNone').tr(),
onTap: () => showChatBreakDialog(),
),
],
),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
],
),
),
],

View File

@@ -7,7 +7,6 @@ import 'package:island/models/activity.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/models/post.dart';
import 'package:island/widgets/check_in.dart';

View File

@@ -7,7 +7,7 @@ part of 'explore.dart';
// **************************************************************************
String _$activityListNotifierHash() =>
r'1baf0bb961bc02bfc8a5b5f515981072c6ce1750';
r'2ca8fe14686d7f4fb09ab26f2978eb2de7184565';
/// See also [ActivityListNotifier].
@ProviderFor(ActivityListNotifier)

View File

@@ -106,21 +106,32 @@ class PublisherProfileScreen extends HookConsumerWidget {
expandedHeight: 180,
pinned: true,
leading: PageBackButton(shadows: [iconShadow]),
flexibleSpace: FlexibleSpaceBar(
background:
data.background?.id != null
? CloudImageWidget(fileId: data.background!.id)
: Container(
color:
Theme.of(context).appBarTheme.backgroundColor,
),
title: Text(
data.nick,
style: TextStyle(
color: Theme.of(context).appBarTheme.foregroundColor,
shadows: [iconShadow],
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.background?.id != null
? CloudImageWidget(file: data.background)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
Theme.of(context).appBarTheme.foregroundColor,
shadows: [iconShadow],
),
),
background:
Container(), // Empty container since background is handled by Stack
),
],
),
actions: [
subStatus.when(
@@ -163,10 +174,7 @@ class PublisherProfileScreen extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20,
children: [
ProfilePictureWidget(
fileId: data.picture!.id,
radius: 32,
),
ProfilePictureWidget(file: data.picture, radius: 32),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@@ -0,0 +1,63 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:island/models/user.dart';
import 'package:material_symbols_icons/symbols.dart';
const kVerificationMarkColors = [
Colors.teal,
Colors.blue,
Colors.amber,
Colors.blueGrey,
Colors.lightBlue,
];
class AccountName extends StatelessWidget {
final SnAccount account;
final TextStyle? style;
const AccountName({super.key, required this.account, this.style});
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
spacing: 4,
children: [
Flexible(child: Text(account.nick, style: style)),
if (account.profile.verification != null)
VerificationMark(mark: account.profile.verification!),
],
);
}
}
class VerificationMark extends StatelessWidget {
final SnVerificationMark mark;
const VerificationMark({super.key, required this.mark});
@override
Widget build(BuildContext context) {
return Tooltip(
richMessage: TextSpan(
text: mark.title ?? 'No title',
children: [
TextSpan(text: '\n'),
TextSpan(
text: mark.description ?? 'descriptionNone'.tr(),
style: TextStyle(fontWeight: FontWeight.normal),
),
],
style: TextStyle(fontWeight: FontWeight.bold),
),
child: Icon(
mark.type == 4
? Symbols.play_circle
: mark.type == 0
? Symbols.build_circle
: Symbols.verified,
size: 16,
color: kVerificationMarkColors[mark.type],
fill: 1,
),
);
}
}

View File

@@ -1,15 +1,11 @@
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activity.dart';
import 'package:island/models/user.dart';
import 'package:island/pods/network.dart';
import 'package:island/widgets/account/status_creation.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:relative_time/relative_time.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart';

View File

@@ -54,13 +54,15 @@ class CloudFileWidget extends ConsumerWidget {
}
class CloudImageWidget extends ConsumerWidget {
final String fileId;
final String? fileId;
final SnCloudFile? file;
final BoxFit fit;
final double aspectRatio;
final String? blurHash;
const CloudImageWidget({
super.key,
required this.fileId,
this.fileId,
this.file,
this.aspectRatio = 1,
this.fit = BoxFit.cover,
this.blurHash,
@@ -68,11 +70,17 @@ class CloudImageWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
assert(fileId != null || file != null);
final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/files/$fileId';
final uri = '$serverUrl/files/${file?.id ?? fileId}';
return AspectRatio(
aspectRatio: aspectRatio,
child: UniversalImage(uri: uri, blurHash: blurHash),
child:
file != null
? CloudFileWidget(item: file!, fit: fit)
: UniversalImage(uri: uri, blurHash: blurHash, fit: fit),
);
}
@@ -88,12 +96,14 @@ class CloudImageWidget extends ConsumerWidget {
class ProfilePictureWidget extends ConsumerWidget {
final String? fileId;
final SnCloudFile? file;
final double radius;
final IconData? fallbackIcon;
final Color? fallbackColor;
const ProfilePictureWidget({
super.key,
required this.fileId,
this.fileId,
this.file,
this.radius = 20,
this.fallbackIcon,
this.fallbackColor,
@@ -101,8 +111,10 @@ class ProfilePictureWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
assert(fileId != null || file != null);
final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/files/$fileId';
final uri = '$serverUrl/files/${file?.id ?? fileId}';
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(radius)),
@@ -119,6 +131,8 @@ class ProfilePictureWidget extends ConsumerWidget {
fallbackColor ??
Theme.of(context).colorScheme.onPrimaryContainer,
).center()
: file != null
? CloudFileWidget(item: file!, fit: BoxFit.cover)
: UniversalImage(uri: uri, fit: BoxFit.cover),
),
);

View File

@@ -7,6 +7,7 @@ class SheetScaffold extends StatelessWidget {
final List<Widget> actions;
final Widget child;
final double heightFactor;
final double? height;
const SheetScaffold({
super.key,
this.title,
@@ -14,6 +15,7 @@ class SheetScaffold extends StatelessWidget {
required this.child,
this.actions = const [],
this.heightFactor = 0.8,
this.height,
});
@override
@@ -32,7 +34,7 @@ class SheetScaffold extends StatelessWidget {
return Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * heightFactor,
maxHeight: height ?? MediaQuery.of(context).size.height * heightFactor,
),
child: Column(
children: [

View File

@@ -11,6 +11,7 @@ import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_file_collection.dart';
@@ -133,9 +134,7 @@ class PostItem extends HookConsumerWidget {
spacing: 12,
children: [
GestureDetector(
child: ProfilePictureWidget(
fileId: item.publisher.picture?.id,
),
child: ProfilePictureWidget(file: item.publisher.picture),
onTap: () {
context.router.push(
PublisherProfileRoute(name: item.publisher.name),
@@ -147,7 +146,15 @@ class PostItem extends HookConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(item.publisher.nick).bold(),
Row(
children: [
Text(item.publisher.nick).bold(),
if (item.publisher.verification != null)
VerificationMark(
mark: item.publisher.verification!,
).padding(left: 4),
],
),
// Add visibility indicator if not public (visibility != 0)
if (item.visibility != 0)
Row(