🚚 Update files layout of pods

This commit is contained in:
2025-12-06 17:31:12 +08:00
parent 91da9768c1
commit 240509ceff
48 changed files with 2534 additions and 2778 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -12,18 +12,16 @@ _SnAbuseReport _$SnAbuseReportFromJson(Map<String, dynamic> json) =>
resourceIdentifier: json['resource_identifier'] as String, resourceIdentifier: json['resource_identifier'] as String,
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
reason: json['reason'] as String, reason: json['reason'] as String,
resolvedAt: resolvedAt: json['resolved_at'] == null
json['resolved_at'] == null ? null
? null : DateTime.parse(json['resolved_at'] as String),
: DateTime.parse(json['resolved_at'] as String),
resolution: json['resolution'] as String?, resolution: json['resolution'] as String?,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAbuseReportToJson(_SnAbuseReport instance) => Map<String, dynamic> _$SnAbuseReportToJson(_SnAbuseReport instance) =>

View File

@@ -15,12 +15,11 @@ _SnAccount _$SnAccountFromJson(Map<String, dynamic> json) => _SnAccount(
isSuperuser: json['is_superuser'] as bool, isSuperuser: json['is_superuser'] as bool,
automatedId: json['automated_id'] as String?, automatedId: json['automated_id'] as String?,
profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>), profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>),
perkSubscription: perkSubscription: json['perk_subscription'] == null
json['perk_subscription'] == null ? null
? null : SnWalletSubscriptionRef.fromJson(
: SnWalletSubscriptionRef.fromJson( json['perk_subscription'] as Map<String, dynamic>,
json['perk_subscription'] as Map<String, dynamic>, ),
),
badges: badges:
(json['badges'] as List<dynamic>?) (json['badges'] as List<dynamic>?)
?.map((e) => SnAccountBadge.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnAccountBadge.fromJson(e as Map<String, dynamic>))
@@ -31,16 +30,14 @@ _SnAccount _$SnAccountFromJson(Map<String, dynamic> json) => _SnAccount(
?.map((e) => SnContactMethod.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnContactMethod.fromJson(e as Map<String, dynamic>))
.toList() ?? .toList() ??
const [], const [],
activatedAt: activatedAt: json['activated_at'] == null
json['activated_at'] == null ? null
? null : DateTime.parse(json['activated_at'] as String),
: DateTime.parse(json['activated_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAccountToJson(_SnAccount instance) => Map<String, dynamic> _$SnAccountToJson(_SnAccount instance) =>
@@ -73,8 +70,9 @@ _UsernameColor _$UsernameColorFromJson(Map<String, dynamic> json) =>
type: json['type'] as String? ?? 'plain', type: json['type'] as String? ?? 'plain',
value: json['value'] as String?, value: json['value'] as String?,
direction: json['direction'] as String?, direction: json['direction'] as String?,
colors: colors: (json['colors'] as List<dynamic>?)
(json['colors'] as List<dynamic>?)?.map((e) => e as String).toList(), ?.map((e) => e as String)
.toList(),
); );
Map<String, dynamic> _$UsernameColorToJson(_UsernameColor instance) => Map<String, dynamic> _$UsernameColorToJson(_UsernameColor instance) =>
@@ -85,69 +83,55 @@ Map<String, dynamic> _$UsernameColorToJson(_UsernameColor instance) =>
'colors': instance.colors, 'colors': instance.colors,
}; };
_SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) => _SnAccountProfile _$SnAccountProfileFromJson(
_SnAccountProfile( Map<String, dynamic> json,
id: json['id'] as String, ) => _SnAccountProfile(
firstName: json['first_name'] as String? ?? '', id: json['id'] as String,
middleName: json['middle_name'] as String? ?? '', firstName: json['first_name'] as String? ?? '',
lastName: json['last_name'] as String? ?? '', middleName: json['middle_name'] as String? ?? '',
bio: json['bio'] as String? ?? '', lastName: json['last_name'] as String? ?? '',
gender: json['gender'] as String? ?? '', bio: json['bio'] as String? ?? '',
pronouns: json['pronouns'] as String? ?? '', gender: json['gender'] as String? ?? '',
location: json['location'] as String? ?? '', pronouns: json['pronouns'] as String? ?? '',
timeZone: json['time_zone'] as String? ?? '', location: json['location'] as String? ?? '',
birthday: timeZone: json['time_zone'] as String? ?? '',
json['birthday'] == null birthday: json['birthday'] == null
? null ? null
: DateTime.parse(json['birthday'] as String), : DateTime.parse(json['birthday'] as String),
links: links: json['links'] == null
json['links'] == null ? const []
? const [] : const ProfileLinkConverter().fromJson(json['links']),
: const ProfileLinkConverter().fromJson(json['links']), lastSeenAt: json['last_seen_at'] == null
lastSeenAt: ? null
json['last_seen_at'] == null : DateTime.parse(json['last_seen_at'] as String),
? null activeBadge: json['active_badge'] == null
: DateTime.parse(json['last_seen_at'] as String), ? null
activeBadge: : SnAccountBadge.fromJson(json['active_badge'] as Map<String, dynamic>),
json['active_badge'] == null experience: (json['experience'] as num).toInt(),
? null level: (json['level'] as num).toInt(),
: SnAccountBadge.fromJson( socialCredits: (json['social_credits'] as num?)?.toDouble() ?? 100,
json['active_badge'] as Map<String, dynamic>, socialCreditsLevel: (json['social_credits_level'] as num?)?.toInt() ?? 0,
), levelingProgress: (json['leveling_progress'] as num).toDouble(),
experience: (json['experience'] as num).toInt(), picture: json['picture'] == null
level: (json['level'] as num).toInt(), ? null
socialCredits: (json['social_credits'] as num?)?.toDouble() ?? 100, : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>),
socialCreditsLevel: (json['social_credits_level'] as num?)?.toInt() ?? 0, background: json['background'] == null
levelingProgress: (json['leveling_progress'] as num).toDouble(), ? null
picture: : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
json['picture'] == null verification: json['verification'] == null
? null ? null
: SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), : SnVerificationMark.fromJson(
background: json['verification'] as Map<String, dynamic>,
json['background'] == null ),
? null usernameColor: json['username_color'] == null
: SnCloudFile.fromJson( ? null
json['background'] as Map<String, dynamic>, : UsernameColor.fromJson(json['username_color'] as Map<String, dynamic>),
), createdAt: DateTime.parse(json['created_at'] as String),
verification: updatedAt: DateTime.parse(json['updated_at'] as String),
json['verification'] == null deletedAt: json['deleted_at'] == null
? null ? null
: SnVerificationMark.fromJson( : DateTime.parse(json['deleted_at'] as String),
json['verification'] as Map<String, dynamic>, );
),
usernameColor:
json['username_color'] == null
? null
: UsernameColor.fromJson(
json['username_color'] as Map<String, dynamic>,
),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) => Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) =>
<String, dynamic>{ <String, dynamic>{
@@ -188,17 +172,15 @@ _SnAccountStatus _$SnAccountStatusFromJson(Map<String, dynamic> json) =>
isCustomized: json['is_customized'] as bool, isCustomized: json['is_customized'] as bool,
label: json['label'] as String? ?? "", label: json['label'] as String? ?? "",
meta: json['meta'] as Map<String, dynamic>?, meta: json['meta'] as Map<String, dynamic>?,
clearedAt: clearedAt: json['cleared_at'] == null
json['cleared_at'] == null ? null
? null : DateTime.parse(json['cleared_at'] as String),
: DateTime.parse(json['cleared_at'] as String),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAccountStatusToJson(_SnAccountStatus instance) => Map<String, dynamic> _$SnAccountStatusToJson(_SnAccountStatus instance) =>
@@ -225,21 +207,18 @@ _SnAccountBadge _$SnAccountBadgeFromJson(Map<String, dynamic> json) =>
label: json['label'] as String?, label: json['label'] as String?,
caption: json['caption'] as String?, caption: json['caption'] as String?,
meta: json['meta'] as Map<String, dynamic>, meta: json['meta'] as Map<String, dynamic>,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
activatedAt: activatedAt: json['activated_at'] == null
json['activated_at'] == null ? null
? null : DateTime.parse(json['activated_at'] as String),
: DateTime.parse(json['activated_at'] as String), deletedAt: json['deleted_at'] == null
deletedAt: ? null
json['deleted_at'] == null : DateTime.parse(json['deleted_at'] as String),
? null
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAccountBadgeToJson(_SnAccountBadge instance) => Map<String, dynamic> _$SnAccountBadgeToJson(_SnAccountBadge instance) =>
@@ -261,20 +240,18 @@ _SnContactMethod _$SnContactMethodFromJson(Map<String, dynamic> json) =>
_SnContactMethod( _SnContactMethod(
id: json['id'] as String, id: json['id'] as String,
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
verifiedAt: verifiedAt: json['verified_at'] == null
json['verified_at'] == null ? null
? null : DateTime.parse(json['verified_at'] as String),
: DateTime.parse(json['verified_at'] as String),
isPrimary: json['is_primary'] as bool, isPrimary: json['is_primary'] as bool,
isPublic: json['is_public'] as bool, isPublic: json['is_public'] as bool,
content: json['content'] as String, content: json['content'] as String,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnContactMethodToJson(_SnContactMethod instance) => Map<String, dynamic> _$SnContactMethodToJson(_SnContactMethod instance) =>
@@ -295,10 +272,9 @@ _SnNotification _$SnNotificationFromJson(Map<String, dynamic> json) =>
_SnNotification( _SnNotification(
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
id: json['id'] as String, id: json['id'] as String,
topic: json['topic'] as String, topic: json['topic'] as String,
title: json['title'] as String, title: json['title'] as String,
@@ -306,10 +282,9 @@ _SnNotification _$SnNotificationFromJson(Map<String, dynamic> json) =>
content: json['content'] as String, content: json['content'] as String,
meta: json['meta'] as Map<String, dynamic>? ?? const {}, meta: json['meta'] as Map<String, dynamic>? ?? const {},
priority: (json['priority'] as num).toInt(), priority: (json['priority'] as num).toInt(),
viewedAt: viewedAt: json['viewed_at'] == null
json['viewed_at'] == null ? null
? null : DateTime.parse(json['viewed_at'] as String),
: DateTime.parse(json['viewed_at'] as String),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
); );
@@ -376,10 +351,9 @@ _SnAuthDeviceWithSessione _$SnAuthDeviceWithSessioneFromJson(
deviceLabel: json['device_label'] as String?, deviceLabel: json['device_label'] as String?,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
platform: (json['platform'] as num).toInt(), platform: (json['platform'] as num).toInt(),
sessions: sessions: (json['sessions'] as List<dynamic>)
(json['sessions'] as List<dynamic>) .map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>))
.map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
isCurrent: json['is_current'] as bool? ?? false, isCurrent: json['is_current'] as bool? ?? false,
); );
@@ -405,10 +379,9 @@ _SnExperienceRecord _$SnExperienceRecordFromJson(Map<String, dynamic> json) =>
bonusMultiplier: (json['bonus_multiplier'] as num?)?.toDouble() ?? 1.0, bonusMultiplier: (json['bonus_multiplier'] as num?)?.toDouble() ?? 1.0,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnExperienceRecordToJson(_SnExperienceRecord instance) => Map<String, dynamic> _$SnExperienceRecordToJson(_SnExperienceRecord instance) =>
@@ -430,16 +403,14 @@ _SnSocialCreditRecord _$SnSocialCreditRecordFromJson(
delta: (json['delta'] as num).toDouble(), delta: (json['delta'] as num).toDouble(),
reasonType: json['reason_type'] as String, reasonType: json['reason_type'] as String,
reason: json['reason'] as String, reason: json['reason'] as String,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnSocialCreditRecordToJson( Map<String, dynamic> _$SnSocialCreditRecordToJson(
@@ -460,10 +431,9 @@ _SnFriendOverviewItem _$SnFriendOverviewItemFromJson(
) => _SnFriendOverviewItem( ) => _SnFriendOverviewItem(
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>), account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
status: SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>), status: SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>),
activities: activities: (json['activities'] as List<dynamic>)
(json['activities'] as List<dynamic>) .map((e) => SnPresenceActivity.fromJson(e as Map<String, dynamic>))
.map((e) => SnPresenceActivity.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
); );
Map<String, dynamic> _$SnFriendOverviewItemToJson( Map<String, dynamic> _$SnFriendOverviewItemToJson(

View File

@@ -12,10 +12,9 @@ _SnNotableDay _$SnNotableDayFromJson(Map<String, dynamic> json) =>
localName: json['local_name'] as String, localName: json['local_name'] as String,
globalName: json['global_name'] as String, globalName: json['global_name'] as String,
countryCode: json['country_code'] as String, countryCode: json['country_code'] as String,
holidays: holidays: (json['holidays'] as List<dynamic>)
(json['holidays'] as List<dynamic>) .map((e) => (e as num).toInt())
.map((e) => (e as num).toInt()) .toList(),
.toList(),
); );
Map<String, dynamic> _$SnNotableDayToJson(_SnNotableDay instance) => Map<String, dynamic> _$SnNotableDayToJson(_SnNotableDay instance) =>
@@ -35,10 +34,9 @@ _SnTimelineEvent _$SnTimelineEventFromJson(Map<String, dynamic> json) =>
data: json['data'], data: json['data'],
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnTimelineEventToJson(_SnTimelineEvent instance) => Map<String, dynamic> _$SnTimelineEventToJson(_SnTimelineEvent instance) =>
@@ -56,21 +54,18 @@ _SnCheckInResult _$SnCheckInResultFromJson(Map<String, dynamic> json) =>
_SnCheckInResult( _SnCheckInResult(
id: json['id'] as String, id: json['id'] as String,
level: (json['level'] as num).toInt(), level: (json['level'] as num).toInt(),
tips: tips: (json['tips'] as List<dynamic>)
(json['tips'] as List<dynamic>) .map((e) => SnFortuneTip.fromJson(e as Map<String, dynamic>))
.map((e) => SnFortuneTip.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnCheckInResultToJson(_SnCheckInResult instance) => Map<String, dynamic> _$SnCheckInResultToJson(_SnCheckInResult instance) =>
@@ -103,16 +98,14 @@ _SnEventCalendarEntry _$SnEventCalendarEntryFromJson(
Map<String, dynamic> json, Map<String, dynamic> json,
) => _SnEventCalendarEntry( ) => _SnEventCalendarEntry(
date: DateTime.parse(json['date'] as String), date: DateTime.parse(json['date'] as String),
checkInResult: checkInResult: json['check_in_result'] == null
json['check_in_result'] == null ? null
? null : 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: .map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>))
(json['statuses'] as List<dynamic>) .toList(),
.map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>))
.toList(),
); );
Map<String, dynamic> _$SnEventCalendarEntryToJson( Map<String, dynamic> _$SnEventCalendarEntryToJson(
@@ -141,10 +134,9 @@ _SnPresenceActivity _$SnPresenceActivityFromJson(Map<String, dynamic> json) =>
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPresenceActivityToJson(_SnPresenceActivity instance) => Map<String, dynamic> _$SnPresenceActivityToJson(_SnPresenceActivity instance) =>

View File

@@ -34,35 +34,29 @@ Map<String, dynamic> _$GeoIpLocationToJson(_GeoIpLocation instance) =>
_SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) =>
_SnAuthChallenge( _SnAuthChallenge(
id: json['id'] as String, id: json['id'] as String,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
stepRemain: (json['step_remain'] as num).toInt(), stepRemain: (json['step_remain'] as num).toInt(),
stepTotal: (json['step_total'] as num).toInt(), stepTotal: (json['step_total'] as num).toInt(),
failedAttempts: (json['failed_attempts'] as num).toInt(), failedAttempts: (json['failed_attempts'] as num).toInt(),
blacklistFactors: blacklistFactors: (json['blacklist_factors'] as List<dynamic>)
(json['blacklist_factors'] as List<dynamic>) .map((e) => e as String)
.map((e) => e as String) .toList(),
.toList(),
audiences: json['audiences'] as List<dynamic>, audiences: json['audiences'] as List<dynamic>,
scopes: json['scopes'] as List<dynamic>, scopes: json['scopes'] as List<dynamic>,
ipAddress: json['ip_address'] as String, ipAddress: json['ip_address'] as String,
userAgent: json['user_agent'] as String, userAgent: json['user_agent'] as String,
nonce: json['nonce'] as String?, nonce: json['nonce'] as String?,
location: location: json['location'] == null
json['location'] == null ? null
? null : GeoIpLocation.fromJson(json['location'] as Map<String, dynamic>),
: GeoIpLocation.fromJson(
json['location'] as Map<String, dynamic>,
),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) => Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) =>
@@ -90,28 +84,23 @@ _SnAuthSession _$SnAuthSessionFromJson(Map<String, dynamic> json) =>
id: json['id'] as String, id: json['id'] as String,
label: json['label'] as String?, label: json['label'] as String?,
lastGrantedAt: DateTime.parse(json['last_granted_at'] as String), lastGrantedAt: DateTime.parse(json['last_granted_at'] as String),
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
audiences: json['audiences'] as List<dynamic>, audiences: json['audiences'] as List<dynamic>,
scopes: json['scopes'] as List<dynamic>, scopes: json['scopes'] as List<dynamic>,
ipAddress: json['ip_address'] as String?, ipAddress: json['ip_address'] as String?,
userAgent: json['user_agent'] as String?, userAgent: json['user_agent'] as String?,
location: location: json['location'] == null
json['location'] == null ? null
? null : GeoIpLocation.fromJson(json['location'] as Map<String, dynamic>),
: GeoIpLocation.fromJson(
json['location'] as Map<String, dynamic>,
),
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAuthSessionToJson(_SnAuthSession instance) => Map<String, dynamic> _$SnAuthSessionToJson(_SnAuthSession instance) =>
@@ -138,18 +127,15 @@ _SnAuthFactor _$SnAuthFactorFromJson(Map<String, dynamic> json) =>
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String), expiredAt: json['expired_at'] == null
expiredAt: ? null
json['expired_at'] == null : DateTime.parse(json['expired_at'] as String),
? null enabledAt: json['enabled_at'] == null
: DateTime.parse(json['expired_at'] as String), ? null
enabledAt: : DateTime.parse(json['enabled_at'] as String),
json['enabled_at'] == null
? null
: DateTime.parse(json['enabled_at'] as String),
trustworthy: (json['trustworthy'] as num).toInt(), trustworthy: (json['trustworthy'] as num).toInt(),
createdResponse: json['created_response'] as Map<String, dynamic>?, createdResponse: json['created_response'] as Map<String, dynamic>?,
); );
@@ -177,10 +163,9 @@ _SnAccountConnection _$SnAccountConnectionFromJson(Map<String, dynamic> json) =>
lastUsedAt: DateTime.parse(json['last_used_at'] as String), lastUsedAt: DateTime.parse(json['last_used_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnAccountConnectionToJson( Map<String, dynamic> _$SnAccountConnectionToJson(

View File

@@ -10,10 +10,9 @@ AutoCompletionAccountResponse _$AutoCompletionAccountResponseFromJson(
Map<String, dynamic> json, Map<String, dynamic> json,
) => AutoCompletionAccountResponse( ) => AutoCompletionAccountResponse(
type: json['type'] as String, type: json['type'] as String,
items: items: (json['items'] as List<dynamic>)
(json['items'] as List<dynamic>) .map((e) => AutoCompletionItem.fromJson(e as Map<String, dynamic>))
.map((e) => AutoCompletionItem.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
@@ -29,10 +28,9 @@ AutoCompletionStickerResponse _$AutoCompletionStickerResponseFromJson(
Map<String, dynamic> json, Map<String, dynamic> json,
) => AutoCompletionStickerResponse( ) => AutoCompletionStickerResponse(
type: json['type'] as String, type: json['type'] as String,
items: items: (json['items'] as List<dynamic>)
(json['items'] as List<dynamic>) .map((e) => AutoCompletionItem.fromJson(e as Map<String, dynamic>))
.map((e) => AutoCompletionItem.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );

View File

@@ -14,10 +14,9 @@ _Bot _$BotFromJson(Map<String, dynamic> json) => _Bot(
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>), account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
developer: developer: json['developer'] == null
json['developer'] == null ? null
? null : SnDeveloper.fromJson(json['developer'] as Map<String, dynamic>),
: SnDeveloper.fromJson(json['developer'] as Map<String, dynamic>),
); );
Map<String, dynamic> _$BotToJson(_Bot instance) => <String, dynamic>{ Map<String, dynamic> _$BotToJson(_Bot instance) => <String, dynamic>{
@@ -74,10 +73,9 @@ _BotSecret _$BotSecretFromJson(Map<String, dynamic> json) => _BotSecret(
id: json['id'] as String? ?? '', id: json['id'] as String? ?? '',
secret: json['secret'] as String? ?? '', secret: json['secret'] as String? ?? '',
description: json['description'] as String?, description: json['description'] as String?,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
botId: json['bot_id'] as String? ?? '', botId: json['bot_id'] as String? ?? '',
); );

View File

@@ -13,30 +13,25 @@ _SnChatRoom _$SnChatRoomFromJson(Map<String, dynamic> json) => _SnChatRoom(
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
isPublic: json['is_public'] as bool? ?? false, isPublic: json['is_public'] as bool? ?? false,
isCommunity: json['is_community'] as bool? ?? false, isCommunity: json['is_community'] as bool? ?? false,
picture: picture: json['picture'] == null
json['picture'] == null ? null
? null : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), background: json['background'] == null
background: ? null
json['background'] == null : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
? null
: SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
realmId: json['realm_id'] as String?, realmId: json['realm_id'] as String?,
accountId: json['account_id'] as String?, accountId: json['account_id'] as String?,
realm: realm: json['realm'] == null
json['realm'] == null ? null
? null : SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String), members: (json['members'] as List<dynamic>?)
members: ?.map((e) => SnChatMember.fromJson(e as Map<String, dynamic>))
(json['members'] as List<dynamic>?) .toList(),
?.map((e) => SnChatMember.fromJson(e as Map<String, dynamic>))
.toList(),
); );
Map<String, dynamic> _$SnChatRoomToJson(_SnChatRoom instance) => Map<String, dynamic> _$SnChatRoomToJson(_SnChatRoom instance) =>
@@ -62,10 +57,9 @@ _SnChatMessage _$SnChatMessageFromJson(Map<String, dynamic> json) =>
_SnChatMessage( _SnChatMessage(
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
id: json['id'] as String, id: json['id'] as String,
type: json['type'] as String? ?? 'text', type: json['type'] as String? ?? 'text',
content: json['content'] as String?, content: json['content'] as String?,
@@ -76,10 +70,9 @@ _SnChatMessage _$SnChatMessageFromJson(Map<String, dynamic> json) =>
?.map((e) => e as String) ?.map((e) => e as String)
.toList() ?? .toList() ??
const [], const [],
editedAt: editedAt: json['edited_at'] == null
json['edited_at'] == null ? null
? null : DateTime.parse(json['edited_at'] as String),
: DateTime.parse(json['edited_at'] as String),
attachments: attachments:
(json['attachments'] as List<dynamic>?) (json['attachments'] as List<dynamic>?)
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
@@ -122,10 +115,9 @@ _SnChatReaction _$SnChatReactionFromJson(Map<String, dynamic> json) =>
_SnChatReaction( _SnChatReaction(
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
id: json['id'] as String, id: json['id'] as String,
messageId: json['message_id'] as String, messageId: json['message_id'] as String,
senderId: json['sender_id'] as String, senderId: json['sender_id'] as String,
@@ -151,42 +143,33 @@ _SnChatMember _$SnChatMemberFromJson(Map<String, dynamic> json) =>
_SnChatMember( _SnChatMember(
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
id: json['id'] as String, id: json['id'] as String,
chatRoomId: json['chat_room_id'] as String, chatRoomId: json['chat_room_id'] as String,
chatRoom: chatRoom: json['chat_room'] == null
json['chat_room'] == null ? null
? null : SnChatRoom.fromJson(json['chat_room'] as Map<String, dynamic>),
: SnChatRoom.fromJson(json['chat_room'] as Map<String, dynamic>),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>), account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
nick: json['nick'] as String?, nick: json['nick'] as String?,
notify: (json['notify'] as num).toInt(), notify: (json['notify'] as num).toInt(),
joinedAt: joinedAt: json['joined_at'] == null
json['joined_at'] == null ? null
? null : DateTime.parse(json['joined_at'] as String),
: DateTime.parse(json['joined_at'] as String), breakUntil: json['break_until'] == null
breakUntil: ? null
json['break_until'] == null : DateTime.parse(json['break_until'] as String),
? null timeoutUntil: json['timeout_until'] == null
: DateTime.parse(json['break_until'] as String), ? null
timeoutUntil: : DateTime.parse(json['timeout_until'] as String),
json['timeout_until'] == null status: json['status'] == null
? null ? null
: DateTime.parse(json['timeout_until'] as String), : SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>),
status: lastTyped: json['last_typed'] == null
json['status'] == null ? null
? null : DateTime.parse(json['last_typed'] as String),
: SnAccountStatus.fromJson(
json['status'] as Map<String, dynamic>,
),
lastTyped:
json['last_typed'] == null
? null
: DateTime.parse(json['last_typed'] as String),
); );
Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) => Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) =>
@@ -211,12 +194,11 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) =>
_SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) => _SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) =>
_SnChatSummary( _SnChatSummary(
unreadCount: (json['unread_count'] as num).toInt(), unreadCount: (json['unread_count'] as num).toInt(),
lastMessage: lastMessage: json['last_message'] == null
json['last_message'] == null ? null
? null : SnChatMessage.fromJson(
: SnChatMessage.fromJson( json['last_message'] as Map<String, dynamic>,
json['last_message'] as Map<String, dynamic>, ),
),
); );
Map<String, dynamic> _$SnChatSummaryToJson(_SnChatSummary instance) => Map<String, dynamic> _$SnChatSummaryToJson(_SnChatSummary instance) =>
@@ -251,10 +233,9 @@ _ChatRealtimeJoinResponse _$ChatRealtimeJoinResponseFromJson(
callId: json['call_id'] as String, callId: json['call_id'] as String,
roomName: json['room_name'] as String, roomName: json['room_name'] as String,
isAdmin: json['is_admin'] as bool, isAdmin: json['is_admin'] as bool,
participants: participants: (json['participants'] as List<dynamic>)
(json['participants'] as List<dynamic>) .map((e) => CallParticipant.fromJson(e as Map<String, dynamic>))
.map((e) => CallParticipant.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
); );
Map<String, dynamic> _$ChatRealtimeJoinResponseToJson( Map<String, dynamic> _$ChatRealtimeJoinResponseToJson(
@@ -288,14 +269,12 @@ _SnRealtimeCall _$SnRealtimeCallFromJson(Map<String, dynamic> json) =>
id: json['id'] as String, id: json['id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String), endedAt: json['ended_at'] == null
endedAt: ? null
json['ended_at'] == null : DateTime.parse(json['ended_at'] as String),
? null
: DateTime.parse(json['ended_at'] as String),
senderId: json['sender_id'] as String, senderId: json['sender_id'] as String,
sender: SnChatMember.fromJson(json['sender'] as Map<String, dynamic>), sender: SnChatMember.fromJson(json['sender'] as Map<String, dynamic>),
roomId: json['room_id'] as String, roomId: json['room_id'] as String,

View File

@@ -12,30 +12,25 @@ _CustomApp _$CustomAppFromJson(Map<String, dynamic> json) => _CustomApp(
name: json['name'] as String? ?? '', name: json['name'] as String? ?? '',
description: json['description'] as String?, description: json['description'] as String?,
status: (json['status'] as num?)?.toInt() ?? 0, status: (json['status'] as num?)?.toInt() ?? 0,
picture: picture: json['picture'] == null
json['picture'] == null ? null
? null : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), background: json['background'] == null
background: ? null
json['background'] == null : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
? null verification: json['verification'] == null
: SnCloudFile.fromJson(json['background'] as Map<String, dynamic>), ? null
verification: : SnVerificationMark.fromJson(
json['verification'] == null json['verification'] as Map<String, dynamic>,
? null ),
: SnVerificationMark.fromJson( oauthConfig: json['oauth_config'] == null
json['verification'] as Map<String, dynamic>, ? null
), : CustomAppOauthConfig.fromJson(
oauthConfig: json['oauth_config'] as Map<String, dynamic>,
json['oauth_config'] == null ),
? null links: json['links'] == null
: CustomAppOauthConfig.fromJson( ? null
json['oauth_config'] as Map<String, dynamic>, : CustomAppLinks.fromJson(json['links'] as Map<String, dynamic>),
),
links:
json['links'] == null
? null
: CustomAppLinks.fromJson(json['links'] as Map<String, dynamic>),
secrets: secrets:
(json['secrets'] as List<dynamic>?) (json['secrets'] as List<dynamic>?)
?.map((e) => CustomAppSecret.fromJson(e as Map<String, dynamic>)) ?.map((e) => CustomAppSecret.fromJson(e as Map<String, dynamic>))
@@ -83,10 +78,9 @@ _CustomAppOauthConfig _$CustomAppOauthConfigFromJson(
?.map((e) => e as String) ?.map((e) => e as String)
.toList() ?? .toList() ??
const [], const [],
postLogoutRedirectUris: postLogoutRedirectUris: (json['post_logout_redirect_uris'] as List<dynamic>?)
(json['post_logout_redirect_uris'] as List<dynamic>?) ?.map((e) => e as String)
?.map((e) => e as String) .toList(),
.toList(),
allowedScopes: allowedScopes:
(json['allowed_scopes'] as List<dynamic>?) (json['allowed_scopes'] as List<dynamic>?)
?.map((e) => e as String) ?.map((e) => e as String)
@@ -118,10 +112,9 @@ _CustomAppSecret _$CustomAppSecretFromJson(Map<String, dynamic> json) =>
id: json['id'] as String? ?? '', id: json['id'] as String? ?? '',
secret: json['secret'] as String? ?? '', secret: json['secret'] as String? ?? '',
description: json['description'] as String?, description: json['description'] as String?,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
isOidc: json['is_oidc'] as bool? ?? false, isOidc: json['is_oidc'] as bool? ?? false,
appId: json['app_id'] as String? ?? '', appId: json['app_id'] as String? ?? '',
); );

View File

@@ -9,10 +9,9 @@ part of 'developer.dart';
_SnDeveloper _$SnDeveloperFromJson(Map<String, dynamic> json) => _SnDeveloper( _SnDeveloper _$SnDeveloperFromJson(Map<String, dynamic> json) => _SnDeveloper(
id: json['id'] as String, id: json['id'] as String,
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
publisher: publisher: json['publisher'] == null
json['publisher'] == null ? null
? null : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
); );
Map<String, dynamic> _$SnDeveloperToJson(_SnDeveloper instance) => Map<String, dynamic> _$SnDeveloperToJson(_SnDeveloper instance) =>

View File

@@ -22,10 +22,9 @@ _DriveTask _$DriveTaskFromJson(Map<String, dynamic> json) => _DriveTask(
transmissionProgress: (json['transmission_progress'] as num?)?.toDouble(), transmissionProgress: (json['transmission_progress'] as num?)?.toDouble(),
errorMessage: json['error_message'] as String?, errorMessage: json['error_message'] as String?,
statusMessage: json['status_message'] as String?, statusMessage: json['status_message'] as String?,
result: result: json['result'] == null
json['result'] == null ? null
? null : SnCloudFile.fromJson(json['result'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['result'] as Map<String, dynamic>),
poolId: json['pool_id'] as String?, poolId: json['pool_id'] as String?,
bundleId: json['bundle_id'] as String?, bundleId: json['bundle_id'] as String?,
encryptPassword: json['encrypt_password'] as String?, encryptPassword: json['encrypt_password'] as String?,

View File

@@ -17,10 +17,9 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) =>
siteName: json['site_name'] as String?, siteName: json['site_name'] as String?,
contentType: json['content_type'] as String?, contentType: json['content_type'] as String?,
author: json['author'] as String?, author: json['author'] as String?,
publishedDate: publishedDate: json['published_date'] == null
json['published_date'] == null ? null
? null : DateTime.parse(json['published_date'] as String),
: DateTime.parse(json['published_date'] as String),
); );
Map<String, dynamic> _$SnScrappedLinkToJson(_SnScrappedLink instance) => Map<String, dynamic> _$SnScrappedLinkToJson(_SnScrappedLink instance) =>

View File

@@ -35,10 +35,9 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
description: json['description'] as String?, description: json['description'] as String?,
fileMeta: json['file_meta'] as Map<String, dynamic>?, fileMeta: json['file_meta'] as Map<String, dynamic>?,
userMeta: json['user_meta'] as Map<String, dynamic>?, userMeta: json['user_meta'] as Map<String, dynamic>?,
pool: pool: json['pool'] == null
json['pool'] == null ? null
? null : SnFilePool.fromJson(json['pool'] as Map<String, dynamic>),
: SnFilePool.fromJson(json['pool'] as Map<String, dynamic>),
sensitiveMarks: sensitiveMarks:
(json['sensitive_marks'] as List<dynamic>?) (json['sensitive_marks'] as List<dynamic>?)
?.map((e) => (e as num).toInt()) ?.map((e) => (e as num).toInt())
@@ -47,17 +46,15 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
mimeType: json['mime_type'] as String?, mimeType: json['mime_type'] as String?,
hash: json['hash'] as String?, hash: json['hash'] as String?,
size: (json['size'] as num).toInt(), size: (json['size'] as num).toInt(),
uploadedAt: uploadedAt: json['uploaded_at'] == null
json['uploaded_at'] == null ? null
? null : DateTime.parse(json['uploaded_at'] as String),
: DateTime.parse(json['uploaded_at'] as String),
uploadedTo: json['uploaded_to'] as String?, uploadedTo: json['uploaded_to'] as String?,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) => Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
@@ -87,10 +84,9 @@ _SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>
file: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>), file: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnCloudFileIndexToJson(_SnCloudFileIndex instance) => Map<String, dynamic> _$SnCloudFileIndexToJson(_SnCloudFileIndex instance) =>

View File

@@ -16,18 +16,15 @@ _SnFilePool _$SnFilePoolFromJson(Map<String, dynamic> json) => _SnFilePool(
isHidden: json['is_hidden'] as bool?, isHidden: json['is_hidden'] as bool?,
accountId: json['account_id'] as String?, accountId: json['account_id'] as String?,
resourceIdentifier: json['resource_identifier'] as String?, resourceIdentifier: json['resource_identifier'] as String?,
createdAt: createdAt: json['created_at'] == null
json['created_at'] == null ? null
? null : DateTime.parse(json['created_at'] as String),
: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null
updatedAt: ? null
json['updated_at'] == null : DateTime.parse(json['updated_at'] as String),
? null deletedAt: json['deleted_at'] == null
: DateTime.parse(json['updated_at'] as String), ? null
deletedAt: : DateTime.parse(json['deleted_at'] as String),
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnFilePoolToJson(_SnFilePool instance) => Map<String, dynamic> _$SnFilePoolToJson(_SnFilePool instance) =>

View File

@@ -10,10 +10,9 @@ _SnHeatmap _$SnHeatmapFromJson(Map<String, dynamic> json) => _SnHeatmap(
unit: json['unit'] as String, unit: json['unit'] as String,
periodStart: DateTime.parse(json['period_start'] as String), periodStart: DateTime.parse(json['period_start'] as String),
periodEnd: DateTime.parse(json['period_end'] as String), periodEnd: DateTime.parse(json['period_end'] as String),
items: items: (json['items'] as List<dynamic>)
(json['items'] as List<dynamic>) .map((e) => SnHeatmapItem.fromJson(e as Map<String, dynamic>))
.map((e) => SnHeatmapItem.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
); );
Map<String, dynamic> _$SnHeatmapToJson(_SnHeatmap instance) => Map<String, dynamic> _$SnHeatmapToJson(_SnHeatmap instance) =>

View File

@@ -8,31 +8,25 @@ part of 'poll.dart';
_SnPollWithStats _$SnPollWithStatsFromJson(Map<String, dynamic> json) => _SnPollWithStats _$SnPollWithStatsFromJson(Map<String, dynamic> json) =>
_SnPollWithStats( _SnPollWithStats(
userAnswer: userAnswer: json['user_answer'] == null
json['user_answer'] == null ? null
? null : SnPollAnswer.fromJson(json['user_answer'] as Map<String, dynamic>),
: SnPollAnswer.fromJson(
json['user_answer'] as Map<String, dynamic>,
),
stats: json['stats'] as Map<String, dynamic>? ?? const {}, stats: json['stats'] as Map<String, dynamic>? ?? const {},
id: json['id'] as String, id: json['id'] as String,
questions: questions: (json['questions'] as List<dynamic>)
(json['questions'] as List<dynamic>) .map((e) => SnPollQuestion.fromJson(e as Map<String, dynamic>))
.map((e) => SnPollQuestion.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
title: json['title'] as String?, title: json['title'] as String?,
description: json['description'] as String?, description: json['description'] as String?,
endedAt: endedAt: json['ended_at'] == null
json['ended_at'] == null ? null
? null : DateTime.parse(json['ended_at'] as String),
: DateTime.parse(json['ended_at'] as String),
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPollWithStatsToJson(_SnPollWithStats instance) => Map<String, dynamic> _$SnPollWithStatsToJson(_SnPollWithStats instance) =>
@@ -52,27 +46,23 @@ Map<String, dynamic> _$SnPollWithStatsToJson(_SnPollWithStats instance) =>
_SnPoll _$SnPollFromJson(Map<String, dynamic> json) => _SnPoll( _SnPoll _$SnPollFromJson(Map<String, dynamic> json) => _SnPoll(
id: json['id'] as String, id: json['id'] as String,
questions: questions: (json['questions'] as List<dynamic>)
(json['questions'] as List<dynamic>) .map((e) => SnPollQuestion.fromJson(e as Map<String, dynamic>))
.map((e) => SnPollQuestion.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
title: json['title'] as String?, title: json['title'] as String?,
description: json['description'] as String?, description: json['description'] as String?,
endedAt: endedAt: json['ended_at'] == null
json['ended_at'] == null ? null
? null : DateTime.parse(json['ended_at'] as String),
: DateTime.parse(json['ended_at'] as String),
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
publisher: publisher: json['publisher'] == null
json['publisher'] == null ? null
? null : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPollToJson(_SnPoll instance) => <String, dynamic>{ Map<String, dynamic> _$SnPollToJson(_SnPoll instance) => <String, dynamic>{
@@ -92,10 +82,9 @@ _SnPollQuestion _$SnPollQuestionFromJson(Map<String, dynamic> json) =>
_SnPollQuestion( _SnPollQuestion(
id: json['id'] as String, id: json['id'] as String,
type: $enumDecode(_$SnPollQuestionTypeEnumMap, json['type']), type: $enumDecode(_$SnPollQuestionTypeEnumMap, json['type']),
options: options: (json['options'] as List<dynamic>?)
(json['options'] as List<dynamic>?) ?.map((e) => SnPollOption.fromJson(e as Map<String, dynamic>))
?.map((e) => SnPollOption.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
title: json['title'] as String, title: json['title'] as String,
description: json['description'] as String?, description: json['description'] as String?,
order: (json['order'] as num).toInt(), order: (json['order'] as num).toInt(),
@@ -145,14 +134,12 @@ _SnPollAnswer _$SnPollAnswerFromJson(Map<String, dynamic> json) =>
pollId: json['poll_id'] as String, pollId: json['poll_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String), account: json['account'] == null
account: ? null
json['account'] == null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
? null
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
); );
Map<String, dynamic> _$SnPollAnswerToJson(_SnPollAnswer instance) => Map<String, dynamic> _$SnPollAnswerToJson(_SnPollAnswer instance) =>

View File

@@ -11,25 +11,20 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
title: json['title'] as String?, title: json['title'] as String?,
description: json['description'] as String?, description: json['description'] as String?,
language: json['language'] as String?, language: json['language'] as String?,
editedAt: editedAt: json['edited_at'] == null
json['edited_at'] == null ? null
? null : DateTime.parse(json['edited_at'] as String),
: DateTime.parse(json['edited_at'] as String), publishedAt: json['published_at'] == null
publishedAt: ? null
json['published_at'] == null : DateTime.parse(json['published_at'] as String),
? null
: DateTime.parse(json['published_at'] as String),
visibility: (json['visibility'] as num?)?.toInt() ?? 0, visibility: (json['visibility'] as num?)?.toInt() ?? 0,
content: json['content'] as String?, content: json['content'] as String?,
slug: json['slug'] as String?, slug: json['slug'] as String?,
type: (json['type'] as num?)?.toInt() ?? 0, type: (json['type'] as num?)?.toInt() ?? 0,
meta: json['meta'] as Map<String, dynamic>?, meta: json['meta'] as Map<String, dynamic>?,
embedView: embedView: json['embed_view'] == null
json['embed_view'] == null ? null
? null : SnPostEmbedView.fromJson(json['embed_view'] as Map<String, dynamic>),
: SnPostEmbedView.fromJson(
json['embed_view'] as Map<String, dynamic>,
),
viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0,
viewsTotal: (json['views_total'] as num?)?.toInt() ?? 0, viewsTotal: (json['views_total'] as num?)?.toInt() ?? 0,
upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, upvotes: (json['upvotes'] as num?)?.toInt() ?? 0,
@@ -38,25 +33,21 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
awardedScore: (json['awarded_score'] as num?)?.toInt() ?? 0, awardedScore: (json['awarded_score'] as num?)?.toInt() ?? 0,
pinMode: (json['pin_mode'] as num?)?.toInt(), 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 ? null
? null : SnPost.fromJson(json['threaded_post'] as Map<String, dynamic>),
: SnPost.fromJson(json['threaded_post'] as Map<String, dynamic>),
repliedPostId: json['replied_post_id'] as String?, repliedPostId: json['replied_post_id'] as String?,
repliedPost: repliedPost: json['replied_post'] == null
json['replied_post'] == null ? null
? null : SnPost.fromJson(json['replied_post'] as Map<String, dynamic>),
: SnPost.fromJson(json['replied_post'] as Map<String, dynamic>),
forwardedPostId: json['forwarded_post_id'] as String?, forwardedPostId: json['forwarded_post_id'] as String?,
forwardedPost: forwardedPost: json['forwarded_post'] == null
json['forwarded_post'] == null ? null
? null : SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>),
: SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>),
realmId: json['realm_id'] as String?, realmId: json['realm_id'] as String?,
realm: realm: json['realm'] == null
json['realm'] == null ? null
? null : SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
attachments: attachments:
(json['attachments'] as List<dynamic>?) (json['attachments'] as List<dynamic>?)
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
@@ -90,18 +81,15 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
?.map((e) => SnPostFeaturedRecord.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnPostFeaturedRecord.fromJson(e as Map<String, dynamic>))
.toList() ?? .toList() ??
const [], const [],
createdAt: createdAt: json['created_at'] == null
json['created_at'] == null ? null
? null : DateTime.parse(json['created_at'] as String),
: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null
updatedAt: ? null
json['updated_at'] == null : DateTime.parse(json['updated_at'] as String),
? null deletedAt: json['deleted_at'] == null
: DateTime.parse(json['updated_at'] as String), ? null
deletedAt: : DateTime.parse(json['deleted_at'] as String),
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
repliedGone: json['replied_gone'] as bool? ?? false, repliedGone: json['replied_gone'] as bool? ?? false,
forwardedGone: json['forwarded_gone'] as bool? ?? false, forwardedGone: json['forwarded_gone'] as bool? ?? false,
isTruncated: json['is_truncated'] as bool? ?? false, isTruncated: json['is_truncated'] as bool? ?? false,
@@ -214,18 +202,15 @@ _SnPostAward _$SnPostAwardFromJson(Map<String, dynamic> json) => _SnPostAward(
message: json['message'] as String?, message: json['message'] as String?,
postId: json['post_id'] as String, postId: json['post_id'] as String,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: createdAt: json['created_at'] == null
json['created_at'] == null ? null
? null : DateTime.parse(json['created_at'] as String),
: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null
updatedAt: ? null
json['updated_at'] == null : DateTime.parse(json['updated_at'] as String),
? null deletedAt: json['deleted_at'] == null
: DateTime.parse(json['updated_at'] as String), ? null
deletedAt: : DateTime.parse(json['deleted_at'] as String),
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPostAwardToJson(_SnPostAward instance) => Map<String, dynamic> _$SnPostAwardToJson(_SnPostAward instance) =>
@@ -250,14 +235,12 @@ _SnPostReaction _$SnPostReactionFromJson(Map<String, dynamic> json) =>
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>), deletedAt: json['deleted_at'] == null
deletedAt: ? null
json['deleted_at'] == null : DateTime.parse(json['deleted_at'] as String),
? null
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) => Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) =>
@@ -278,17 +261,15 @@ _SnPostFeaturedRecord _$SnPostFeaturedRecordFromJson(
) => _SnPostFeaturedRecord( ) => _SnPostFeaturedRecord(
id: json['id'] as String, id: json['id'] as String,
postId: json['post_id'] as String, postId: json['post_id'] as String,
featuredAt: featuredAt: json['featured_at'] == null
json['featured_at'] == null ? null
? null : DateTime.parse(json['featured_at'] as String),
: DateTime.parse(json['featured_at'] as String),
socialCredits: (json['social_credits'] as num).toInt(), socialCredits: (json['social_credits'] as num).toInt(),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPostFeaturedRecordToJson( Map<String, dynamic> _$SnPostFeaturedRecordToJson(

View File

@@ -17,10 +17,9 @@ _SnPublicationSite _$SnPublicationSiteFromJson(Map<String, dynamic> json) =>
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
pages: pages: (json['pages'] as List<dynamic>)
(json['pages'] as List<dynamic>) .map((e) => SnPublicationPage.fromJson(e as Map<String, dynamic>))
.map((e) => SnPublicationPage.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
); );
Map<String, dynamic> _$SnPublicationSiteToJson(_SnPublicationSite instance) => Map<String, dynamic> _$SnPublicationSiteToJson(_SnPublicationSite instance) =>

View File

@@ -12,38 +12,31 @@ _SnPublisher _$SnPublisherFromJson(Map<String, dynamic> json) => _SnPublisher(
name: json['name'] as String? ?? '', name: json['name'] as String? ?? '',
nick: json['nick'] as String? ?? '', nick: json['nick'] as String? ?? '',
bio: json['bio'] as String? ?? '', bio: json['bio'] as String? ?? '',
picture: picture: json['picture'] == null
json['picture'] == null ? null
? null : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), background: json['background'] == null
background: ? null
json['background'] == null : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
? null account: json['account'] == null
: SnCloudFile.fromJson(json['background'] as Map<String, dynamic>), ? null
account: : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
json['account'] == null
? null
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
accountId: json['account_id'] as String?, accountId: json['account_id'] as String?,
createdAt: createdAt: json['created_at'] == null
json['created_at'] == null ? null
? null : DateTime.parse(json['created_at'] as String),
: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null
updatedAt: ? null
json['updated_at'] == null : DateTime.parse(json['updated_at'] as String),
? null deletedAt: json['deleted_at'] == null
: DateTime.parse(json['updated_at'] as String), ? null
deletedAt: : DateTime.parse(json['deleted_at'] as String),
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
realmId: json['realm_id'] as String?, realmId: json['realm_id'] as String?,
verification: verification: json['verification'] == null
json['verification'] == null ? null
? null : SnVerificationMark.fromJson(
: SnVerificationMark.fromJson( json['verification'] as Map<String, dynamic>,
json['verification'] as Map<String, dynamic>, ),
),
); );
Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) => Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
@@ -67,26 +60,22 @@ Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) =>
_SnPublisherMember _$SnPublisherMemberFromJson(Map<String, dynamic> json) => _SnPublisherMember _$SnPublisherMemberFromJson(Map<String, dynamic> json) =>
_SnPublisherMember( _SnPublisherMember(
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
publisher: publisher: json['publisher'] == null
json['publisher'] == null ? null
? null : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
role: (json['role'] as num).toInt(), role: (json['role'] as num).toInt(),
joinedAt: joinedAt: json['joined_at'] == null
json['joined_at'] == null ? null
? null : DateTime.parse(json['joined_at'] as String),
: DateTime.parse(json['joined_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnPublisherMemberToJson(_SnPublisherMember instance) => Map<String, dynamic> _$SnPublisherMemberToJson(_SnPublisherMember instance) =>

View File

@@ -12,27 +12,23 @@ _SnRealm _$SnRealmFromJson(Map<String, dynamic> json) => _SnRealm(
name: json['name'] as String? ?? '', name: json['name'] as String? ?? '',
description: json['description'] as String? ?? '', description: json['description'] as String? ?? '',
verifiedAs: json['verified_as'] as String?, verifiedAs: json['verified_as'] as String?,
verifiedAt: verifiedAt: json['verified_at'] == null
json['verified_at'] == null ? null
? null : DateTime.parse(json['verified_at'] as String),
: DateTime.parse(json['verified_at'] as String),
isCommunity: json['is_community'] as bool, isCommunity: json['is_community'] as bool,
isPublic: json['is_public'] as bool, isPublic: json['is_public'] as bool,
picture: picture: json['picture'] == null
json['picture'] == null ? null
? null : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), background: json['background'] == null
background: ? null
json['background'] == null : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
? null
: SnCloudFile.fromJson(json['background'] as Map<String, dynamic>),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnRealmToJson(_SnRealm instance) => <String, dynamic>{ Map<String, dynamic> _$SnRealmToJson(_SnRealm instance) => <String, dynamic>{
@@ -55,32 +51,25 @@ Map<String, dynamic> _$SnRealmToJson(_SnRealm instance) => <String, dynamic>{
_SnRealmMember _$SnRealmMemberFromJson(Map<String, dynamic> json) => _SnRealmMember _$SnRealmMemberFromJson(Map<String, dynamic> json) =>
_SnRealmMember( _SnRealmMember(
realmId: json['realm_id'] as String, realmId: json['realm_id'] as String,
realm: realm: json['realm'] == null
json['realm'] == null ? null
? null : SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
role: (json['role'] as num).toInt(), role: (json['role'] as num).toInt(),
joinedAt: joinedAt: json['joined_at'] == null
json['joined_at'] == null ? null
? null : DateTime.parse(json['joined_at'] as String),
: DateTime.parse(json['joined_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String), status: json['status'] == null
status: ? null
json['status'] == null : SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>),
? null
: SnAccountStatus.fromJson(
json['status'] as Map<String, dynamic>,
),
); );
Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) => Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) =>

View File

@@ -9,22 +9,19 @@ part of 'reference.dart';
_Reference _$ReferenceFromJson(Map<String, dynamic> json) => _Reference( _Reference _$ReferenceFromJson(Map<String, dynamic> json) => _Reference(
id: json['id'] as String, id: json['id'] as String,
fileId: json['file_id'] as String, fileId: json['file_id'] as String,
file: file: json['file'] == null
json['file'] == null ? null
? null : SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
usage: json['usage'] as String, usage: json['usage'] as String,
resourceId: json['resource_id'] as String, resourceId: json['resource_id'] as String,
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$ReferenceToJson(_Reference instance) => Map<String, dynamic> _$ReferenceToJson(_Reference instance) =>

View File

@@ -8,26 +8,22 @@ part of 'relationship.dart';
_SnRelationship _$SnRelationshipFromJson(Map<String, dynamic> json) => _SnRelationship _$SnRelationshipFromJson(Map<String, dynamic> json) =>
_SnRelationship( _SnRelationship(
createdAt: createdAt: json['created_at'] == null
json['created_at'] == null ? null
? null : DateTime.parse(json['created_at'] as String),
: DateTime.parse(json['created_at'] as String), updatedAt: json['updated_at'] == null
updatedAt: ? null
json['updated_at'] == null : DateTime.parse(json['updated_at'] as String),
? null deletedAt: json['deleted_at'] == null
: DateTime.parse(json['updated_at'] as String), ? null
deletedAt: : DateTime.parse(json['deleted_at'] as String),
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>), account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
relatedId: json['related_id'] as String, relatedId: json['related_id'] as String,
related: SnAccount.fromJson(json['related'] as Map<String, dynamic>), related: SnAccount.fromJson(json['related'] as Map<String, dynamic>),
expiredAt: expiredAt: json['expired_at'] == null
json['expired_at'] == null ? null
? null : DateTime.parse(json['expired_at'] as String),
: DateTime.parse(json['expired_at'] as String),
status: (json['status'] as num).toInt(), status: (json['status'] as num).toInt(),
); );

View File

@@ -11,16 +11,14 @@ _SnSticker _$SnStickerFromJson(Map<String, dynamic> json) => _SnSticker(
slug: json['slug'] as String, slug: json['slug'] as String,
image: SnCloudFile.fromJson(json['image'] as Map<String, dynamic>), image: SnCloudFile.fromJson(json['image'] as Map<String, dynamic>),
packId: json['pack_id'] as String, packId: json['pack_id'] as String,
pack: pack: json['pack'] == null
json['pack'] == null ? null
? null : SnStickerPack.fromJson(json['pack'] as Map<String, dynamic>),
: SnStickerPack.fromJson(json['pack'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnStickerToJson(_SnSticker instance) => Map<String, dynamic> _$SnStickerToJson(_SnSticker instance) =>
@@ -42,20 +40,17 @@ _SnStickerPack _$SnStickerPackFromJson(Map<String, dynamic> json) =>
description: json['description'] as String, description: json['description'] as String,
prefix: json['prefix'] as String, prefix: json['prefix'] as String,
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
icon: icon: json['icon'] == null
json['icon'] == null ? null
? null : SnCloudFile.fromJson(json['icon'] as Map<String, dynamic>),
: SnCloudFile.fromJson(json['icon'] as Map<String, dynamic>), publisher: json['publisher'] == null
publisher: ? null
json['publisher'] == null : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
? null
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
stickers: stickers:
(json['stickers'] as List<dynamic>?) (json['stickers'] as List<dynamic>?)
?.map((e) => SnSticker.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnSticker.fromJson(e as Map<String, dynamic>))

View File

@@ -16,14 +16,12 @@ _StreamThinkingRequest _$StreamThinkingRequestFromJson(
?.map((e) => e as String) ?.map((e) => e as String)
.toList() ?? .toList() ??
const [], const [],
attachedPosts: attachedPosts: (json['attached_posts'] as List<dynamic>?)
(json['attached_posts'] as List<dynamic>?) ?.map((e) => e as String)
?.map((e) => e as String) .toList(),
.toList(), attachedMessages: (json['attached_messages'] as List<dynamic>?)
attachedMessages: ?.map((e) => e as Map<String, dynamic>)
(json['attached_messages'] as List<dynamic>?) .toList(),
?.map((e) => e as Map<String, dynamic>)
.toList(),
serviceId: json['service_id'] as String?, serviceId: json['service_id'] as String?,
); );
@@ -87,18 +85,14 @@ _SnThinkingMessagePart _$SnThinkingMessagePartFromJson(
(json['type'] as num).toInt(), (json['type'] as num).toInt(),
), ),
text: json['text'] as String?, text: json['text'] as String?,
functionCall: functionCall: json['function_call'] == null
json['function_call'] == null ? null
? null : SnFunctionCall.fromJson(json['function_call'] as Map<String, dynamic>),
: SnFunctionCall.fromJson( functionResult: json['function_result'] == null
json['function_call'] as Map<String, dynamic>, ? null
), : SnFunctionResult.fromJson(
functionResult: json['function_result'] as Map<String, dynamic>,
json['function_result'] == null ),
? null
: SnFunctionResult.fromJson(
json['function_result'] as Map<String, dynamic>,
),
); );
Map<String, dynamic> _$SnThinkingMessagePartToJson( Map<String, dynamic> _$SnThinkingMessagePartToJson(
@@ -119,10 +113,9 @@ _SnThinkingSequence _$SnThinkingSequenceFromJson(Map<String, dynamic> json) =>
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnThinkingSequenceToJson(_SnThinkingSequence instance) => Map<String, dynamic> _$SnThinkingSequenceToJson(_SnThinkingSequence instance) =>
@@ -159,18 +152,16 @@ _SnThinkingThought _$SnThinkingThoughtFromJson(Map<String, dynamic> json) =>
tokenCount: (json['token_count'] as num?)?.toInt(), tokenCount: (json['token_count'] as num?)?.toInt(),
modelName: json['model_name'] as String?, modelName: json['model_name'] as String?,
sequenceId: json['sequence_id'] as String, sequenceId: json['sequence_id'] as String,
sequence: sequence: json['sequence'] == null
json['sequence'] == null ? null
? null : SnThinkingSequence.fromJson(
: SnThinkingSequence.fromJson( json['sequence'] as Map<String, dynamic>,
json['sequence'] as Map<String, dynamic>, ),
),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnThinkingThoughtToJson(_SnThinkingThought instance) => Map<String, dynamic> _$SnThinkingThoughtToJson(_SnThinkingThought instance) =>
@@ -206,10 +197,9 @@ _ThoughtServicesResponse _$ThoughtServicesResponseFromJson(
Map<String, dynamic> json, Map<String, dynamic> json,
) => _ThoughtServicesResponse( ) => _ThoughtServicesResponse(
defaultService: json['default_service'] as String, defaultService: json['default_service'] as String,
services: services: (json['services'] as List<dynamic>)
(json['services'] as List<dynamic>) .map((e) => ThoughtService.fromJson(e as Map<String, dynamic>))
.map((e) => ThoughtService.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
); );
Map<String, dynamic> _$ThoughtServicesResponseToJson( Map<String, dynamic> _$ThoughtServicesResponseToJson(

View File

@@ -8,21 +8,18 @@ part of 'wallet.dart';
_SnWallet _$SnWalletFromJson(Map<String, dynamic> json) => _SnWallet( _SnWallet _$SnWalletFromJson(Map<String, dynamic> json) => _SnWallet(
id: json['id'] as String, id: json['id'] as String,
pockets: pockets: (json['pockets'] as List<dynamic>)
(json['pockets'] as List<dynamic>) .map((e) => SnWalletPocket.fromJson(e as Map<String, dynamic>))
.map((e) => SnWalletPocket.fromJson(e as Map<String, dynamic>)) .toList(),
.toList(),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletToJson(_SnWallet instance) => <String, dynamic>{ Map<String, dynamic> _$SnWalletToJson(_SnWallet instance) => <String, dynamic>{
@@ -77,10 +74,9 @@ _SnWalletPocket _$SnWalletPocketFromJson(Map<String, dynamic> json) =>
walletId: json['wallet_id'] as String, walletId: json['wallet_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletPocketToJson(_SnWalletPocket instance) => Map<String, dynamic> _$SnWalletPocketToJson(_SnWalletPocket instance) =>
@@ -102,21 +98,18 @@ _SnTransaction _$SnTransactionFromJson(Map<String, dynamic> json) =>
remarks: json['remarks'] as String?, remarks: json['remarks'] as String?,
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
payerWalletId: json['payer_wallet_id'] as String?, payerWalletId: json['payer_wallet_id'] as String?,
payerWallet: payerWallet: json['payer_wallet'] == null
json['payer_wallet'] == null ? null
? null : SnWallet.fromJson(json['payer_wallet'] as Map<String, dynamic>),
: SnWallet.fromJson(json['payer_wallet'] as Map<String, dynamic>),
payeeWalletId: json['payee_wallet_id'] as String?, payeeWalletId: json['payee_wallet_id'] as String?,
payeeWallet: payeeWallet: json['payee_wallet'] == null
json['payee_wallet'] == null ? null
? null : SnWallet.fromJson(json['payee_wallet'] as Map<String, dynamic>),
: SnWallet.fromJson(json['payee_wallet'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnTransactionToJson(_SnTransaction instance) => Map<String, dynamic> _$SnTransactionToJson(_SnTransaction instance) =>
@@ -140,10 +133,9 @@ _SnWalletSubscription _$SnWalletSubscriptionFromJson(
) => _SnWalletSubscription( ) => _SnWalletSubscription(
id: json['id'] as String, id: json['id'] as String,
begunAt: DateTime.parse(json['begun_at'] as String), begunAt: DateTime.parse(json['begun_at'] as String),
endedAt: endedAt: json['ended_at'] == null
json['ended_at'] == null ? null
? null : DateTime.parse(json['ended_at'] as String),
: DateTime.parse(json['ended_at'] as String),
identifier: json['identifier'] as String, identifier: json['identifier'] as String,
isActive: json['is_active'] as bool? ?? true, isActive: json['is_active'] as bool? ?? true,
isFreeTrial: json['is_free_trial'] as bool? ?? false, isFreeTrial: json['is_free_trial'] as bool? ?? false,
@@ -153,23 +145,20 @@ _SnWalletSubscription _$SnWalletSubscriptionFromJson(
basePrice: (json['base_price'] as num?)?.toDouble(), basePrice: (json['base_price'] as num?)?.toDouble(),
couponId: json['coupon_id'] as String?, couponId: json['coupon_id'] as String?,
coupon: json['coupon'], coupon: json['coupon'],
renewalAt: renewalAt: json['renewal_at'] == null
json['renewal_at'] == null ? null
? null : DateTime.parse(json['renewal_at'] as String),
: DateTime.parse(json['renewal_at'] as String),
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
isAvailable: json['is_available'] as bool? ?? true, isAvailable: json['is_available'] as bool? ?? true,
finalPrice: (json['final_price'] as num?)?.toDouble(), finalPrice: (json['final_price'] as num?)?.toDouble(),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletSubscriptionToJson( Map<String, dynamic> _$SnWalletSubscriptionToJson(
@@ -204,10 +193,9 @@ _SnWalletSubscriptionRef _$SnWalletSubscriptionRefFromJson(
isActive: json['is_active'] as bool, isActive: json['is_active'] as bool,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
identifier: json['identifier'] as String, identifier: json['identifier'] as String,
); );
@@ -239,10 +227,9 @@ _SnWalletOrder _$SnWalletOrderFromJson(Map<String, dynamic> json) =>
issuerAppId: json['issuer_app_id'] as String?, issuerAppId: json['issuer_app_id'] as String?,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletOrderToJson(_SnWalletOrder instance) => Map<String, dynamic> _$SnWalletOrderToJson(_SnWalletOrder instance) =>
@@ -269,43 +256,36 @@ _SnWalletGift _$SnWalletGiftFromJson(Map<String, dynamic> json) =>
giftCode: json['gift_code'] as String, giftCode: json['gift_code'] as String,
subscriptionIdentifier: json['subscription_identifier'] as String, subscriptionIdentifier: json['subscription_identifier'] as String,
recipientId: json['recipient_id'] as String?, recipientId: json['recipient_id'] as String?,
recipient: recipient: json['recipient'] == null
json['recipient'] == null ? null
? null : SnAccount.fromJson(json['recipient'] as Map<String, dynamic>),
: SnAccount.fromJson(json['recipient'] as Map<String, dynamic>),
gifterId: json['gifter_id'] as String, gifterId: json['gifter_id'] as String,
gifter: gifter: json['gifter'] == null
json['gifter'] == null ? null
? null : SnAccount.fromJson(json['gifter'] as Map<String, dynamic>),
: SnAccount.fromJson(json['gifter'] as Map<String, dynamic>),
redeemerId: json['redeemer_id'] as String?, redeemerId: json['redeemer_id'] as String?,
redeemer: redeemer: json['redeemer'] == null
json['redeemer'] == null ? null
? null : SnAccount.fromJson(json['redeemer'] as Map<String, dynamic>),
: SnAccount.fromJson(json['redeemer'] as Map<String, dynamic>),
message: json['message'] as String?, message: json['message'] as String?,
status: (json['status'] as num).toInt(), status: (json['status'] as num).toInt(),
redeemedAt: redeemedAt: json['redeemed_at'] == null
json['redeemed_at'] == null ? null
? null : DateTime.parse(json['redeemed_at'] as String),
: DateTime.parse(json['redeemed_at'] as String), expiredAt: json['expired_at'] == null
expiredAt: ? null
json['expired_at'] == null : DateTime.parse(json['expired_at'] as String),
? null
: DateTime.parse(json['expired_at'] as String),
subscriptionId: json['subscription_id'] as String?, subscriptionId: json['subscription_id'] as String?,
subscription: subscription: json['subscription'] == null
json['subscription'] == null ? null
? null : SnWalletSubscription.fromJson(
: SnWalletSubscription.fromJson( json['subscription'] as Map<String, dynamic>,
json['subscription'] as Map<String, dynamic>, ),
),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletGiftToJson(_SnWalletGift instance) => Map<String, dynamic> _$SnWalletGiftToJson(_SnWalletGift instance) =>
@@ -330,35 +310,31 @@ Map<String, dynamic> _$SnWalletGiftToJson(_SnWalletGift instance) =>
'deleted_at': instance.deletedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(),
}; };
_SnWalletFund _$SnWalletFundFromJson( _SnWalletFund _$SnWalletFundFromJson(Map<String, dynamic> json) =>
Map<String, dynamic> json, _SnWalletFund(
) => _SnWalletFund( id: json['id'] as String,
id: json['id'] as String, currency: json['currency'] as String,
currency: json['currency'] as String, totalAmount: (json['total_amount'] as num).toDouble(),
totalAmount: (json['total_amount'] as num).toDouble(), remainingAmount: (json['remaining_amount'] as num).toDouble(),
remainingAmount: (json['remaining_amount'] as num).toDouble(), amountOfSplits: (json['amount_of_splits'] as num).toInt(),
amountOfSplits: (json['amount_of_splits'] as num).toInt(), splitType: (json['split_type'] as num).toInt(),
splitType: (json['split_type'] as num).toInt(), status: (json['status'] as num).toInt(),
status: (json['status'] as num).toInt(), message: json['message'] as String?,
message: json['message'] as String?, creatorAccountId: json['creator_account_id'] as String,
creatorAccountId: json['creator_account_id'] as String, creatorAccount: json['creator_account'] == null
creatorAccount:
json['creator_account'] == null
? null ? null
: SnAccount.fromJson(json['creator_account'] as Map<String, dynamic>), : SnAccount.fromJson(json['creator_account'] as Map<String, dynamic>),
expiredAt: DateTime.parse(json['expired_at'] as String), expiredAt: DateTime.parse(json['expired_at'] as String),
recipients: recipients: (json['recipients'] as List<dynamic>)
(json['recipients'] as List<dynamic>)
.map((e) => SnWalletFundRecipient.fromJson(e as Map<String, dynamic>)) .map((e) => SnWalletFundRecipient.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
isOpen: json['is_open'] as bool, isOpen: json['is_open'] as bool,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletFundToJson(_SnWalletFund instance) => Map<String, dynamic> _$SnWalletFundToJson(_SnWalletFund instance) =>
<String, dynamic>{ <String, dynamic>{
@@ -386,24 +362,19 @@ _SnWalletFundRecipient _$SnWalletFundRecipientFromJson(
id: json['id'] as String, id: json['id'] as String,
fundId: json['fund_id'] as String, fundId: json['fund_id'] as String,
recipientAccountId: json['recipient_account_id'] as String, recipientAccountId: json['recipient_account_id'] as String,
recipientAccount: recipientAccount: json['recipient_account'] == null
json['recipient_account'] == null ? null
? null : SnAccount.fromJson(json['recipient_account'] as Map<String, dynamic>),
: SnAccount.fromJson(
json['recipient_account'] as Map<String, dynamic>,
),
amount: (json['amount'] as num).toDouble(), amount: (json['amount'] as num).toDouble(),
isReceived: json['is_received'] as bool, isReceived: json['is_received'] as bool,
receivedAt: receivedAt: json['received_at'] == null
json['received_at'] == null ? null
? null : DateTime.parse(json['received_at'] as String),
: DateTime.parse(json['received_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWalletFundRecipientToJson( Map<String, dynamic> _$SnWalletFundRecipientToJson(
@@ -425,33 +396,29 @@ _SnLotteryTicket _$SnLotteryTicketFromJson(Map<String, dynamic> json) =>
_SnLotteryTicket( _SnLotteryTicket(
id: json['id'] as String, id: json['id'] as String,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
account: account: json['account'] == null
json['account'] == null ? null
? null : SnAccount.fromJson(json['account'] as Map<String, dynamic>),
: SnAccount.fromJson(json['account'] as Map<String, dynamic>), regionOneNumbers: (json['region_one_numbers'] as List<dynamic>)
regionOneNumbers: .map((e) => (e as num).toInt())
(json['region_one_numbers'] as List<dynamic>) .toList(),
.map((e) => (e as num).toInt())
.toList(),
regionTwoNumber: (json['region_two_number'] as num).toInt(), regionTwoNumber: (json['region_two_number'] as num).toInt(),
multiplier: (json['multiplier'] as num).toInt(), multiplier: (json['multiplier'] as num).toInt(),
drawStatus: (json['draw_status'] as num).toInt(), drawStatus: (json['draw_status'] as num).toInt(),
drawDate: drawDate: json['draw_date'] == null
json['draw_date'] == null ? null
? null : DateTime.parse(json['draw_date'] as String),
: DateTime.parse(json['draw_date'] as String),
matchedRegionOneNumbers: matchedRegionOneNumbers:
(json['matched_region_one_numbers'] as List<dynamic>?) (json['matched_region_one_numbers'] as List<dynamic>?)
?.map((e) => (e as num).toInt()) ?.map((e) => (e as num).toInt())
.toList(), .toList(),
matchedRegionTwoNumber: matchedRegionTwoNumber: (json['matched_region_two_number'] as num?)
(json['matched_region_two_number'] as num?)?.toInt(), ?.toInt(),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnLotteryTicketToJson(_SnLotteryTicket instance) => Map<String, dynamic> _$SnLotteryTicketToJson(_SnLotteryTicket instance) =>
@@ -471,26 +438,24 @@ Map<String, dynamic> _$SnLotteryTicketToJson(_SnLotteryTicket instance) =>
'deleted_at': instance.deletedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(),
}; };
_SnLotteryRecord _$SnLotteryRecordFromJson(Map<String, dynamic> json) => _SnLotteryRecord _$SnLotteryRecordFromJson(
_SnLotteryRecord( Map<String, dynamic> json,
id: json['id'] as String, ) => _SnLotteryRecord(
drawDate: DateTime.parse(json['draw_date'] as String), id: json['id'] as String,
winningRegionOneNumbers: drawDate: DateTime.parse(json['draw_date'] as String),
(json['winning_region_one_numbers'] as List<dynamic>) winningRegionOneNumbers: (json['winning_region_one_numbers'] as List<dynamic>)
.map((e) => (e as num).toInt()) .map((e) => (e as num).toInt())
.toList(), .toList(),
winningRegionTwoNumber: winningRegionTwoNumber: (json['winning_region_two_number'] as num).toInt(),
(json['winning_region_two_number'] as num).toInt(), totalTickets: (json['total_tickets'] as num).toInt(),
totalTickets: (json['total_tickets'] as num).toInt(), totalPrizesAwarded: (json['total_prizes_awarded'] as num).toInt(),
totalPrizesAwarded: (json['total_prizes_awarded'] as num).toInt(), totalPrizeAmount: (json['total_prize_amount'] as num).toDouble(),
totalPrizeAmount: (json['total_prize_amount'] as num).toDouble(), createdAt: DateTime.parse(json['created_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), deletedAt: json['deleted_at'] == null
deletedAt: ? null
json['deleted_at'] == null : DateTime.parse(json['deleted_at'] as String),
? null );
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnLotteryRecordToJson(_SnLotteryRecord instance) => Map<String, dynamic> _$SnLotteryRecordToJson(_SnLotteryRecord instance) =>
<String, dynamic>{ <String, dynamic>{

View File

@@ -17,14 +17,12 @@ _SnWebFeed _$SnWebFeedFromJson(Map<String, dynamic> json) => _SnWebFeed(
url: json['url'] as String, url: json['url'] as String,
title: json['title'] as String, title: json['title'] as String,
description: json['description'] as String?, description: json['description'] as String?,
preview: preview: json['preview'] == null
json['preview'] == null ? null
? null : SnScrappedLink.fromJson(json['preview'] as Map<String, dynamic>),
: SnScrappedLink.fromJson(json['preview'] as Map<String, dynamic>), config: json['config'] == null
config: ? const SnWebFeedConfig()
json['config'] == null : SnWebFeedConfig.fromJson(json['config'] as Map<String, dynamic>),
? const SnWebFeedConfig()
: SnWebFeedConfig.fromJson(json['config'] as Map<String, dynamic>),
publisherId: json['publisher_id'] as String, publisherId: json['publisher_id'] as String,
articles: articles:
(json['articles'] as List<dynamic>?) (json['articles'] as List<dynamic>?)
@@ -33,10 +31,9 @@ _SnWebFeed _$SnWebFeedFromJson(Map<String, dynamic> json) => _SnWebFeed(
const [], const [],
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWebFeedToJson(_SnWebFeed instance) => Map<String, dynamic> _$SnWebFeedToJson(_SnWebFeed instance) =>
@@ -61,28 +58,22 @@ _SnWebArticle _$SnWebArticleFromJson(Map<String, dynamic> json) =>
url: json['url'] as String, url: json['url'] as String,
author: json['author'] as String?, author: json['author'] as String?,
meta: json['meta'] as Map<String, dynamic>?, meta: json['meta'] as Map<String, dynamic>?,
preview: preview: json['preview'] == null
json['preview'] == null ? null
? null : SnScrappedLink.fromJson(json['preview'] as Map<String, dynamic>),
: SnScrappedLink.fromJson( feed: json['feed'] == null
json['preview'] as Map<String, dynamic>, ? null
), : SnWebFeed.fromJson(json['feed'] as Map<String, dynamic>),
feed:
json['feed'] == null
? null
: SnWebFeed.fromJson(json['feed'] as Map<String, dynamic>),
content: json['content'] as String?, content: json['content'] as String?,
publishedAt: publishedAt: json['published_at'] == null
json['published_at'] == null ? null
? null : DateTime.parse(json['published_at'] as String),
: DateTime.parse(json['published_at'] as String),
feedId: json['feed_id'] as String, feedId: json['feed_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: deletedAt: json['deleted_at'] == null
json['deleted_at'] == null ? null
? null : DateTime.parse(json['deleted_at'] as String),
: DateTime.parse(json['deleted_at'] as String),
); );
Map<String, dynamic> _$SnWebArticleToJson(_SnWebArticle instance) => Map<String, dynamic> _$SnWebArticleToJson(_SnWebArticle instance) =>

View File

@@ -0,0 +1,72 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/paging.dart';
part 'post_list.freezed.dart';
@freezed
sealed class PostListQuery with _$PostListQuery {
const factory PostListQuery({
String? pubName,
String? realm,
int? type,
List<String>? categories,
List<String>? tags,
bool? pinned,
@Default(false) bool shuffle,
bool? includeReplies,
bool? mediaOnly,
String? queryTerm,
String? order,
int? periodStart,
int? periodEnd,
@Default(true) bool orderDesc,
}) = _PostListQuery;
}
final postListNotifierProvider = AsyncNotifierProvider.autoDispose
.family<PostListNotifier, List<SnPost>, PostListQuery>(
PostListNotifier.new,
);
class PostListNotifier extends AsyncNotifier<List<SnPost>>
with AsyncPaginationController<SnPost> {
final PostListQuery arg;
PostListNotifier(this.arg);
static const int pageSize = 20;
@override
Future<List<SnPost>> fetch() async {
final client = ref.read(apiClientProvider);
final queryParams = {
'offset': fetchedCount,
'take': pageSize,
'replies': arg.includeReplies,
'orderDesc': arg.orderDesc,
if (arg.shuffle) 'shuffle': arg.shuffle,
if (arg.pubName != null) 'pub': arg.pubName,
if (arg.realm != null) 'realm': arg.realm,
if (arg.type != null) 'type': arg.type,
if (arg.tags != null) 'tags': arg.tags,
if (arg.categories != null) 'categories': arg.categories,
if (arg.pinned != null) 'pinned': arg.pinned,
if (arg.order != null) 'order': arg.order,
if (arg.periodStart != null) 'periodStart': arg.periodStart,
if (arg.periodEnd != null) 'periodEnd': arg.periodEnd,
if (arg.queryTerm != null) 'query': arg.queryTerm,
if (arg.mediaOnly != null) 'media': arg.mediaOnly,
};
final response = await client.get(
'/sphere/posts',
queryParameters: queryParams,
);
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
final List<dynamic> data = response.data;
return data.map((json) => SnPost.fromJson(json)).toList();
}
}

View File

@@ -10,9 +10,9 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/file_references.dart'; import 'package:island/pods/drive/file_references.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/upload_tasks.dart'; import 'package:island/pods/drive/upload_tasks.dart';
import 'package:island/models/drive_task.dart'; import 'package:island/models/drive_task.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/services/time.dart'; import 'package:island/services/time.dart';
@@ -120,8 +120,9 @@ class FileDetailScreen extends HookConsumerWidget {
child: SizedBox( child: SizedBox(
width: 400, width: 400,
child: Material( child: Material(
color: color: Theme.of(
Theme.of(context).colorScheme.surfaceContainer, context,
).colorScheme.surfaceContainer,
elevation: 8, elevation: 8,
child: FileInfoSheet( child: FileInfoSheet(
item: item, item: item,
@@ -176,17 +177,15 @@ class FileDetailScreen extends HookConsumerWidget {
actions.add( actions.add(
IconButton( IconButton(
icon: Icon(Icons.link), icon: Icon(Icons.link),
onPressed: onPressed: () => showModalBottomSheet(
() => showModalBottomSheet( useRootNavigator: true,
useRootNavigator: true, context: context,
context: context, isScrollControlled: true,
isScrollControlled: true, builder: (context) => SheetScaffold(
builder: titleText: 'File References',
(context) => SheetScaffold( child: ReferencesList(fileId: item.id),
titleText: 'File References', ),
child: ReferencesList(fileId: item.id), ),
),
),
), ),
); );
@@ -300,43 +299,39 @@ class ReferencesList extends ConsumerWidget {
final asyncReferences = ref.watch(fileReferencesProvider(fileId)); final asyncReferences = ref.watch(fileReferencesProvider(fileId));
return asyncReferences.when( return asyncReferences.when(
data: data: (references) => ListView.builder(
(references) => ListView.builder( itemCount: references.length,
itemCount: references.length, itemBuilder: (context, index) {
itemBuilder: (context, index) { final reference = references[index];
final reference = references[index]; return ListTile(
return ListTile( leading: const Icon(Icons.link),
leading: const Icon(Icons.link), title: Row(
title: Row( spacing: 6,
spacing: 6, children: [
children: [ Text(
Text( reference.usage,
reference.usage, style: GoogleFonts.robotoMono(
style: GoogleFonts.robotoMono( fontWeight: FontWeight.bold,
fontWeight: FontWeight.bold, fontSize: 13,
fontSize: 13, ),
),
),
Text(
reference.id,
style: GoogleFonts.robotoMono(fontSize: 13),
),
],
), ),
subtitle: Row( Text(reference.id, style: GoogleFonts.robotoMono(fontSize: 13)),
spacing: 8, ],
children: [ ),
Text(reference.createdAt.formatRelative(context)), subtitle: Row(
const VerticalDivider(width: 1, thickness: 1).height(12), spacing: 8,
Text(reference.createdAt.formatSystem()), children: [
], Text(reference.createdAt.formatRelative(context)),
), const VerticalDivider(width: 1, thickness: 1).height(12),
); Text(reference.createdAt.formatSystem()),
}, ],
), ),
);
},
),
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(child: CircularProgressIndicator()),
error: error: (error, _) =>
(error, _) => Center(child: Text('Error loading references: $error')), Center(child: Text('Error loading references: $error')),
); );
} }
} }

View File

@@ -7,7 +7,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/file_pool.dart'; import 'package:island/models/file_pool.dart';
import 'package:island/pods/file_list.dart'; import 'package:island/pods/drive/file_list.dart';
import 'package:island/services/file_uploader.dart'; import 'package:island/services/file_uploader.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
@@ -40,38 +40,31 @@ class FileListScreen extends HookConsumerWidget {
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Symbols.bar_chart), icon: const Icon(Symbols.bar_chart),
onPressed: onPressed: () =>
() => _showUsageSheet( _showUsageSheet(context, usageAsync.value, quotaAsync.value),
context,
usageAsync.value,
quotaAsync.value,
),
), ),
const Gap(8), const Gap(8),
], ],
), ),
body: usageAsync.when( body: usageAsync.when(
data: data: (usage) => quotaAsync.when(
(usage) => quotaAsync.when( data: (quota) => FileListView(
data: usage: usage,
(quota) => FileListView( quota: quota,
usage: usage, currentPath: currentPath,
quota: quota, selectedPool: selectedPool,
currentPath: currentPath, onPickAndUpload: () => _pickAndUploadFile(
selectedPool: selectedPool, ref,
onPickAndUpload: currentPath.value,
() => _pickAndUploadFile( selectedPool.value?.id,
ref,
currentPath.value,
selectedPool.value?.id,
),
onShowCreateDirectory: _showCreateDirectoryDialog,
mode: mode,
viewMode: viewMode,
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('Error loading quota')),
), ),
onShowCreateDirectory: _showCreateDirectoryDialog,
mode: mode,
viewMode: viewMode,
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('Error loading quota')),
),
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('Error loading usage')), error: (e, _) => Center(child: Text('Error loading usage')),
), ),
@@ -158,44 +151,43 @@ class FileListScreen extends HookConsumerWidget {
await showDialog( await showDialog(
context: context, context: context,
builder: builder: (context) => AlertDialog(
(context) => AlertDialog( title: const Text('Navigate to Directory'),
title: const Text('Navigate to Directory'), content: Column(
content: Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ const Gap(8),
const Gap(8), TextField(
TextField( controller: controller,
controller: controller, decoration: const InputDecoration(
decoration: const InputDecoration( labelText: 'Directory path',
labelText: 'Directory path', hintText: 'e.g., documents, projects/my-app',
hintText: 'e.g., documents, projects/my-app', helperText:
helperText: 'Enter a directory path. The directory will be created when you upload files to it.',
'Enter a directory path. The directory will be created when you upload files to it.', helperMaxLines: 3,
helperMaxLines: 3, border: OutlineInputBorder(
border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onSubmitted: (_) {
handleChangeDirectory(context);
},
), ),
], ),
onSubmitted: (_) {
handleChangeDirectory(context);
},
), ),
actions: [ ],
TextButton( ),
onPressed: () => Navigator.of(context).pop(), actions: [
child: const Text('Cancel'), TextButton(
), onPressed: () => Navigator.of(context).pop(),
TextButton.icon( child: const Text('Cancel'),
onPressed: () => handleChangeDirectory(context),
label: const Text('Go to Directory'),
icon: const Icon(Symbols.arrow_right_alt),
),
],
), ),
TextButton.icon(
onPressed: () => handleChangeDirectory(context),
label: const Text('Go to Directory'),
icon: const Icon(Symbols.arrow_right_alt),
),
],
),
); );
} }
@@ -207,14 +199,13 @@ class FileListScreen extends HookConsumerWidget {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: builder: (context) => SheetScaffold(
(context) => SheetScaffold( titleText: 'Usage Overview',
titleText: 'Usage Overview', child: UsageOverviewWidget(
child: UsageOverviewWidget( usage: usage,
usage: usage, quota: quota,
quota: quota, ).padding(horizontal: 8, vertical: 16),
).padding(horizontal: 8, vertical: 16), ),
),
); );
} }
} }

View File

@@ -18,14 +18,12 @@ _PostComposeInitialState _$PostComposeInitialStateFromJson(
.toList() ?? .toList() ??
const [], const [],
visibility: (json['visibility'] as num?)?.toInt(), visibility: (json['visibility'] as num?)?.toInt(),
replyingTo: replyingTo: json['replying_to'] == null
json['replying_to'] == null ? null
? null : SnPost.fromJson(json['replying_to'] as Map<String, dynamic>),
: SnPost.fromJson(json['replying_to'] as Map<String, dynamic>), forwardingTo: json['forwarding_to'] == null
forwardingTo: ? null
json['forwarding_to'] == null : SnPost.fromJson(json['forwarding_to'] as Map<String, dynamic>),
? null
: SnPost.fromJson(json['forwarding_to'] as Map<String, dynamic>),
); );
Map<String, dynamic> _$PostComposeInitialStateToJson( Map<String, dynamic> _$PostComposeInitialStateToJson(

View File

@@ -7,9 +7,12 @@ import 'package:island/models/post.dart';
import 'package:island/pods/network.dart'; 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_item.dart'; import 'package:island/widgets/post/post_item.dart';
import 'package:island/widgets/posts/post_filter.dart';
import 'package:gap/gap.dart';
import 'package:island/pods/paging.dart'; import 'package:island/pods/paging.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/paging/pagination_list.dart'; import 'package:island/widgets/paging/pagination_list.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
final postSearchProvider = AsyncNotifierProvider.autoDispose( final postSearchProvider = AsyncNotifierProvider.autoDispose(
@@ -36,6 +39,14 @@ class PostSearchNotifier extends AsyncNotifier<List<SnPost>>
return []; return [];
} }
bool? _includeReplies;
bool _mediaOnly = false;
String? _queryTerm;
String? _order;
bool _orderDesc = true;
int? _periodStart;
int? _periodEnd;
Future<void> search( Future<void> search(
String query, { String query, {
String? pubName, String? pubName,
@@ -45,6 +56,13 @@ class PostSearchNotifier extends AsyncNotifier<List<SnPost>>
List<String>? tags, List<String>? tags,
bool shuffle = false, bool shuffle = false,
bool? pinned, bool? pinned,
bool? includeReplies,
bool mediaOnly = false,
String? queryTerm,
String? order,
bool orderDesc = true,
int? periodStart,
int? periodEnd,
}) async { }) async {
_currentQuery = query.trim(); _currentQuery = query.trim();
_pubName = pubName; _pubName = pubName;
@@ -54,6 +72,13 @@ class PostSearchNotifier extends AsyncNotifier<List<SnPost>>
_tags = tags; _tags = tags;
_shuffle = shuffle; _shuffle = shuffle;
_pinned = pinned; _pinned = pinned;
_includeReplies = includeReplies;
_mediaOnly = mediaOnly;
_queryTerm = queryTerm;
_order = order;
_orderDesc = orderDesc;
_periodStart = periodStart;
_periodEnd = periodEnd;
final hasFilters = final hasFilters =
pubName != null || pubName != null ||
@@ -62,7 +87,13 @@ class PostSearchNotifier extends AsyncNotifier<List<SnPost>>
categories != null || categories != null ||
tags != null || tags != null ||
shuffle || shuffle ||
pinned != null; pinned != null ||
includeReplies != null ||
mediaOnly ||
queryTerm != null ||
order != null ||
periodStart != null ||
periodEnd != null;
if (_currentQuery.isEmpty && !hasFilters) { if (_currentQuery.isEmpty && !hasFilters) {
state = const AsyncData([]); state = const AsyncData([]);
@@ -91,6 +122,13 @@ class PostSearchNotifier extends AsyncNotifier<List<SnPost>>
if (_categories != null) 'categories': _categories, if (_categories != null) 'categories': _categories,
if (_shuffle) 'shuffle': true, if (_shuffle) 'shuffle': true,
if (_pinned != null) 'pinned': _pinned, if (_pinned != null) 'pinned': _pinned,
if (_includeReplies != null) 'includeReplies': _includeReplies,
if (_mediaOnly) 'mediaOnly': true,
if (_queryTerm != null) 'queryTerm': _queryTerm,
if (_order != null) 'order': _order,
if (_orderDesc) 'orderDesc': true,
if (_periodStart != null) 'periodStart': _periodStart,
if (_periodEnd != null) 'periodEnd': _periodEnd,
}, },
); );
@@ -117,6 +155,17 @@ class PostSearchScreen extends HookConsumerWidget {
final shuffleValue = useState(false); final shuffleValue = useState(false);
final pinnedValue = useState<bool?>(null); final pinnedValue = useState<bool?>(null);
// State variables for PostFilterWidget
final categoryTabController = useTabController(initialLength: 3);
final includeReplies = useState<bool?>(null);
final mediaOnly = useState(false);
final queryTerm = useState<String?>(null);
final order = useState<String?>('date');
final orderDesc = useState(true);
final periodStart = useState<int?>(null);
final periodEnd = useState<int?>(null);
final showAdvancedFilters = useState(false);
useEffect(() { useEffect(() {
return () { return () {
searchController.dispose(); searchController.dispose();
@@ -130,7 +179,21 @@ class PostSearchScreen extends HookConsumerWidget {
if (debounceTimer.value?.isActive ?? false) debounceTimer.value!.cancel(); if (debounceTimer.value?.isActive ?? false) debounceTimer.value!.cancel();
debounceTimer.value = Timer(debounce, () { debounceTimer.value = Timer(debounce, () {
ref.read(postSearchProvider.notifier).search(query); ref
.read(postSearchProvider.notifier)
.search(
query,
type: categoryTabController.index == 1
? 0
: (categoryTabController.index == 2 ? 1 : null),
includeReplies: includeReplies.value,
mediaOnly: mediaOnly.value,
queryTerm: queryTerm.value,
order: order.value,
orderDesc: orderDesc.value,
periodStart: periodStart.value,
periodEnd: periodEnd.value,
);
}); });
} }
@@ -142,20 +205,28 @@ class PostSearchScreen extends HookConsumerWidget {
.read(postSearchProvider.notifier) .read(postSearchProvider.notifier)
.search( .search(
query, query,
pubName: pubName: pubNameController.text.isNotEmpty
pubNameController.text.isNotEmpty ? pubNameController.text
? pubNameController.text : null,
: null, realm: realmController.text.isNotEmpty
realm: ? realmController.text
realmController.text.isNotEmpty ? realmController.text : null, : null,
type: typeValue.value, type: categoryTabController.index == 1
categories: ? 0
selectedCategories.value.isNotEmpty : (categoryTabController.index == 2 ? 1 : null),
? selectedCategories.value categories: selectedCategories.value.isNotEmpty
: null, ? selectedCategories.value
: null,
tags: selectedTags.value.isNotEmpty ? selectedTags.value : null, tags: selectedTags.value.isNotEmpty ? selectedTags.value : null,
shuffle: shuffleValue.value, shuffle: shuffleValue.value,
pinned: pinnedValue.value, pinned: pinnedValue.value,
includeReplies: includeReplies.value,
mediaOnly: mediaOnly.value,
queryTerm: queryTerm.value,
order: order.value,
orderDesc: orderDesc.value,
periodStart: periodStart.value,
periodEnd: periodEnd.value,
); );
}); });
} }
@@ -164,187 +235,213 @@ class PostSearchScreen extends HookConsumerWidget {
showFilters.value = !showFilters.value; showFilters.value = !showFilters.value;
} }
void applyFilters() {
onSearchWithFilters(searchController.text);
}
void clearFilters() {
pubNameController.clear();
realmController.clear();
typeValue.value = null;
selectedCategories.value = [];
selectedTags.value = [];
shuffleValue.value = false;
pinnedValue.value = null;
onSearchChanged(searchController.text);
}
Widget buildFilterPanel() { Widget buildFilterPanel() {
return Card( return PostFilterWidget(
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 8), categoryTabController: categoryTabController,
child: Padding( includeReplies: includeReplies,
padding: EdgeInsets.all(16), mediaOnly: mediaOnly,
child: Column( queryTerm: queryTerm,
crossAxisAlignment: CrossAxisAlignment.start, order: order,
children: [ orderDesc: orderDesc,
Row( periodStart: periodStart,
mainAxisAlignment: MainAxisAlignment.spaceBetween, periodEnd: periodEnd,
children: [ showAdvancedFilters: showAdvancedFilters,
Text( hideSearch: true,
'filters'.tr(),
style: Theme.of(context).textTheme.titleMedium,
).padding(left: 4),
Row(
children: [
TextButton(
onPressed: applyFilters,
child: Text('apply'.tr()),
),
TextButton(
onPressed: clearFilters,
child: Text('clear'.tr()),
),
],
),
],
),
SizedBox(height: 16),
TextField(
controller: pubNameController,
decoration: InputDecoration(
labelText: 'pubName'.tr(),
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
),
onChanged:
(value) => onSearchWithFilters(searchController.text),
),
SizedBox(height: 8),
TextField(
controller: realmController,
decoration: InputDecoration(
labelText: 'realm'.tr(),
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
),
onChanged:
(value) => onSearchWithFilters(searchController.text),
),
SizedBox(height: 8),
Row(
children: [
Checkbox(
value: shuffleValue.value,
onChanged: (value) {
shuffleValue.value = value ?? false;
onSearchWithFilters(searchController.text);
},
),
Text('shuffle'.tr()),
],
),
Row(
children: [
Checkbox(
value: pinnedValue.value ?? false,
onChanged: (value) {
pinnedValue.value = value;
onSearchWithFilters(searchController.text);
},
),
Text('pinned'.tr()),
],
),
],
),
),
); );
} }
return AppScaffold( return AppScaffold(
isNoBackground: false, isNoBackground: false,
appBar: AppBar( appBar: isWideScreen(context)
title: Row( ? null
children: [ : AppBar(
Expanded( title: Row(
child: TextField( children: [
controller: searchController, Expanded(
decoration: InputDecoration( child: TextField(
hintText: 'search'.tr(), controller: searchController,
border: InputBorder.none, decoration: InputDecoration(
hintStyle: TextStyle( hintText: 'search'.tr(),
color: Theme.of(context).appBarTheme.foregroundColor, border: InputBorder.none,
hintStyle: TextStyle(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
style: TextStyle(
color: Theme.of(context).appBarTheme.foregroundColor,
),
onChanged: onSearchChanged,
onSubmitted: (value) {
onSearchWithFilters(value);
},
autofocus: true,
),
), ),
), IconButton(
style: TextStyle( icon: Icon(
color: Theme.of(context).appBarTheme.foregroundColor, showFilters.value
), ? Icons.filter_alt
onChanged: onSearchChanged, : Icons.filter_alt_outlined,
onSubmitted: (value) { ),
onSearchWithFilters(value); onPressed: toggleFilters,
}, tooltip: 'toggleFilters'.tr(),
autofocus: true, ),
],
), ),
), ),
IconButton(
icon: Icon(
showFilters.value
? Icons.filter_alt
: Icons.filter_alt_outlined,
),
onPressed: toggleFilters,
tooltip: 'toggleFilters'.tr(),
),
],
),
),
body: Consumer( body: Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
final searchState = ref.watch(postSearchProvider); final searchState = ref.watch(postSearchProvider);
return CustomScrollView( return isWideScreen(context)
slivers: [ ? Row(
if (showFilters.value) children: [
SliverToBoxAdapter( Flexible(
child: Center( flex: 4,
child: ConstrainedBox( child: CustomScrollView(
constraints: const BoxConstraints(maxWidth: 600), slivers: [
child: buildFilterPanel(), SliverGap(16),
SliverToBoxAdapter(
child: SearchBar(
elevation: WidgetStateProperty.all(4),
controller: searchController,
hintText: 'search'.tr(),
leading: const Icon(Icons.search),
padding: WidgetStateProperty.all(
const EdgeInsets.symmetric(horizontal: 24),
),
onChanged: onSearchChanged,
onSubmitted: (value) {
onSearchWithFilters(value);
},
),
),
const SliverGap(16),
if (showFilters.value && !isWideScreen(context))
SliverToBoxAdapter(child: buildFilterPanel()),
// Use PaginationList with isSliver=true
PaginationList(
provider: postSearchProvider,
notifier: postSearchProvider.notifier,
isSliver: true,
isRefreshable: false,
itemBuilder: (context, index, post) {
return Card(
margin: EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
child: PostActionableItem(
item: post,
borderRadius: 8,
),
);
},
),
if (searchState.value?.isEmpty == true &&
searchController.text.isNotEmpty &&
!searchState.isLoading)
SliverFillRemaining(
child: Center(child: Text('noResultsFound'.tr())),
),
SliverGap(MediaQuery.of(context).padding.bottom + 16),
],
).padding(left: 8),
), ),
), Flexible(
), flex: 3,
// Use PaginationList with isSliver=true child: Align(
PaginationList( alignment: Alignment.topLeft,
provider: postSearchProvider, child: SingleChildScrollView(
notifier: postSearchProvider.notifier, child: Column(
isSliver: true, crossAxisAlignment: CrossAxisAlignment.stretch,
isRefreshable: children: [
false, // CustomScrollView handles refreshing usually, but here we don't have PullToRefresh Gap(16),
itemBuilder: (context, index, post) { Card(
return Center( margin: EdgeInsets.symmetric(horizontal: 8),
child: ConstrainedBox( child: Padding(
constraints: BoxConstraints(maxWidth: 600), padding: const EdgeInsets.symmetric(
child: Card( horizontal: 12,
margin: EdgeInsets.symmetric( vertical: 8,
horizontal: 8, ),
vertical: 4, child: Row(
children: [
const Icon(
Symbols.tune,
).padding(horizontal: 8),
Expanded(
child: Text(
'filters'.tr(),
style: Theme.of(
context,
).textTheme.bodyLarge,
),
),
IconButton(
icon: Icon(
Symbols.filter_alt,
fill: showFilters.value ? 1 : null,
),
onPressed: toggleFilters,
tooltip: 'toggleFilters'.tr(),
),
const Gap(4),
],
),
),
),
const Gap(8),
if (showFilters.value) buildFilterPanel(),
],
),
), ),
child: PostActionableItem(item: post, borderRadius: 8),
), ),
), ),
); ],
}, )
), : CustomScrollView(
if (searchState.value?.isEmpty == true && slivers: [
searchController.text.isNotEmpty && if (showFilters.value)
!searchState.isLoading) SliverToBoxAdapter(
SliverFillRemaining( child: Center(
child: Center(child: Text('noResultsFound'.tr())), child: ConstrainedBox(
), constraints: const BoxConstraints(maxWidth: 600),
], child: buildFilterPanel(),
); ),
),
),
// Use PaginationList with isSliver=true
PaginationList(
provider: postSearchProvider,
notifier: postSearchProvider.notifier,
isSliver: true,
isRefreshable: false,
itemBuilder: (context, index, post) {
return Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600),
child: Card(
margin: EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
child: PostActionableItem(
item: post,
borderRadius: 8,
),
),
),
);
},
),
if (searchState.value?.isEmpty == true &&
searchController.text.isNotEmpty &&
!searchState.isLoading)
SliverFillRemaining(
child: Center(child: Text('noResultsFound'.tr())),
),
],
);
}, },
), ),
); );

View File

@@ -22,6 +22,7 @@ import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/content/markdown.dart'; import 'package:island/widgets/content/markdown.dart';
import 'package:island/widgets/post/post_list.dart'; import 'package:island/widgets/post/post_list.dart';
import 'package:island/widgets/activity_heatmap.dart'; import 'package:island/widgets/activity_heatmap.dart';
import 'package:island/widgets/posts/post_filter.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:island/services/color_extraction.dart'; import 'package:island/services/color_extraction.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -82,8 +83,9 @@ class _PublisherBasisWidget extends StatelessWidget {
size: 12, size: 12,
color: Theme.of(context).colorScheme.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
), ),
backgroundColor: backgroundColor: Theme.of(
Theme.of(context).colorScheme.primary, context,
).colorScheme.primary,
offset: Offset(0, 48), offset: Offset(0, 48),
child: ProfilePictureWidget( child: ProfilePictureWidget(
file: data.picture, file: data.picture,
@@ -121,8 +123,9 @@ class _PublisherBasisWidget extends StatelessWidget {
size: 16, size: 16,
color: Theme.of(context).colorScheme.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
), ),
backgroundColor: backgroundColor: Theme.of(
Theme.of(context).colorScheme.primary, context,
).colorScheme.primary,
offset: Offset(0, 48), offset: Offset(0, 48),
child: ProfilePictureWidget( child: ProfilePictureWidget(
file: data.picture, file: data.picture,
@@ -201,45 +204,41 @@ class _PublisherBasisWidget extends StatelessWidget {
), ),
subStatus subStatus
.when( .when(
data: data: (status) => FilledButton.icon(
(status) => FilledButton.icon( onPressed: subscribing.value
onPressed: ? null
subscribing.value : (status.isSubscribed
? null ? unsubscribe
: (status.isSubscribed : subscribe),
? unsubscribe icon: Icon(
: subscribe), status.isSubscribed
icon: Icon( ? Symbols.remove_circle
status.isSubscribed : Symbols.add_circle,
? Symbols.remove_circle ),
: Symbols.add_circle, label: Text(
), status.isSubscribed
label: ? 'unsubscribe'
Text( : 'subscribe',
status.isSubscribed ).tr(),
? 'unsubscribe' style: ButtonStyle(
: 'subscribe', visualDensity: VisualDensity(
).tr(), vertical: -2,
style: ButtonStyle(
visualDensity: VisualDensity(
vertical: -2,
),
),
), ),
),
),
error: (_, _) => const SizedBox(), error: (_, _) => const SizedBox(),
loading: loading: () => const SizedBox(
() => const SizedBox( height: 36,
height: 36, child: Center(
child: Center( child: SizedBox(
child: SizedBox( width: 20,
width: 20, height: 20,
height: 20, child: CircularProgressIndicator(
child: CircularProgressIndicator( strokeWidth: 2,
strokeWidth: 2,
),
),
), ),
), ),
),
),
) )
.padding(vertical: 12), .padding(vertical: 12),
], ],
@@ -271,10 +270,10 @@ class _PublisherBadgesWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return (badges.value?.isNotEmpty ?? false) return (badges.value?.isNotEmpty ?? false)
? Card( ? Card(
child: BadgeList( child: BadgeList(
badges: badges.value!, badges: badges.value!,
).padding(horizontal: 26, vertical: 20), ).padding(horizontal: 26, vertical: 20),
).padding(horizontal: 4) ).padding(horizontal: 4)
: const SizedBox.shrink(); : const SizedBox.shrink();
} }
} }
@@ -288,9 +287,9 @@ class _PublisherVerificationWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return (data.verification != null) return (data.verification != null)
? Card( ? Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4), margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: VerificationStatusCard(mark: data.verification!), child: VerificationStatusCard(mark: data.verification!),
) )
: const SizedBox.shrink(); : const SizedBox.shrink();
} }
} }
@@ -333,14 +332,12 @@ class _PublisherHeatmapWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return heatmap.when( return heatmap.when(
data: data: (data) => data != null
(data) => ? ActivityHeatmapWidget(
data != null heatmap: data,
? ActivityHeatmapWidget( forceDense: forceDense,
heatmap: data, ).padding(horizontal: 8)
forceDense: forceDense, : const SizedBox.shrink(),
).padding(horizontal: 8)
: const SizedBox.shrink(),
loading: () => const SizedBox.shrink(), loading: () => const SizedBox.shrink(),
error: (_, _) => const SizedBox.shrink(), error: (_, _) => const SizedBox.shrink(),
); );
@@ -372,242 +369,16 @@ class _PublisherCategoryTabWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return PostFilterWidget(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4), categoryTabController: categoryTabController,
child: Column( includeReplies: includeReplies,
children: [ mediaOnly: mediaOnly,
TabBar( queryTerm: queryTerm,
controller: categoryTabController, order: order,
dividerColor: Colors.transparent, orderDesc: orderDesc,
splashBorderRadius: const BorderRadius.all(Radius.circular(8)), periodStart: periodStart,
tabs: [ periodEnd: periodEnd,
Tab(text: 'all'.tr()), showAdvancedFilters: showAdvancedFilters,
Tab(text: 'postTypePost'.tr()),
Tab(text: 'postArticle'.tr()),
],
),
const Divider(height: 1),
Column(
children: [
Row(
children: [
Expanded(
child: CheckboxListTile(
title: Text('reply'.tr()),
value: includeReplies.value,
tristate: true,
onChanged: (value) {
// Cycle through: null -> false -> true -> null
if (includeReplies.value == null) {
includeReplies.value = false;
} else if (includeReplies.value == false) {
includeReplies.value = true;
} else {
includeReplies.value = null;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.reply),
),
),
Expanded(
child: CheckboxListTile(
title: Text('attachments'.tr()),
value: mediaOnly.value,
onChanged: (value) {
if (value != null) {
mediaOnly.value = value;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.attachment),
),
),
],
),
CheckboxListTile(
title: Text('descendingOrder'.tr()),
value: orderDesc.value,
onChanged: (value) {
if (value != null) {
orderDesc.value = value;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.sort),
),
],
),
const Divider(height: 1),
ListTile(
title: Text('advancedFilters'.tr()),
leading: const Icon(Symbols.filter_list),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(const Radius.circular(8)),
),
trailing: Icon(
showAdvancedFilters.value
? Symbols.expand_less
: Symbols.expand_more,
),
onTap: () {
showAdvancedFilters.value = !showAdvancedFilters.value;
},
),
if (showAdvancedFilters.value) ...[
const Divider(height: 1),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
decoration: InputDecoration(
labelText: 'search'.tr(),
hintText: 'searchPosts'.tr(),
prefixIcon: const Icon(Symbols.search),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
),
onChanged: (value) {
queryTerm.value = value.isEmpty ? null : value;
},
),
const Gap(12),
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'sortBy'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
),
value: order.value,
items: [
DropdownMenuItem(value: 'date', child: Text('date'.tr())),
DropdownMenuItem(
value: 'popularity',
child: Text('popularity'.tr()),
),
],
onChanged: (value) {
order.value = value;
},
),
const Gap(12),
Row(
children: [
Expanded(
child: InkWell(
onTap: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate:
periodStart.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodStart.value! * 1000,
)
: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime.now().add(
const Duration(days: 365),
),
);
if (pickedDate != null) {
periodStart.value =
pickedDate.millisecondsSinceEpoch ~/ 1000;
}
},
child: InputDecorator(
decoration: InputDecoration(
labelText: 'fromDate'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
suffixIcon: const Icon(Symbols.calendar_today),
),
child: Text(
periodStart.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodStart.value! * 1000,
).toString().split(' ')[0]
: 'selectDate'.tr(),
),
),
),
),
const Gap(8),
Expanded(
child: InkWell(
onTap: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate:
periodEnd.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodEnd.value! * 1000,
)
: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime.now().add(
const Duration(days: 365),
),
);
if (pickedDate != null) {
periodEnd.value =
pickedDate.millisecondsSinceEpoch ~/ 1000;
}
},
child: InputDecorator(
decoration: InputDecoration(
labelText: 'toDate'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
suffixIcon: const Icon(Symbols.calendar_today),
),
child: Text(
periodEnd.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodEnd.value! * 1000,
).toString().split(' ')[0]
: 'selectDate'.tr(),
),
),
),
),
],
),
],
),
),
],
],
),
); );
} }
} }
@@ -739,205 +510,34 @@ class PublisherProfileScreen extends HookConsumerWidget {
); );
return publisher.when( return publisher.when(
data: data: (data) => AppScaffold(
(data) => AppScaffold( isNoBackground: false,
isNoBackground: false, appBar: isWideScreen(context)
appBar: ? AppBar(
isWideScreen(context) foregroundColor: appbarColor.value,
? AppBar( leading: PageBackButton(
foregroundColor: appbarColor.value, color: appbarColor.value,
leading: PageBackButton( shadows: [appbarShadow],
color: appbarColor.value, ),
shadows: [appbarShadow], title: Text(
), data.nick,
title: Text( style: TextStyle(
data.nick, color:
style: TextStyle( appbarColor.value ??
color: Theme.of(context).appBarTheme.foregroundColor,
appbarColor.value ?? shadows: [appbarShadow],
Theme.of(context).appBarTheme.foregroundColor, ),
shadows: [appbarShadow], ),
), )
), : null,
) body: isWideScreen(context)
: null, ? Row(
body: children: [
isWideScreen(context) Flexible(
? Row( flex: 4,
children: [ child: CustomScrollView(
Flexible(
flex: 4,
child: CustomScrollView(
slivers: [
SliverGap(16),
SliverToBoxAdapter(
child: Card(
margin: EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
child: ListTile(
title: Text('pinnedPosts'.tr()),
leading: const Icon(Symbols.push_pin),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
trailing: Icon(
isPinnedExpanded.value
? Symbols.expand_less
: Symbols.expand_more,
),
onTap:
() =>
isPinnedExpanded.value =
!isPinnedExpanded.value,
),
),
),
...[
if (isPinnedExpanded.value)
SliverPostList(pubName: name, pinned: true),
],
SliverToBoxAdapter(
child: _PublisherCategoryTabWidget(
categoryTabController: categoryTabController,
includeReplies: includeReplies,
mediaOnly: mediaOnly,
queryTerm: queryTerm,
order: order,
orderDesc: orderDesc,
periodStart: periodStart,
periodEnd: periodEnd,
showAdvancedFilters: showAdvancedFilters,
),
),
SliverPostList(
key: ValueKey(
'${categoryTab.value}-${includeReplies.value}-${mediaOnly.value}-${queryTerm.value}-${order.value}-${orderDesc.value}-${periodStart.value}-${periodEnd.value}',
),
pubName: name,
pinned: false,
type:
categoryTab.value == 1
? 0
: (categoryTab.value == 2 ? 1 : null),
includeReplies: includeReplies.value,
mediaOnly: mediaOnly.value,
queryTerm: queryTerm.value,
order: order.value,
orderDesc: orderDesc.value,
periodStart: periodStart.value,
periodEnd: periodEnd.value,
),
SliverGap(
MediaQuery.of(context).padding.bottom + 16,
),
],
).padding(left: 8),
),
Flexible(
flex: 3,
child: Align(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_PublisherBasisWidget(
data: data,
subStatus: subStatus,
subscribing: subscribing,
subscribe: subscribe,
unsubscribe: unsubscribe,
).padding(horizontal: 4, top: 20),
_PublisherBadgesWidget(
data: data,
badges: badges,
),
_PublisherVerificationWidget(data: data),
_PublisherBioWidget(data: data),
_PublisherHeatmapWidget(
heatmap: heatmap,
forceDense: true,
).padding(vertical: 4),
],
),
),
),
),
],
)
: CustomScrollView(
slivers: [ slivers: [
SliverAppBar( SliverGap(16),
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
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:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
background:
Container(), // Empty container since background is handled by Stack
),
],
),
),
SliverToBoxAdapter(
child: _PublisherBasisWidget(
data: data,
subStatus: subStatus,
subscribing: subscribing,
subscribe: subscribe,
unsubscribe: unsubscribe,
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _PublisherBadgesWidget(
data: data,
badges: badges,
),
),
SliverToBoxAdapter(
child: _PublisherVerificationWidget(data: data),
),
SliverToBoxAdapter(
child: _PublisherBioWidget(data: data),
),
SliverToBoxAdapter(
child: _PublisherHeatmapWidget(
heatmap: heatmap,
).padding(vertical: 4),
),
SliverToBoxAdapter( SliverToBoxAdapter(
child: Card( child: Card(
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
@@ -946,15 +546,19 @@ class PublisherProfileScreen extends HookConsumerWidget {
), ),
child: ListTile( child: ListTile(
title: Text('pinnedPosts'.tr()), title: Text('pinnedPosts'.tr()),
leading: const Icon(Symbols.push_pin),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
trailing: Icon( trailing: Icon(
isPinnedExpanded.value isPinnedExpanded.value
? Symbols.expand_less ? Symbols.expand_less
: Symbols.expand_more, : Symbols.expand_more,
), ),
onTap: onTap: () => isPinnedExpanded.value =
() => !isPinnedExpanded.value,
isPinnedExpanded.value =
!isPinnedExpanded.value,
), ),
), ),
), ),
@@ -981,10 +585,9 @@ class PublisherProfileScreen extends HookConsumerWidget {
), ),
pubName: name, pubName: name,
pinned: false, pinned: false,
type: type: categoryTab.value == 1
categoryTab.value == 1 ? 0
? 0 : (categoryTab.value == 2 ? 1 : null),
: (categoryTab.value == 2 ? 1 : null),
includeReplies: includeReplies.value, includeReplies: includeReplies.value,
mediaOnly: mediaOnly.value, mediaOnly: mediaOnly.value,
queryTerm: queryTerm.value, queryTerm: queryTerm.value,
@@ -995,20 +598,158 @@ class PublisherProfileScreen extends HookConsumerWidget {
), ),
SliverGap(MediaQuery.of(context).padding.bottom + 16), SliverGap(MediaQuery.of(context).padding.bottom + 16),
], ],
).padding(left: 8),
),
Flexible(
flex: 3,
child: Align(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_PublisherBasisWidget(
data: data,
subStatus: subStatus,
subscribing: subscribing,
subscribe: subscribe,
unsubscribe: unsubscribe,
).padding(horizontal: 4, top: 20),
_PublisherBadgesWidget(data: data, badges: badges),
_PublisherVerificationWidget(data: data),
_PublisherBioWidget(data: data),
_PublisherHeatmapWidget(
heatmap: heatmap,
forceDense: true,
).padding(vertical: 4),
],
),
),
), ),
), ),
error: ],
(error, stackTrace) => AppScaffold( )
isNoBackground: false, : CustomScrollView(
appBar: AppBar(leading: const PageBackButton()), slivers: [
body: Center(child: Text(error.toString())), SliverAppBar(
), foregroundColor: appbarColor.value,
loading: expandedHeight: 180,
() => AppScaffold( pinned: true,
isNoBackground: false, leading: PageBackButton(
appBar: AppBar(leading: const PageBackButton()), color: appbarColor.value,
body: Center(child: CircularProgressIndicator()), shadows: [appbarShadow],
), ),
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:
appbarColor.value ??
Theme.of(context).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
background:
Container(), // Empty container since background is handled by Stack
),
],
),
),
SliverToBoxAdapter(
child: _PublisherBasisWidget(
data: data,
subStatus: subStatus,
subscribing: subscribing,
subscribe: subscribe,
unsubscribe: unsubscribe,
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _PublisherBadgesWidget(data: data, badges: badges),
),
SliverToBoxAdapter(
child: _PublisherVerificationWidget(data: data),
),
SliverToBoxAdapter(child: _PublisherBioWidget(data: data)),
SliverToBoxAdapter(
child: _PublisherHeatmapWidget(
heatmap: heatmap,
).padding(vertical: 4),
),
SliverToBoxAdapter(
child: Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: ListTile(
title: Text('pinnedPosts'.tr()),
trailing: Icon(
isPinnedExpanded.value
? Symbols.expand_less
: Symbols.expand_more,
),
onTap: () =>
isPinnedExpanded.value = !isPinnedExpanded.value,
),
),
),
...[
if (isPinnedExpanded.value)
SliverPostList(pubName: name, pinned: true),
],
SliverToBoxAdapter(
child: _PublisherCategoryTabWidget(
categoryTabController: categoryTabController,
includeReplies: includeReplies,
mediaOnly: mediaOnly,
queryTerm: queryTerm,
order: order,
orderDesc: orderDesc,
periodStart: periodStart,
periodEnd: periodEnd,
showAdvancedFilters: showAdvancedFilters,
),
),
SliverPostList(
key: ValueKey(
'${categoryTab.value}-${includeReplies.value}-${mediaOnly.value}-${queryTerm.value}-${order.value}-${orderDesc.value}-${periodStart.value}-${periodEnd.value}',
),
pubName: name,
pinned: false,
type: categoryTab.value == 1
? 0
: (categoryTab.value == 2 ? 1 : null),
includeReplies: includeReplies.value,
mediaOnly: mediaOnly.value,
queryTerm: queryTerm.value,
order: order.value,
orderDesc: orderDesc.value,
periodStart: periodStart.value,
periodEnd: periodEnd.value,
),
SliverGap(MediaQuery.of(context).padding.bottom + 16),
],
),
),
error: (error, stackTrace) => AppScaffold(
isNoBackground: false,
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: Text(error.toString())),
),
loading: () => AppScaffold(
isNoBackground: false,
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: CircularProgressIndicator()),
),
); );
} }
} }

View File

@@ -21,7 +21,7 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/file_pool.dart'; import 'package:island/pods/drive/file_pool.dart';
class SettingsScreen extends HookConsumerWidget { class SettingsScreen extends HookConsumerWidget {
const SettingsScreen({super.key}); const SettingsScreen({super.key});
@@ -249,10 +249,9 @@ class SettingsScreen extends HookConsumerWidget {
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
Color selectedColor = Color selectedColor = settings.appColorScheme != null
settings.appColorScheme != null ? Color(settings.appColorScheme!)
? Color(settings.appColorScheme!) : Colors.indigo;
: Colors.indigo;
return AlertDialog( return AlertDialog(
title: Text('Seed Color').tr(), title: Text('Seed Color').tr(),
@@ -292,10 +291,9 @@ class SettingsScreen extends HookConsumerWidget {
height: 24, height: 24,
margin: EdgeInsets.symmetric(horizontal: 2, vertical: 8), margin: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: settings.appColorScheme != null
settings.appColorScheme != null ? Color(settings.appColorScheme!)
? Color(settings.appColorScheme!) : Colors.indigo,
: Colors.indigo,
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: Theme.of( color: Theme.of(
@@ -310,19 +308,17 @@ class SettingsScreen extends HookConsumerWidget {
// Custom colors section // Custom colors section
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
child: child: Text(
Text( 'Custom Colors',
'Custom Colors', style: Theme.of(context).textTheme.titleMedium,
style: Theme.of(context).textTheme.titleMedium, ).bold(),
).bold(),
), ),
// Primary color // Primary color
_ColorPickerTile( _ColorPickerTile(
title: 'Primary', title: 'Primary',
color: color: settings.customColors?.primary != null
settings.customColors?.primary != null ? Color(settings.customColors!.primary!)
? Color(settings.customColors!.primary!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -333,10 +329,9 @@ class SettingsScreen extends HookConsumerWidget {
// Secondary // Secondary
_ColorPickerTile( _ColorPickerTile(
title: 'Secondary', title: 'Secondary',
color: color: settings.customColors?.secondary != null
settings.customColors?.secondary != null ? Color(settings.customColors!.secondary!)
? Color(settings.customColors!.secondary!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -347,10 +342,9 @@ class SettingsScreen extends HookConsumerWidget {
// Tertiary // Tertiary
_ColorPickerTile( _ColorPickerTile(
title: 'Tertiary', title: 'Tertiary',
color: color: settings.customColors?.tertiary != null
settings.customColors?.tertiary != null ? Color(settings.customColors!.tertiary!)
? Color(settings.customColors!.tertiary!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -361,10 +355,9 @@ class SettingsScreen extends HookConsumerWidget {
// Surface // Surface
_ColorPickerTile( _ColorPickerTile(
title: 'Surface', title: 'Surface',
color: color: settings.customColors?.surface != null
settings.customColors?.surface != null ? Color(settings.customColors!.surface!)
? Color(settings.customColors!.surface!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -375,10 +368,9 @@ class SettingsScreen extends HookConsumerWidget {
// Background // Background
_ColorPickerTile( _ColorPickerTile(
title: 'Background', title: 'Background',
color: color: settings.customColors?.background != null
settings.customColors?.background != null ? Color(settings.customColors!.background!)
? Color(settings.customColors!.background!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -391,10 +383,9 @@ class SettingsScreen extends HookConsumerWidget {
// Error // Error
_ColorPickerTile( _ColorPickerTile(
title: 'Error', title: 'Error',
color: color: settings.customColors?.error != null
settings.customColors?.error != null ? Color(settings.customColors!.error!)
? Color(settings.customColors!.error!) : null,
: null,
onColorChanged: (color) { onColorChanged: (color) {
final current = settings.customColors ?? ThemeColors(); final current = settings.customColors ?? ThemeColors();
ref ref
@@ -509,8 +500,9 @@ class SettingsScreen extends HookConsumerWidget {
// Background image enabled // Background image enabled
if (!kIsWeb && docBasepath.value != null) if (!kIsWeb && docBasepath.value != null)
FutureBuilder<bool>( FutureBuilder<bool>(
future: future: File(
File('${docBasepath.value}/$kAppBackgroundImagePath').exists(), '${docBasepath.value}/$kAppBackgroundImagePath',
).exists(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData || !snapshot.data!) { if (!snapshot.hasData || !snapshot.data!) {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -536,8 +528,9 @@ class SettingsScreen extends HookConsumerWidget {
// Clear background image option // Clear background image option
if (!kIsWeb && docBasepath.value != null) if (!kIsWeb && docBasepath.value != null)
FutureBuilder<bool>( FutureBuilder<bool>(
future: future: File(
File('${docBasepath.value}/$kAppBackgroundImagePath').exists(), '${docBasepath.value}/$kAppBackgroundImagePath',
).exists(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData || !snapshot.data!) { if (!snapshot.hasData || !snapshot.data!) {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -565,8 +558,9 @@ class SettingsScreen extends HookConsumerWidget {
if (!kIsWeb && docBasepath.value != null) if (!kIsWeb && docBasepath.value != null)
FutureBuilder( FutureBuilder(
future: future: File(
File('${docBasepath.value}/$kAppBackgroundImagePath').exists(), '${docBasepath.value}/$kAppBackgroundImagePath',
).exists(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData || !snapshot.data!) { if (!snapshot.hasData || !snapshot.data!) {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -598,8 +592,8 @@ class SettingsScreen extends HookConsumerWidget {
); );
final color = final color =
MediaQuery.of(context).platformBrightness == Brightness.dark MediaQuery.of(context).platformBrightness == Brightness.dark
? colorScheme.primary ? colorScheme.primary
: colorScheme.primary; : colorScheme.primary;
ref ref
.read(appSettingsProvider.notifier) .read(appSettingsProvider.notifier)
.setAppColorScheme(color.value); .setAppColorScheme(color.value);
@@ -674,20 +668,19 @@ class SettingsScreen extends HookConsumerWidget {
trailing: DropdownButtonHideUnderline( trailing: DropdownButtonHideUnderline(
child: DropdownButton2<String>( child: DropdownButton2<String>(
isExpanded: true, isExpanded: true,
items: items: validPools.map((p) {
validPools.map((p) { return DropdownMenuItem<String>(
return DropdownMenuItem<String>( value: p.id,
value: p.id, child: Tooltip(
child: Tooltip( message: p.name,
message: p.name, child: Text(
child: Text( p.name,
p.name, maxLines: 1,
maxLines: 1, overflow: TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, ).fontSize(14),
).fontSize(14), ),
), );
); }).toList(),
}).toList(),
value: currentPoolId, value: currentPoolId,
onChanged: (value) { onChanged: (value) {
ref ref
@@ -705,19 +698,17 @@ class SettingsScreen extends HookConsumerWidget {
), ),
); );
}, },
loading: loading: () => const ListTile(
() => const ListTile( minLeadingWidth: 48,
minLeadingWidth: 48, title: Text('Loading pools...'),
title: Text('Loading pools...'), leading: CircularProgressIndicator(),
leading: CircularProgressIndicator(), ),
), error: (err, st) => ListTile(
error: minLeadingWidth: 48,
(err, st) => ListTile( title: Text('settingsDefaultPool').tr(),
minLeadingWidth: 48, subtitle: Text('Error: $err'),
title: Text('settingsDefaultPool').tr(), leading: const Icon(Icons.error, color: Colors.red),
subtitle: Text('Error: $err'), ),
leading: const Icon(Icons.error, color: Colors.red),
),
), ),
]; ];
@@ -767,10 +758,9 @@ class SettingsScreen extends HookConsumerWidget {
ListTile( ListTile(
minLeadingWidth: 48, minLeadingWidth: 48,
title: Text('settingsEnterToSend').tr(), title: Text('settingsEnterToSend').tr(),
subtitle: subtitle: isDesktop
isDesktop ? Text('settingsEnterToSendDesktopHint').tr().fontSize(12)
? Text('settingsEnterToSendDesktopHint').tr().fontSize(12) : null,
: null,
contentPadding: const EdgeInsets.only(left: 24, right: 17), contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.send), leading: const Icon(Symbols.send),
trailing: Switch( trailing: Switch(
@@ -823,33 +813,32 @@ class SettingsScreen extends HookConsumerWidget {
]; ];
// Desktop-specific settings // Desktop-specific settings
final desktopSettings = final desktopSettings = !isDesktop
!isDesktop ? <Widget>[]
? <Widget>[] : [
: [ ListTile(
ListTile( minLeadingWidth: 48,
minLeadingWidth: 48, title: Text('settingsWindowOpacity').tr(),
title: Text('settingsWindowOpacity').tr(), contentPadding: const EdgeInsets.only(left: 24, right: 17),
contentPadding: const EdgeInsets.only(left: 24, right: 17), leading: const Icon(Symbols.opacity),
leading: const Icon(Symbols.opacity), subtitle: Padding(
subtitle: Padding( padding: const EdgeInsets.only(top: 8),
padding: const EdgeInsets.only(top: 8), child: Slider(
child: Slider( value: settings.windowOpacity,
value: settings.windowOpacity, min: 0.1,
min: 0.1, max: 1.0,
max: 1.0, year2023: true,
year2023: true, padding: EdgeInsets.only(right: 24),
padding: EdgeInsets.only(right: 24), label: '${(settings.windowOpacity * 100).round()}%',
label: '${(settings.windowOpacity * 100).round()}%', onChanged: (value) {
onChanged: (value) { ref
ref .read(appSettingsProvider.notifier)
.read(appSettingsProvider.notifier) .setWindowOpacity(value);
.setWindowOpacity(value); },
},
),
), ),
), ),
]; ),
];
// Create a responsive layout based on screen width // Create a responsive layout based on screen width
Widget buildSettingsList() { Widget buildSettingsList() {

View File

@@ -7,7 +7,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/upload_tasks.dart'; import 'package:island/pods/drive/upload_tasks.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:native_exif/native_exif.dart'; import 'package:native_exif/native_exif.dart';
import 'package:path/path.dart' show extension; import 'package:path/path.dart' show extension;
@@ -211,8 +211,9 @@ class FileUploader {
// Use old way for Uint8List // Use old way for Uint8List
final chunks = <Uint8List>[]; final chunks = <Uint8List>[];
for (int i = 0; i < fileData.length; i += chunkSize) { for (int i = 0; i < fileData.length; i += chunkSize) {
final end = final end = i + chunkSize > fileData.length
i + chunkSize > fileData.length ? fileData.length : i + chunkSize; ? fileData.length
: i + chunkSize;
chunks.add(Uint8List.fromList(fileData.sublist(i, end))); chunks.add(Uint8List.fromList(fileData.sublist(i, end)));
} }

View File

@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/file_pool.dart'; import 'package:island/models/file_pool.dart';
import 'package:island/pods/file_pool.dart'; import 'package:island/pods/drive/file_pool.dart';
import 'package:island/widgets/content/attachment_preview.dart'; import 'package:island/widgets/content/attachment_preview.dart';
import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/post/compose_shared.dart'; import 'package:island/widgets/post/compose_shared.dart';
@@ -79,13 +79,12 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
children: [ children: [
DropdownButtonFormField<String>( DropdownButtonFormField<String>(
value: selectedPoolId, value: selectedPoolId,
items: items: pools.map((pool) {
pools.map((pool) { return DropdownMenuItem<String>(
return DropdownMenuItem<String>( value: pool.id,
value: pool.id, child: Text(pool.name),
child: Text(pool.name), );
); }).toList(),
}).toList(),
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
selectedPoolId = value; selectedPoolId = value;
@@ -140,10 +139,9 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
Container( Container(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: Theme.of(
Theme.of( context,
context, ).colorScheme.errorContainer,
).colorScheme.errorContainer,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Column( child: Column(
@@ -155,23 +153,22 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
Icon( Icon(
Symbols.warning, Symbols.warning,
size: 18, size: 18,
color: color: Theme.of(
Theme.of( context,
context, ).colorScheme.error,
).colorScheme.error,
), ),
const Gap(8), const Gap(8),
Text( Text(
'uploadConstraints'.tr(), 'uploadConstraints'.tr(),
style: Theme.of( style: Theme.of(context)
context, .textTheme
).textTheme.bodyMedium?.copyWith( .bodyMedium
color: ?.copyWith(
Theme.of( color: Theme.of(
context, context,
).colorScheme.error, ).colorScheme.error,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
], ],
), ),
@@ -183,28 +180,28 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
_formatFileSize(maxFileSize), _formatFileSize(maxFileSize),
], ],
), ),
style: Theme.of( style: Theme.of(context)
context, .textTheme
).textTheme.bodySmall?.copyWith( .bodySmall
color: ?.copyWith(
Theme.of( color: Theme.of(
context, context,
).colorScheme.error, ).colorScheme.error,
), ),
), ),
], ],
if (!typeAccepted) ...[ if (!typeAccepted) ...[
const Gap(4), const Gap(4),
Text( Text(
'fileTypeNotAccepted'.tr(), 'fileTypeNotAccepted'.tr(),
style: Theme.of( style: Theme.of(context)
context, .textTheme
).textTheme.bodySmall?.copyWith( .bodySmall
color: ?.copyWith(
Theme.of( color: Theme.of(
context, context,
).colorScheme.error, ).colorScheme.error,
), ),
), ),
], ],
], ],
@@ -229,10 +226,9 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
), ),
], ],
), ),
style: style: Theme.of(
Theme.of( context,
context, ).textTheme.bodyMedium,
).textTheme.bodyMedium,
).fontSize(13), ).fontSize(13),
), ),
], ],
@@ -300,8 +296,8 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> {
final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?; final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?;
final fileSizeExceeded = maxFileSize != null && fileSize > maxFileSize; final fileSizeExceeded = maxFileSize != null && fileSize > maxFileSize;
final acceptTypes = final acceptTypes = (selectedPool.policyConfig?['accept_types'] as List?)
(selectedPool.policyConfig?['accept_types'] as List?)?.cast<String>(); ?.cast<String>();
final mimeType = final mimeType =
attachment.data.mimeType ?? attachment.data.mimeType ??
ComposeLogic.getMimeTypeFromFileType(attachment.type); ComposeLogic.getMimeTypeFromFileType(attachment.type);

View File

@@ -12,8 +12,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file_list_item.dart'; import 'package:island/models/file_list_item.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/file_pool.dart'; import 'package:island/models/file_pool.dart';
import 'package:island/pods/file_list.dart'; import 'package:island/pods/drive/file_list.dart';
import 'package:island/pods/file_pool.dart'; import 'package:island/pods/drive/file_pool.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/services/file_uploader.dart'; import 'package:island/services/file_uploader.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
@@ -123,45 +123,39 @@ class FileListView extends HookConsumerWidget {
notifier: unindexedFileListProvider.notifier, notifier: unindexedFileListProvider.notifier,
isRefreshable: false, isRefreshable: false,
isSliver: true, isSliver: true,
contentBuilder: contentBuilder: (data, footer) => data.isEmpty
(data, footer) => ? SliverToBoxAdapter(child: _buildEmptyUnindexedFilesHint(ref))
data.isEmpty : _buildUnindexedFileListContent(
? SliverToBoxAdapter( data,
child: _buildEmptyUnindexedFilesHint(ref), ref,
) context,
: _buildUnindexedFileListContent( viewMode,
data, isSelectionMode,
ref, selectedFileIds,
context, currentVisibleItems,
viewMode, footer,
isSelectionMode, ),
selectedFileIds,
currentVisibleItems,
footer,
),
), ),
_ => PaginationWidget( _ => PaginationWidget(
provider: indexedCloudFileListProvider, provider: indexedCloudFileListProvider,
notifier: indexedCloudFileListProvider.notifier, notifier: indexedCloudFileListProvider.notifier,
isRefreshable: false, isRefreshable: false,
isSliver: true, isSliver: true,
contentBuilder: contentBuilder: (data, footer) => data.isEmpty
(data, footer) => ? SliverToBoxAdapter(
data.isEmpty child: _buildEmptyDirectoryHint(ref, currentPath),
? SliverToBoxAdapter( )
child: _buildEmptyDirectoryHint(ref, currentPath), : _buildFileListContent(
) data,
: _buildFileListContent( ref,
data, context,
ref, currentPath,
context, viewMode,
currentPath, isSelectionMode,
viewMode, selectedFileIds,
isSelectionMode, currentVisibleItems,
selectedFileIds, footer,
currentVisibleItems, ),
footer,
),
), ),
}; };
@@ -177,11 +171,10 @@ class FileListView extends HookConsumerWidget {
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
); );
} else { } else {
final pathParts = final pathParts = currentPath.value
currentPath.value .split('/')
.split('/') .where((part) => part.isNotEmpty)
.where((part) => part.isNotEmpty) .toList();
.toList();
final breadcrumbs = <Widget>[]; final breadcrumbs = <Widget>[];
// Add root // Add root
@@ -266,10 +259,9 @@ class FileListView extends HookConsumerWidget {
dragging.value = false; dragging.value = false;
}, },
child: Container( child: Container(
color: color: dragging.value
dragging.value ? Theme.of(context).primaryColor.withOpacity(0.1)
? Theme.of(context).primaryColor.withOpacity(0.1) : null,
: null,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -302,28 +294,25 @@ class FileListView extends HookConsumerWidget {
? Symbols.arrow_back ? Symbols.arrow_back
: Symbols.folder, : Symbols.folder,
), ),
onPressed: onPressed: isRefreshing
isRefreshing ? null
? null : () {
: () { if (mode.value == FileListMode.unindexed) {
if (mode.value == FileListMode.unindexed) { mode.value = FileListMode.normal;
mode.value = FileListMode.normal; currentPath.value = '/';
currentPath.value = '/'; } else {
} else { final pathParts = currentPath.value
final pathParts = .split('/')
currentPath.value .where((part) => part.isNotEmpty)
.split('/') .toList();
.where((part) => part.isNotEmpty) if (pathParts.isNotEmpty) {
.toList(); pathParts.removeLast();
if (pathParts.isNotEmpty) { currentPath.value = pathParts.isEmpty
pathParts.removeLast(); ? '/'
currentPath.value = : '/${pathParts.join('/')}';
pathParts.isEmpty
? '/'
: '/${pathParts.join('/')}';
}
} }
}, }
},
visualDensity: const VisualDensity( visualDensity: const VisualDensity(
horizontal: -4, horizontal: -4,
vertical: -4, vertical: -4,
@@ -342,16 +331,13 @@ class FileListView extends HookConsumerWidget {
? Symbols.view_module ? Symbols.view_module
: Symbols.list, : Symbols.list,
), ),
onPressed: onPressed: () => viewMode.value =
() =>
viewMode.value =
viewMode.value == FileListViewMode.list
? FileListViewMode.waterfall
: FileListViewMode.list,
tooltip:
viewMode.value == FileListViewMode.list viewMode.value == FileListViewMode.list
? 'Switch to Waterfall View' ? FileListViewMode.waterfall
: 'Switch to List View', : FileListViewMode.list,
tooltip: viewMode.value == FileListViewMode.list
? 'Switch to Waterfall View'
: 'Switch to List View',
visualDensity: const VisualDensity( visualDensity: const VisualDensity(
horizontal: -4, horizontal: -4,
vertical: -4, vertical: -4,
@@ -363,12 +349,11 @@ class FileListView extends HookConsumerWidget {
? Symbols.close ? Symbols.close
: Symbols.select_check_box, : Symbols.select_check_box,
), ),
onPressed: onPressed: () =>
() => isSelectionMode.value = !isSelectionMode.value, isSelectionMode.value = !isSelectionMode.value,
tooltip: tooltip: isSelectionMode.value
isSelectionMode.value ? 'Exit Selection Mode'
? 'Exit Selection Mode' : 'Enter Selection Mode',
: 'Enter Selection Mode',
visualDensity: const VisualDensity( visualDensity: const VisualDensity(
horizontal: -4, horizontal: -4,
vertical: -4, vertical: -4,
@@ -377,9 +362,8 @@ class FileListView extends HookConsumerWidget {
if (mode.value == FileListMode.normal) if (mode.value == FileListMode.normal)
IconButton( IconButton(
icon: const Icon(Symbols.create_new_folder), icon: const Icon(Symbols.create_new_folder),
onPressed: onPressed: () =>
() => onShowCreateDirectory(ref.context, currentPath),
onShowCreateDirectory(ref.context, currentPath),
tooltip: 'Create Directory', tooltip: 'Create Directory',
visualDensity: const VisualDensity( visualDensity: const VisualDensity(
horizontal: -4, horizontal: -4,
@@ -397,10 +381,9 @@ class FileListView extends HookConsumerWidget {
recycled.value = !recycled.value; recycled.value = !recycled.value;
unindexedNotifier.setRecycled(recycled.value); unindexedNotifier.setRecycled(recycled.value);
}, },
tooltip: tooltip: recycled.value
recycled.value ? 'Show Active Files'
? 'Show Active Files' : 'Show Recycle Bin',
: 'Show Recycle Bin',
visualDensity: const VisualDensity( visualDensity: const VisualDensity(
horizontal: -4, horizontal: -4,
vertical: -4, vertical: -4,
@@ -429,12 +412,14 @@ class FileListView extends HookConsumerWidget {
if (mode.value == FileListMode.normal && currentPath.value == '/') if (mode.value == FileListMode.normal && currentPath.value == '/')
_buildUnindexedFilesEntry(ref).padding(bottom: 12), _buildUnindexedFilesEntry(ref).padding(bottom: 12),
Expanded( Expanded(
child: CustomScrollView( child:
slivers: [bodyWidget, const SliverGap(12)], CustomScrollView(
).padding( slivers: [bodyWidget, const SliverGap(12)],
horizontal: ).padding(
viewMode.value == FileListViewMode.waterfall ? 12 : null, horizontal: viewMode.value == FileListViewMode.waterfall
), ? 12
: null,
),
), ),
if (isSelectionMode.value) if (isSelectionMode.value)
Material( Material(
@@ -457,16 +442,15 @@ class FileListView extends HookConsumerWidget {
const Gap(12), const Gap(12),
OutlinedButton( OutlinedButton(
onPressed: () { onPressed: () {
final allIds = final allIds = currentVisibleItems.value
currentVisibleItems.value .expand(
.expand( (item) => item.maybeMap(
(item) => item.maybeMap( file: (f) => [f.fileIndex.id],
file: (f) => [f.fileIndex.id], unindexedFile: (u) => [u.file.id],
unindexedFile: (u) => [u.file.id], orElse: () => <String>[],
orElse: () => <String>[], ),
), )
) .toSet();
.toSet();
if (allIds if (allIds
.difference(selectedFileIds.value) .difference(selectedFileIds.value)
@@ -482,16 +466,16 @@ class FileListView extends HookConsumerWidget {
currentVisibleItems.value.isEmpty currentVisibleItems.value.isEmpty
? 'Select All' ? 'Select All'
: currentVisibleItems.value : currentVisibleItems.value
.expand( .expand(
(item) => item.maybeMap( (item) => item.maybeMap(
file: (f) => [f.fileIndex.id], file: (f) => [f.fileIndex.id],
unindexedFile: (u) => [u.file.id], unindexedFile: (u) => [u.file.id],
orElse: () => <String>[], orElse: () => <String>[],
), ),
) )
.toSet() .toSet()
.difference(selectedFileIds.value) .difference(selectedFileIds.value)
.isEmpty .isEmpty
? 'Deselect All' ? 'Deselect All'
: 'Select All', : 'Select All',
), ),
@@ -502,47 +486,46 @@ class FileListView extends HookConsumerWidget {
ElevatedButton.icon( ElevatedButton.icon(
icon: const Icon(Symbols.delete), icon: const Icon(Symbols.delete),
label: const Text('Delete'), label: const Text('Delete'),
onPressed: onPressed: selectedFileIds.value.isNotEmpty
selectedFileIds.value.isNotEmpty ? () async {
? () async { final confirmed = await showConfirmAlert(
final confirmed = await showConfirmAlert( 'Are you sure you want to delete the selected files?',
'Are you sure you want to delete the selected files?', 'Delete Selected Files',
'Delete Selected Files', isDanger: true,
isDanger: true, );
if (!confirmed) return;
if (context.mounted) {
showLoadingModal(context);
}
try {
final client = ref.read(apiClientProvider);
final resp = await client.post(
'/drive/files/batches/delete',
data: {
'file_ids': selectedFileIds.value
.toList(),
},
); );
if (!confirmed) return; final count = resp.data['count'] as int;
selectedFileIds.value.clear();
isSelectionMode.value = false;
ref.invalidate(
mode.value == FileListMode.normal
? indexedCloudFileListProvider
: unindexedFileListProvider,
);
showSnackBar('Deleted $count files.');
} catch (e) {
showSnackBar(
'Failed to delete selected files.',
);
} finally {
if (context.mounted) { if (context.mounted) {
showLoadingModal(context); hideLoadingModal(context);
}
try {
final client = ref.read(apiClientProvider);
final resp = await client.post(
'/drive/files/batches/delete',
data: {
'file_ids':
selectedFileIds.value.toList(),
},
);
final count = resp.data['count'] as int;
selectedFileIds.value.clear();
isSelectionMode.value = false;
ref.invalidate(
mode.value == FileListMode.normal
? indexedCloudFileListProvider
: unindexedFileListProvider,
);
showSnackBar('Deleted $count files.');
} catch (e) {
showSnackBar(
'Failed to delete selected files.',
);
} finally {
if (context.mounted) {
hideLoadingModal(context);
}
} }
} }
: null, }
: null,
), ),
], ],
), ),
@@ -584,26 +567,24 @@ class FileListView extends HookConsumerWidget {
final item = items[index]; final item = items[index];
return item.map( return item.map(
file: file: (fileItem) => _buildWaterfallFileTile(
(fileItem) => _buildWaterfallFileTile( fileItem,
fileItem, ref,
ref, context,
context, isSelectionMode.value,
isSelectionMode.value, selectedFileIds.value.contains(fileItem.fileIndex.id),
selectedFileIds.value.contains(fileItem.fileIndex.id), () {
() { if (selectedFileIds.value.contains(fileItem.fileIndex.id)) {
if (selectedFileIds.value.contains(fileItem.fileIndex.id)) { selectedFileIds.value = Set.from(selectedFileIds.value)
selectedFileIds.value = Set.from(selectedFileIds.value) ..remove(fileItem.fileIndex.id);
..remove(fileItem.fileIndex.id); } else {
} else { selectedFileIds.value = Set.from(selectedFileIds.value)
selectedFileIds.value = Set.from(selectedFileIds.value) ..add(fileItem.fileIndex.id);
..add(fileItem.fileIndex.id); }
} },
}, ),
), folder: (folderItem) =>
folder: _buildWaterfallFolderTile(folderItem, currentPath, context),
(folderItem) =>
_buildWaterfallFolderTile(folderItem, currentPath, context),
unindexedFile: (unindexedFileItem) { unindexedFile: (unindexedFileItem) {
// Should not happen // Should not happen
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -620,47 +601,44 @@ class FileListView extends HookConsumerWidget {
} }
final item = items[index]; final item = items[index];
return item.map( return item.map(
file: file: (fileItem) => _buildIndexedListTile(
(fileItem) => _buildIndexedListTile( fileItem,
fileItem, ref,
ref, context,
context, isSelectionMode.value,
isSelectionMode.value, selectedFileIds.value.contains(fileItem.fileIndex.id),
selectedFileIds.value.contains(fileItem.fileIndex.id), () {
() { if (selectedFileIds.value.contains(fileItem.fileIndex.id)) {
if (selectedFileIds.value.contains(fileItem.fileIndex.id)) { selectedFileIds.value = Set.from(selectedFileIds.value)
selectedFileIds.value = Set.from(selectedFileIds.value) ..remove(fileItem.fileIndex.id);
..remove(fileItem.fileIndex.id); } else {
} else { selectedFileIds.value = Set.from(selectedFileIds.value)
selectedFileIds.value = Set.from(selectedFileIds.value) ..add(fileItem.fileIndex.id);
..add(fileItem.fileIndex.id); }
} },
}, ),
), folder: (folderItem) => ListTile(
folder: leading: ClipRRect(
(folderItem) => ListTile( borderRadius: const BorderRadius.all(Radius.circular(8)),
leading: ClipRRect( child: SizedBox(
borderRadius: const BorderRadius.all(Radius.circular(8)), height: 48,
child: SizedBox( width: 48,
height: 48, child: const Icon(Symbols.folder, fill: 1).center(),
width: 48,
child: const Icon(Symbols.folder, fill: 1).center(),
),
),
title: Text(
folderItem.folderName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: const Text('folder').tr(),
onTap: () {
final newPath =
currentPath.value == '/'
? '/${folderItem.folderName}'
: '${currentPath.value}/${folderItem.folderName}';
currentPath.value = newPath;
},
), ),
),
title: Text(
folderItem.folderName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: const Text('folder').tr(),
onTap: () {
final newPath = currentPath.value == '/'
? '/${folderItem.folderName}'
: '${currentPath.value}/${folderItem.folderName}';
currentPath.value = newPath;
},
),
unindexedFile: (unindexedFileItem) { unindexedFile: (unindexedFileItem) {
// Should not happen in normal mode // Should not happen in normal mode
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -705,10 +683,9 @@ class FileListView extends HookConsumerWidget {
ValueNotifier<String> currentPath, ValueNotifier<String> currentPath,
) { ) {
return Card( return Card(
margin: margin: viewMode.value == FileListViewMode.waterfall
viewMode.value == FileListViewMode.waterfall ? const EdgeInsets.fromLTRB(0, 0, 0, 16)
? const EdgeInsets.fromLTRB(0, 0, 0, 16) : const EdgeInsets.fromLTRB(12, 0, 12, 16),
: const EdgeInsets.fromLTRB(12, 0, 12, 16),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 48), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 48),
child: Column( child: Column(
@@ -748,8 +725,8 @@ class FileListView extends HookConsumerWidget {
), ),
const Gap(12), const Gap(12),
OutlinedButton.icon( OutlinedButton.icon(
onPressed: onPressed: () =>
() => onShowCreateDirectory(ref.context, currentPath), onShowCreateDirectory(ref.context, currentPath),
icon: const Icon(Symbols.create_new_folder), icon: const Icon(Symbols.create_new_folder),
label: const Text('Create Directory'), label: const Text('Create Directory'),
), ),
@@ -822,8 +799,9 @@ class FileListView extends HookConsumerWidget {
VoidCallback? toggleSelection, VoidCallback? toggleSelection,
) { ) {
final meta = file.fileMeta is Map ? (file.fileMeta as Map) : const {}; final meta = file.fileMeta is Map ? (file.fileMeta as Map) : const {};
final ratio = final ratio = meta['ratio'] is num
meta['ratio'] is num ? (meta['ratio'] as num).toDouble() : 1.0; ? (meta['ratio'] as num).toDouble()
: 1.0;
final itemType = file.mimeType?.split('/').first; final itemType = file.mimeType?.split('/').first;
final uri = final uri =
'${ref.read(apiClientProvider).options.baseUrl}/drive/files/${file.id}'; '${ref.read(apiClientProvider).options.baseUrl}/drive/files/${file.id}';
@@ -851,22 +829,20 @@ class FileListView extends HookConsumerWidget {
.read(apiClientProvider) .read(apiClientProvider)
.get(uri) .get(uri)
.then((response) => response.data as String), .then((response) => response.data as String),
builder: builder: (context, snapshot) => snapshot.hasData
(context, snapshot) => ? SingleChildScrollView(
snapshot.hasData padding: EdgeInsets.all(24),
? SingleChildScrollView( child: Text(
padding: EdgeInsets.all(24), snapshot.data!,
child: Text( style: const TextStyle(
snapshot.data!, fontSize: 9,
style: const TextStyle( fontFamily: 'monospace',
fontSize: 9, ),
fontFamily: 'monospace', maxLines: 20,
), overflow: TextOverflow.ellipsis,
maxLines: 20, ),
overflow: TextOverflow.ellipsis, )
), : const Center(child: CircularProgressIndicator()),
)
: const Center(child: CircularProgressIndicator()),
), ),
); );
break; break;
@@ -961,10 +937,9 @@ class FileListView extends HookConsumerWidget {
return InkWell( return InkWell(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
onTap: () { onTap: () {
final newPath = final newPath = currentPath.value == '/'
currentPath.value == '/' ? '/${folderItem.folderName}'
? '/${folderItem.folderName}' : '${currentPath.value}/${folderItem.folderName}';
: '${currentPath.value}/${folderItem.folderName}';
currentPath.value = newPath; currentPath.value = newPath;
}, },
child: Container( child: Container(
@@ -1038,8 +1013,8 @@ class FileListView extends HookConsumerWidget {
// Should not happen in unindexed mode // Should not happen in unindexed mode
return const SizedBox.shrink(); return const SizedBox.shrink();
}, },
unindexedFile: unindexedFile: (unindexedFileItem) =>
(unindexedFileItem) => _buildWaterfallUnindexedFileTile( _buildWaterfallUnindexedFileTile(
unindexedFileItem, unindexedFileItem,
ref, ref,
context, context,
@@ -1077,25 +1052,22 @@ class FileListView extends HookConsumerWidget {
// Should not happen in unindexed mode // Should not happen in unindexed mode
return const SizedBox.shrink(); return const SizedBox.shrink();
}, },
unindexedFile: unindexedFile: (unindexedFileItem) => _buildUnindexedListTile(
(unindexedFileItem) => _buildUnindexedListTile( unindexedFileItem,
unindexedFileItem, ref,
ref, context,
context, isSelectionMode.value,
isSelectionMode.value, selectedFileIds.value.contains(unindexedFileItem.file.id),
selectedFileIds.value.contains(unindexedFileItem.file.id), () {
() { if (selectedFileIds.value.contains(unindexedFileItem.file.id)) {
if (selectedFileIds.value.contains( selectedFileIds.value = Set.from(selectedFileIds.value)
unindexedFileItem.file.id, ..remove(unindexedFileItem.file.id);
)) { } else {
selectedFileIds.value = Set.from(selectedFileIds.value) selectedFileIds.value = Set.from(selectedFileIds.value)
..remove(unindexedFileItem.file.id); ..add(unindexedFileItem.file.id);
} else { }
selectedFileIds.value = Set.from(selectedFileIds.value) },
..add(unindexedFileItem.file.id); ),
}
},
),
); );
}, },
), ),
@@ -1130,10 +1102,9 @@ class FileListView extends HookConsumerWidget {
), ),
], ],
), ),
title: title: file.name.isEmpty
file.name.isEmpty ? Text('untitled').tr().italic()
? Text('untitled').tr().italic() : Text(file.name, maxLines: 1, overflow: TextOverflow.ellipsis),
: Text(file.name, maxLines: 1, overflow: TextOverflow.ellipsis),
subtitle: Text(formatFileSize(file.size)), subtitle: Text(formatFileSize(file.size)),
onTap: () { onTap: () {
if (isSelectionMode) { if (isSelectionMode) {
@@ -1199,10 +1170,9 @@ class FileListView extends HookConsumerWidget {
), ),
], ],
), ),
title: title: file.name.isEmpty
file.name.isEmpty ? Text('untitled').tr().italic()
? Text('untitled').tr().italic() : Text(file.name, maxLines: 1, overflow: TextOverflow.ellipsis),
: Text(file.name, maxLines: 1, overflow: TextOverflow.ellipsis),
subtitle: Text(formatFileSize(file.size)), subtitle: Text(formatFileSize(file.size)),
onTap: () { onTap: () {
if (isSelectionMode) { if (isSelectionMode) {
@@ -1289,10 +1259,9 @@ class FileListView extends HookConsumerWidget {
Widget _buildEmptyUnindexedFilesHint(WidgetRef ref) { Widget _buildEmptyUnindexedFilesHint(WidgetRef ref) {
return Card( return Card(
margin: margin: viewMode.value == FileListViewMode.waterfall
viewMode.value == FileListViewMode.waterfall ? EdgeInsets.zero
? EdgeInsets.zero : const EdgeInsets.fromLTRB(12, 0, 12, 0),
: const EdgeInsets.fromLTRB(12, 0, 12, 0),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 48), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 48),
child: Column( child: Column(
@@ -1395,19 +1364,18 @@ class FileListView extends HookConsumerWidget {
ObjectRef<Timer?> queryDebounceTimer, ObjectRef<Timer?> queryDebounceTimer,
) { ) {
final poolDropdownItems = poolsAsync.when( final poolDropdownItems = poolsAsync.when(
data: data: (pools) => [
(pools) => [ const DropdownMenuItem<SnFilePool>(
const DropdownMenuItem<SnFilePool>( value: null,
value: null, child: Text('All Pools', style: TextStyle(fontSize: 14)),
child: Text('All Pools', style: TextStyle(fontSize: 14)), ),
), ...pools.map(
...pools.map( (p) => DropdownMenuItem<SnFilePool>(
(p) => DropdownMenuItem<SnFilePool>( value: p,
value: p, child: Text(p.name, style: const TextStyle(fontSize: 14)),
child: Text(p.name, style: const TextStyle(fontSize: 14)), ),
), ),
), ],
],
loading: () => const <DropdownMenuItem<SnFilePool>>[], loading: () => const <DropdownMenuItem<SnFilePool>>[],
error: (err, stack) => const <DropdownMenuItem<SnFilePool>>[], error: (err, stack) => const <DropdownMenuItem<SnFilePool>>[],
); );
@@ -1416,17 +1384,16 @@ class FileListView extends HookConsumerWidget {
child: DropdownButton2<SnFilePool>( child: DropdownButton2<SnFilePool>(
value: selectedPool.value, value: selectedPool.value,
items: poolDropdownItems, items: poolDropdownItems,
onChanged: onChanged: isRefreshing
isRefreshing ? null
? null : (value) {
: (value) { selectedPool.value = value;
selectedPool.value = value; if (mode.value == FileListMode.unindexed) {
if (mode.value == FileListMode.unindexed) { unindexedNotifier.setPool(value?.id);
unindexedNotifier.setPool(value?.id); } else {
} else { cloudNotifier.setPool(value?.id);
cloudNotifier.setPool(value?.id); }
} },
},
customButton: Container( customButton: Container(
height: 28, height: 28,
width: 200, width: 200,
@@ -1493,19 +1460,17 @@ class FileListView extends HookConsumerWidget {
final orderDropdown = DropdownButtonHideUnderline( final orderDropdown = DropdownButtonHideUnderline(
child: DropdownButton2<String>( child: DropdownButton2<String>(
value: order.value, value: order.value,
items: items: ['date', 'size', 'name']
['date', 'size', 'name'] .map(
.map( (e) => DropdownMenuItem(
(e) => DropdownMenuItem( value: e,
value: e, child: Text(
child: e == 'date' ? e : 'file${e.capitalizeEachWord()}',
Text( style: const TextStyle(fontSize: 14),
e == 'date' ? e : 'file${e.capitalizeEachWord()}', ).tr(),
style: const TextStyle(fontSize: 14), ),
).tr(), )
), .toList(),
)
.toList(),
onChanged: (value) => order.value = value, onChanged: (value) => order.value = value,
customButton: Container( customButton: Container(
height: 28, height: 28,
@@ -1517,13 +1482,12 @@ class FileListView extends HookConsumerWidget {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Center( child: Center(
child: child: Text(
Text( (order.value ?? 'date') == 'date'
(order.value ?? 'date') == 'date' ? (order.value ?? 'date')
? (order.value ?? 'date') : 'file${order.value?.capitalizeEachWord()}',
: 'file${order.value?.capitalizeEachWord()}', style: const TextStyle(fontSize: 12),
style: const TextStyle(fontSize: 12), ).tr(),
).tr(),
), ),
), ),
buttonStyleData: const ButtonStyleData( buttonStyleData: const ButtonStyleData(

View File

@@ -24,7 +24,7 @@ import 'package:island/widgets/post/compose_link_attachments.dart';
import 'package:island/widgets/post/compose_poll.dart'; import 'package:island/widgets/post/compose_poll.dart';
import 'package:island/widgets/post/compose_fund.dart'; import 'package:island/widgets/post/compose_fund.dart';
import 'package:island/widgets/post/compose_recorder.dart'; import 'package:island/widgets/post/compose_recorder.dart';
import 'package:island/pods/file_pool.dart'; import 'package:island/pods/drive/file_pool.dart';
import 'package:pasteboard/pasteboard.dart'; import 'package:pasteboard/pasteboard.dart';
import 'package:island/talker.dart'; import 'package:island/talker.dart';
@@ -108,8 +108,8 @@ class ComposeLogic {
String? pollId; String? pollId;
String? fundId; String? fundId;
if (originalPost?.meta?['embeds'] is List) { if (originalPost?.meta?['embeds'] is List) {
final embeds = final embeds = (originalPost!.meta!['embeds'] as List)
(originalPost!.meta!['embeds'] as List).cast<Map<String, dynamic>>(); .cast<Map<String, dynamic>>();
try { try {
final pollEmbed = embeds.firstWhere((e) => e['type'] == 'poll'); final pollEmbed = embeds.firstWhere((e) => e['type'] == 'poll');
pollId = pollEmbed['id']; pollId = pollEmbed['id'];
@@ -202,11 +202,10 @@ class ComposeLogic {
final attachment = state.attachments.value[i]; final attachment = state.attachments.value[i];
if (attachment.data is! SnCloudFile) { if (attachment.data is! SnCloudFile) {
try { try {
final cloudFile = final cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile( ref: ref,
ref: ref, fileData: attachment,
fileData: attachment, ).future;
).future;
if (cloudFile != null) { if (cloudFile != null) {
// Update attachments list with cloud file // Update attachments list with cloud file
final clone = List.of(state.attachments.value); final clone = List.of(state.attachments.value);
@@ -242,11 +241,10 @@ class ComposeLogic {
repliedPost: null, repliedPost: null,
forwardedPostId: null, forwardedPostId: null,
forwardedPost: null, forwardedPost: null,
attachments: attachments: state.attachments.value
state.attachments.value .map((e) => e.data)
.map((e) => e.data) .whereType<SnCloudFile>()
.whereType<SnCloudFile>() .toList(),
.toList(),
publisher: SnPublisher( publisher: SnPublisher(
id: '', id: '',
type: 0, type: 0,
@@ -315,11 +313,10 @@ class ComposeLogic {
repliedPost: null, repliedPost: null,
forwardedPostId: null, forwardedPostId: null,
forwardedPost: null, forwardedPost: null,
attachments: attachments: state.attachments.value
state.attachments.value .map((e) => e.data)
.map((e) => e.data) .whereType<SnCloudFile>()
.whereType<SnCloudFile>() .toList(),
.toList(),
publisher: SnPublisher( publisher: SnPublisher(
id: '', id: '',
type: 0, type: 0,
@@ -501,11 +498,10 @@ class ComposeLogic {
UniversalFile value, UniversalFile value,
int index, int index,
) { ) {
state.attachments.value = state.attachments.value = state.attachments.value.mapIndexed((idx, ele) {
state.attachments.value.mapIndexed((idx, ele) { if (idx == index) return value;
if (idx == index) return value; return ele;
return ele; }).toList();
}).toList();
} }
static Future<void> uploadAttachment( static Future<void> uploadAttachment(
@@ -528,22 +524,20 @@ class ComposeLogic {
final pools = await ref.read(poolsProvider.future); final pools = await ref.read(poolsProvider.future);
final selectedPoolId = resolveDefaultPoolId(ref, pools); final selectedPoolId = resolveDefaultPoolId(ref, pools);
cloudFile = cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile( ref: ref,
ref: ref, fileData: attachment,
fileData: attachment, poolId: poolId ?? selectedPoolId,
poolId: poolId ?? selectedPoolId, mode: attachment.type == UniversalFileType.file
mode: ? FileUploadMode.generic
attachment.type == UniversalFileType.file : FileUploadMode.mediaSafe,
? FileUploadMode.generic onProgress: (progress, _) {
: FileUploadMode.mediaSafe, state.attachmentProgress.value = {
onProgress: (progress, _) { ...state.attachmentProgress.value,
state.attachmentProgress.value = { index: progress ?? 0.0,
...state.attachmentProgress.value, };
index: progress ?? 0.0, },
}; ).future;
},
).future;
if (cloudFile == null) { if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...'); throw ArgumentError('Failed to upload the file...');
@@ -713,11 +707,10 @@ class ComposeLogic {
if (state.slugController.text.isNotEmpty) if (state.slugController.text.isNotEmpty)
'slug': state.slugController.text, 'slug': state.slugController.text,
'visibility': state.visibility.value, 'visibility': state.visibility.value,
'attachments': 'attachments': state.attachments.value
state.attachments.value .where((e) => e.isOnCloud)
.where((e) => e.isOnCloud) .map((e) => e.data.id)
.map((e) => e.data.id) .toList(),
.toList(),
'type': state.postType, 'type': state.postType,
if (repliedPost != null) 'replied_post_id': repliedPost.id, if (repliedPost != null) 'replied_post_id': repliedPost.id,
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id, if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,

View File

@@ -1,81 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart'; import 'package:island/models/post.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/post/post_list.dart';
import 'package:island/pods/paging.dart';
import 'package:island/widgets/paging/pagination_list.dart'; import 'package:island/widgets/paging/pagination_list.dart';
import 'package:island/widgets/post/post_item.dart'; import 'package:island/widgets/post/post_item.dart';
import 'package:island/widgets/post/post_item_creator.dart'; import 'package:island/widgets/post/post_item_creator.dart';
import 'package:island/widgets/post/post_item_skeleton.dart'; import 'package:island/widgets/post/post_item_skeleton.dart';
part 'post_list.freezed.dart';
@freezed
sealed class PostListQuery with _$PostListQuery {
const factory PostListQuery({
String? pubName,
String? realm,
int? type,
List<String>? categories,
List<String>? tags,
bool? pinned,
@Default(false) bool shuffle,
bool? includeReplies,
bool? mediaOnly,
String? queryTerm,
String? order,
int? periodStart,
int? periodEnd,
@Default(true) bool orderDesc,
}) = _PostListQuery;
}
final postListNotifierProvider = AsyncNotifierProvider.autoDispose
.family<PostListNotifier, List<SnPost>, PostListQuery>(
PostListNotifier.new,
);
class PostListNotifier extends AsyncNotifier<List<SnPost>>
with AsyncPaginationController<SnPost> {
final PostListQuery arg;
PostListNotifier(this.arg);
static const int pageSize = 20;
@override
Future<List<SnPost>> fetch() async {
final client = ref.read(apiClientProvider);
final queryParams = {
'offset': fetchedCount,
'take': pageSize,
'replies': arg.includeReplies,
'orderDesc': arg.orderDesc,
if (arg.shuffle) 'shuffle': arg.shuffle,
if (arg.pubName != null) 'pub': arg.pubName,
if (arg.realm != null) 'realm': arg.realm,
if (arg.type != null) 'type': arg.type,
if (arg.tags != null) 'tags': arg.tags,
if (arg.categories != null) 'categories': arg.categories,
if (arg.pinned != null) 'pinned': arg.pinned,
if (arg.order != null) 'order': arg.order,
if (arg.periodStart != null) 'periodStart': arg.periodStart,
if (arg.periodEnd != null) 'periodEnd': arg.periodEnd,
if (arg.queryTerm != null) 'query': arg.queryTerm,
if (arg.mediaOnly != null) 'media': arg.mediaOnly,
};
final response = await client.get(
'/sphere/posts',
queryParameters: queryParams,
);
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
final List<dynamic> data = response.data;
return data.map((json) => SnPost.fromJson(json)).toList();
}
}
/// Defines which post item widget to use in the list /// Defines which post item widget to use in the list
enum PostItemType { enum PostItemType {
/// Regular post item with user information /// Regular post item with user information

View File

@@ -113,10 +113,7 @@ return $default(_that);case _:
final _that = this; final _that = this;
switch (_that) { switch (_that) {
case _ReactionListQuery(): case _ReactionListQuery():
return $default(_that);case _: return $default(_that);}
throw StateError('Unexpected subclass');
}
} }
/// A variant of `map` that fallback to returning `null`. /// A variant of `map` that fallback to returning `null`.
/// ///
@@ -175,10 +172,7 @@ return $default(_that.symbol,_that.postId);case _:
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String symbol, String postId) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String symbol, String postId) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _ReactionListQuery(): case _ReactionListQuery():
return $default(_that.symbol,_that.postId);case _: return $default(_that.symbol,_that.postId);}
throw StateError('Unexpected subclass');
}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///

View File

@@ -0,0 +1,271 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:material_symbols_icons/symbols.dart';
class PostFilterWidget extends StatelessWidget {
final TabController categoryTabController;
final ValueNotifier<bool?> includeReplies;
final ValueNotifier<bool> mediaOnly;
final ValueNotifier<String?> queryTerm;
final ValueNotifier<String?> order;
final ValueNotifier<bool> orderDesc;
final ValueNotifier<int?> periodStart;
final ValueNotifier<int?> periodEnd;
final ValueNotifier<bool> showAdvancedFilters;
final bool hideSearch;
const PostFilterWidget({
super.key,
required this.categoryTabController,
required this.includeReplies,
required this.mediaOnly,
required this.queryTerm,
required this.order,
required this.orderDesc,
required this.periodStart,
required this.periodEnd,
required this.showAdvancedFilters,
this.hideSearch = false,
});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Column(
children: [
TabBar(
controller: categoryTabController,
dividerColor: Colors.transparent,
splashBorderRadius: const BorderRadius.all(Radius.circular(8)),
tabs: [
Tab(text: 'all'.tr()),
Tab(text: 'postTypePost'.tr()),
Tab(text: 'postArticle'.tr()),
],
),
const Divider(height: 1),
Column(
children: [
Row(
children: [
Expanded(
child: CheckboxListTile(
title: Text('reply'.tr()),
value: includeReplies.value,
tristate: true,
onChanged: (value) {
// Cycle through: null -> false -> true -> null
if (includeReplies.value == null) {
includeReplies.value = false;
} else if (includeReplies.value == false) {
includeReplies.value = true;
} else {
includeReplies.value = null;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.reply),
),
),
Expanded(
child: CheckboxListTile(
title: Text('attachments'.tr()),
value: mediaOnly.value,
onChanged: (value) {
if (value != null) {
mediaOnly.value = value;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.attachment),
),
),
],
),
CheckboxListTile(
title: Text('descendingOrder'.tr()),
value: orderDesc.value,
onChanged: (value) {
if (value != null) {
orderDesc.value = value;
}
},
dense: true,
controlAffinity: ListTileControlAffinity.leading,
secondary: const Icon(Symbols.sort),
),
],
),
const Divider(height: 1),
ListTile(
title: Text('advancedFilters'.tr()),
leading: const Icon(Symbols.filter_list),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(const Radius.circular(8)),
),
trailing: Icon(
showAdvancedFilters.value
? Symbols.expand_less
: Symbols.expand_more,
),
onTap: () {
showAdvancedFilters.value = !showAdvancedFilters.value;
},
),
if (showAdvancedFilters.value) ...[
const Divider(height: 1),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (!hideSearch)
TextField(
decoration: InputDecoration(
labelText: 'search'.tr(),
hintText: 'searchPosts'.tr(),
prefixIcon: const Icon(Symbols.search),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
),
onChanged: (value) {
queryTerm.value = value.isEmpty ? null : value;
},
),
if (!hideSearch) const Gap(12),
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'sortBy'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
),
value: order.value,
items: [
DropdownMenuItem(value: 'date', child: Text('date'.tr())),
DropdownMenuItem(
value: 'popularity',
child: Text('popularity'.tr()),
),
],
onChanged: (value) {
order.value = value;
},
),
const Gap(12),
Row(
children: [
Expanded(
child: InkWell(
onTap: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate: periodStart.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodStart.value! * 1000,
)
: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime.now().add(
const Duration(days: 365),
),
);
if (pickedDate != null) {
periodStart.value =
pickedDate.millisecondsSinceEpoch ~/ 1000;
}
},
child: InputDecorator(
decoration: InputDecoration(
labelText: 'fromDate'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
suffixIcon: const Icon(Symbols.calendar_today),
),
child: Text(
periodStart.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodStart.value! * 1000,
).toString().split(' ')[0]
: 'selectDate'.tr(),
),
),
),
),
const Gap(8),
Expanded(
child: InkWell(
onTap: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate: periodEnd.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodEnd.value! * 1000,
)
: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime.now().add(
const Duration(days: 365),
),
);
if (pickedDate != null) {
periodEnd.value =
pickedDate.millisecondsSinceEpoch ~/ 1000;
}
},
child: InputDecorator(
decoration: InputDecoration(
labelText: 'toDate'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
suffixIcon: const Icon(Symbols.calendar_today),
),
child: Text(
periodEnd.value != null
? DateTime.fromMillisecondsSinceEpoch(
periodEnd.value! * 1000,
).toString().split(' ')[0]
: 'selectDate'.tr(),
),
),
),
),
],
),
],
),
),
],
],
),
);
}
}

View File

@@ -5,7 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/drive_task.dart'; import 'package:island/models/drive_task.dart';
import 'package:island/pods/upload_tasks.dart'; import 'package:island/pods/drive/upload_tasks.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@@ -223,14 +223,14 @@ class _UploadOverlayContent extends HookConsumerWidget {
if (!isExpanded && activeTasks.isNotEmpty) if (!isExpanded && activeTasks.isNotEmpty)
Text( Text(
_getOverallProgressText(activeTasks), _getOverallProgressText(activeTasks),
style: Theme.of( style: Theme.of(context)
context, .textTheme
).textTheme.bodySmall?.copyWith( .bodySmall
color: ?.copyWith(
Theme.of( color: Theme.of(
context, context,
).colorScheme.onSurfaceVariant, ).colorScheme.onSurfaceVariant,
), ),
), ),
], ],
), ),
@@ -244,10 +244,9 @@ class _UploadOverlayContent extends HookConsumerWidget {
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: _getOverallProgress(activeTasks), value: _getOverallProgress(activeTasks),
strokeWidth: 3, strokeWidth: 3,
backgroundColor: backgroundColor: Theme.of(
Theme.of( context,
context, ).colorScheme.surfaceContainerHighest,
).colorScheme.surfaceContainerHighest,
), ),
), ),
@@ -263,8 +262,8 @@ class _UploadOverlayContent extends HookConsumerWidget {
size: 20, size: 20,
), ),
), ),
onPressed: onPressed: () =>
() => onExpansionChanged?.call(!isExpanded), onExpansionChanged?.call(!isExpanded),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
), ),
@@ -297,20 +296,18 @@ class _UploadOverlayContent extends HookConsumerWidget {
leading: Icon( leading: Icon(
Symbols.clear_all, Symbols.clear_all,
size: 18, size: 18,
color: color: Theme.of(
Theme.of( context,
context, ).colorScheme.onSurfaceVariant,
).colorScheme.onSurfaceVariant,
), ),
onTap: () { onTap: () {
taskNotifier.clearCompletedTasks(); taskNotifier.clearCompletedTasks();
onExpansionChanged?.call(false); onExpansionChanged?.call(false);
}, },
tileColor: tileColor: Theme.of(
Theme.of( context,
context, ).colorScheme.surfaceContainerHighest,
).colorScheme.surfaceContainerHighest,
), ),
), ),
@@ -326,17 +323,17 @@ class _UploadOverlayContent extends HookConsumerWidget {
leading: Icon( leading: Icon(
Symbols.clear_all, Symbols.clear_all,
size: 18, size: 18,
color: color: Theme.of(
Theme.of(context).colorScheme.error, context,
).colorScheme.error,
), ),
onTap: () { onTap: () {
taskNotifier.clearAllTasks(); taskNotifier.clearAllTasks();
onExpansionChanged?.call(false); onExpansionChanged?.call(false);
}, },
tileColor: tileColor: Theme.of(
Theme.of( context,
context, ).colorScheme.surfaceContainerHighest,
).colorScheme.surfaceContainerHighest,
), ),
), ),
@@ -556,8 +553,9 @@ class _UploadTaskTileState extends State<UploadTaskTile>
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: widget.task.progress, value: widget.task.progress,
strokeWidth: 2.5, strokeWidth: 2.5,
backgroundColor: backgroundColor: Theme.of(
Theme.of(context).colorScheme.surfaceContainerHighest, context,
).colorScheme.surfaceContainerHighest,
), ),
), ),
), ),
@@ -604,10 +602,9 @@ class _UploadTaskTileState extends State<UploadTaskTile>
color = Theme.of(context).colorScheme.secondary; color = Theme.of(context).colorScheme.secondary;
break; break;
case DriveTaskStatus.inProgress: case DriveTaskStatus.inProgress:
icon = icon = widget.task.type == 'FileDownload'
widget.task.type == 'FileDownload' ? Symbols.download
? Symbols.download : Symbols.upload;
: Symbols.upload;
color = Theme.of(context).colorScheme.primary; color = Theme.of(context).colorScheme.primary;
break; break;
case DriveTaskStatus.paused: case DriveTaskStatus.paused: