Able to render offsite media

This commit is contained in:
2026-01-01 02:00:09 +08:00
parent adb231278c
commit ec71125fa9
13 changed files with 352 additions and 349 deletions

View File

@@ -55,6 +55,7 @@ sealed class SnCloudFile with _$SnCloudFile {
required DateTime createdAt, required DateTime createdAt,
required DateTime updatedAt, required DateTime updatedAt,
required DateTime? deletedAt, required DateTime? deletedAt,
String? url,
}) = _SnCloudFile; }) = _SnCloudFile;
factory SnCloudFile.fromJson(Map<String, dynamic> json) => factory SnCloudFile.fromJson(Map<String, dynamic> json) =>

View File

@@ -281,7 +281,7 @@ as String?,
/// @nodoc /// @nodoc
mixin _$SnCloudFile { mixin _$SnCloudFile {
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get url;
/// Create a copy of SnCloudFile /// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -294,16 +294,16 @@ $SnCloudFileCopyWith<SnCloudFile> get copyWith => _$SnCloudFileCopyWithImpl<SnCl
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
@override @override
String toString() { String toString() {
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
} }
@@ -314,7 +314,7 @@ abstract mixin class $SnCloudFileCopyWith<$Res> {
factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl; factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
}); });
@@ -331,7 +331,7 @@ class _$SnCloudFileCopyWithImpl<$Res>
/// Create a copy of SnCloudFile /// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
@@ -348,7 +348,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String?,
)); ));
} }
/// Create a copy of SnCloudFile /// Create a copy of SnCloudFile
@@ -442,10 +443,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnCloudFile() when $default != null: case _SnCloudFile() when $default != null:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
return orElse(); return orElse();
} }
@@ -463,10 +464,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnCloudFile(): case _SnCloudFile():
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);} return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -480,10 +481,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnCloudFile() when $default != null: case _SnCloudFile() when $default != null:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
return null; return null;
} }
@@ -495,7 +496,7 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
@JsonSerializable() @JsonSerializable()
class _SnCloudFile implements SnCloudFile { class _SnCloudFile implements SnCloudFile {
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks; const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt, this.url}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json); factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json);
@override final String id; @override final String id;
@@ -535,6 +536,7 @@ class _SnCloudFile implements SnCloudFile {
@override final DateTime createdAt; @override final DateTime createdAt;
@override final DateTime updatedAt; @override final DateTime updatedAt;
@override final DateTime? deletedAt; @override final DateTime? deletedAt;
@override final String? url;
/// Create a copy of SnCloudFile /// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@@ -549,16 +551,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
@override @override
String toString() { String toString() {
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
} }
@@ -569,7 +571,7 @@ abstract mixin class _$SnCloudFileCopyWith<$Res> implements $SnCloudFileCopyWith
factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl; factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
}); });
@@ -586,7 +588,7 @@ class __$SnCloudFileCopyWithImpl<$Res>
/// Create a copy of SnCloudFile /// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
return _then(_SnCloudFile( return _then(_SnCloudFile(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
@@ -603,7 +605,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String?,
)); ));
} }

View File

@@ -55,6 +55,7 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
deletedAt: json['deleted_at'] == null deletedAt: json['deleted_at'] == null
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
url: json['url'] as String?,
); );
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) => Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
@@ -74,6 +75,7 @@ Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
'created_at': instance.createdAt.toIso8601String(), 'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(),
'url': instance.url,
}; };
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) => _SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>

View File

@@ -476,9 +476,9 @@ class _AccountPublisherList extends StatelessWidget {
subtitle: Text( subtitle: Text(
publisher.bio.isNotEmpty publisher.bio.isNotEmpty
? publisher.bio ? publisher.bio
.split('\n') .split('\n')
.where((line) => line.trim().isNotEmpty) .where((line) => line.trim().isNotEmpty)
.join('\n') .join('\n')
: 'descriptionNone'.tr(), : 'descriptionNone'.tr(),
maxLines: 3, maxLines: 3,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -550,16 +550,14 @@ class _AccountAction extends StatelessWidget {
), ),
), ),
onPressed: relationshipAction, onPressed: relationshipAction,
label: label: Text(
Text( accountRelationship.value == null
accountRelationship.value == null ? 'addFriendShort'
? 'addFriendShort' : 'added',
: 'added', ).tr(),
).tr(), icon: accountRelationship.value == null
icon: ? const Icon(Symbols.person_add)
accountRelationship.value == null : const Icon(Symbols.person_check),
? const Icon(Symbols.person_add)
: const Icon(Symbols.person_check),
), ),
), ),
if (accountRelationship.value == null || if (accountRelationship.value == null ||
@@ -579,16 +577,14 @@ class _AccountAction extends StatelessWidget {
), ),
), ),
onPressed: blockAction, onPressed: blockAction,
label: label: Text(
Text( accountRelationship.value == null
accountRelationship.value == null ? 'blockUser'
? 'blockUser' : 'unblockUser',
: 'unblockUser', ).tr(),
).tr(), icon: accountRelationship.value == null
icon: ? const Icon(Symbols.block)
accountRelationship.value == null : const Icon(Symbols.person_cancel),
? const Icon(Symbols.block)
: const Icon(Symbols.person_cancel),
), ),
), ),
], ],
@@ -600,13 +596,12 @@ class _AccountAction extends StatelessWidget {
child: FilledButton.icon( child: FilledButton.icon(
onPressed: directMessageAction, onPressed: directMessageAction,
icon: const Icon(Symbols.message), icon: const Icon(Symbols.message),
label: label: Text(
Text( accountChat.value == null
accountChat.value == null ? 'createDirectMessage'
? 'createDirectMessage' : 'gotoDirectMessage',
: 'gotoDirectMessage', maxLines: 1,
maxLines: 1, ).tr(),
).tr(),
), ),
), ),
IconButton.filled( IconButton.filled(
@@ -664,7 +659,7 @@ Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async {
if (account.profile.background == null) return null; if (account.profile.background == null) return null;
final colors = await ColorExtractionService.getColorsFromImage( final colors = await ColorExtractionService.getColorsFromImage(
CloudImageWidget.provider( CloudImageWidget.provider(
fileId: account.profile.background!.id, file: account.profile.background!,
serverUrl: ref.watch(serverUrlProvider), serverUrl: ref.watch(serverUrlProvider),
), ),
); );
@@ -838,262 +833,256 @@ class AccountProfileScreen extends HookConsumerWidget {
final accountPublishers = ref.watch(accountPublishersProvider(data.id)); final accountPublishers = ref.watch(accountPublishersProvider(data.id));
return AppScaffold( return AppScaffold(
isNoBackground: false, isNoBackground: false,
appBar: appBar: isWideScreen(context)
isWideScreen(context) ? AppBar(
? AppBar( foregroundColor: appbarColor.value,
foregroundColor: appbarColor.value, leading: PageBackButton(
leading: PageBackButton( color: appbarColor.value,
color: appbarColor.value, shadows: [appbarShadow],
),
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(context).appBarTheme.foregroundColor,
shadows: [appbarShadow], shadows: [appbarShadow],
), ),
title: Text( ),
data.nick, )
style: TextStyle( : null,
color: body: isWideScreen(context)
appbarColor.value ?? ? Row(
Theme.of(context).appBarTheme.foregroundColor, children: [
shadows: [appbarShadow], Flexible(
), child: CustomScrollView(
), slivers: [
) SliverToBoxAdapter(
: null, child: _AccountBasicInfo(
body: data: data,
isWideScreen(context) uname: name,
? Row( accountDeveloper: accountDeveloper,
children: [ ).padding(horizontal: 4, top: 20),
Flexible( ),
child: CustomScrollView( if (data.badges.isNotEmpty)
slivers: [
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
).padding(horizontal: 4, top: 20),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(left: 2, right: 4),
),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(18),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 4, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
),
),
SliverToBoxAdapter( SliverToBoxAdapter(
child: Card( child: Card(
child: FortuneGraphWidget( child: BadgeList(
events: accountEvents, badges: data.badges,
eventCalandarUser: data.name, ).padding(horizontal: 26, vertical: 20),
margin: EdgeInsets.zero, ).padding(left: 2, right: 4),
), ),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(18),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 4, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
), ),
), ),
], SliverToBoxAdapter(
), child: Card(
), child: FortuneGraphWidget(
], events: accountEvents,
).padding(horizontal: 24) eventCalandarUser: data.name,
: CustomScrollView( margin: EdgeInsets.zero,
slivers: [
SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
), ),
), ),
], ),
), ],
), ),
SliverToBoxAdapter( ),
child: _AccountBasicInfo( ],
data: data, ).padding(horizontal: 24)
uname: name, : CustomScrollView(
accountDeveloper: accountDeveloper, slivers: [
).padding(horizontal: 4, top: 8), SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
), ),
if (data.badges.isNotEmpty) flexibleSpace: Stack(
SliverToBoxAdapter( children: [
child: Card( Positioned.fill(
child: BadgeList( child: data.profile.background?.id != null
badges: data.badges, ? CloudImageWidget(
).padding(horizontal: 26, vertical: 20), file: data.profile.background,
).padding(horizontal: 4), )
), : Container(
SliverToBoxAdapter( color: Theme.of(
child: Column( context,
children: [ ).appBarTheme.backgroundColor,
LevelingProgressCard( ),
level: data.profile.level, ),
experience: data.profile.experience, FlexibleSpaceBar(
progress: data.profile.levelingProgress, title: Text(
).padding(top: 8, horizontal: 8, bottom: 4), data.nick,
if (data.profile.verification != null) style: TextStyle(
Card( color:
child: VerificationStatusCard( appbarColor.value ??
mark: data.profile.verification!, Theme.of(
), context,
).padding(horizontal: 4), ).appBarTheme.foregroundColor,
], shadows: [appbarShadow],
), ),
),
),
],
), ),
SliverToBoxAdapter( ),
child: _AccountProfileBio( SliverToBoxAdapter(
data: data, child: _AccountBasicInfo(
).padding(horizontal: 4), data: data,
), uname: name,
if (data.profile.links.isNotEmpty) accountDeveloper: accountDeveloper,
SliverToBoxAdapter( ).padding(horizontal: 4, top: 8),
child: _AccountProfileLinks( ),
data: data, if (data.badges.isNotEmpty)
).padding(horizontal: 4),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 8, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
SliverToBoxAdapter( SliverToBoxAdapter(
child: Card( child: Card(
child: FortuneGraphWidget( child: BadgeList(
events: accountEvents, badges: data.badges,
eventCalandarUser: data.name, ).padding(horizontal: 26, vertical: 20),
),
).padding(horizontal: 4), ).padding(horizontal: 4),
), ),
], SliverToBoxAdapter(
), child: Column(
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(top: 8, horizontal: 8, bottom: 4),
if (data.profile.verification != null)
Card(
child: VerificationStatusCard(
mark: data.profile.verification!,
),
).padding(horizontal: 4),
],
),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(horizontal: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(
data: data,
).padding(horizontal: 4),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 8, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalandarUser: data.name,
),
).padding(horizontal: 4),
),
],
),
); );
}, },
error: error: (error, stackTrace) => AppScaffold(
(error, stackTrace) => AppScaffold( appBar: AppBar(leading: const PageBackButton()),
appBar: AppBar(leading: const PageBackButton()), body: Center(child: Text(error.toString())),
body: Center(child: Text(error.toString())), ),
), loading: () => AppScaffold(
loading: appBar: AppBar(leading: const PageBackButton()),
() => AppScaffold( body: Center(child: CircularProgressIndicator()),
appBar: AppBar(leading: const PageBackButton()), ),
body: Center(child: CircularProgressIndicator()),
),
); );
} }
} }

View File

@@ -393,7 +393,7 @@ Future<Color?> publisherAppbarForcegroundColor(Ref ref, String pubName) async {
if (publisher.background == null) return null; if (publisher.background == null) return null;
final colors = await ColorExtractionService.getColorsFromImage( final colors = await ColorExtractionService.getColorsFromImage(
CloudImageWidget.provider( CloudImageWidget.provider(
fileId: publisher.background!.id, file: publisher.background!,
serverUrl: ref.watch(serverUrlProvider), serverUrl: ref.watch(serverUrlProvider),
), ),
); );

View File

@@ -33,7 +33,7 @@ final realmAppbarForegroundColorProvider = FutureProvider.autoDispose
if (realm?.background == null) return null; if (realm?.background == null) return null;
final colors = await ColorExtractionService.getColorsFromImage( final colors = await ColorExtractionService.getColorsFromImage(
CloudImageWidget.provider( CloudImageWidget.provider(
fileId: realm!.background!.id, file: realm!.background!,
serverUrl: ref.watch(serverUrlProvider), serverUrl: ref.watch(serverUrlProvider),
), ),
); );

View File

@@ -3,11 +3,11 @@ import 'package:flutter/material.dart';
import 'package:island/models/activitypub.dart'; import 'package:island/models/activitypub.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
class ActorAvatarWidget extends StatelessWidget { class ActorPictureWidget extends StatelessWidget {
final SnActivityPubActor actor; final SnActivityPubActor actor;
final double radius; final double radius;
const ActorAvatarWidget({super.key, required this.actor, this.radius = 16}); const ActorPictureWidget({super.key, required this.actor, this.radius = 16});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -29,10 +29,12 @@ class ActorAvatarWidget extends StatelessWidget {
backgroundImage: CachedNetworkImageProvider(avatarUrl), backgroundImage: CachedNetworkImageProvider(avatarUrl),
radius: radius, radius: radius,
backgroundColor: Theme.of(context).colorScheme.surfaceContainer, backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
child: Icon( child: avatarUrl.isNotEmpty
Symbols.person, ? null
color: Theme.of(context).colorScheme.onSurfaceVariant, : Icon(
), Symbols.person,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
), ),
Positioned( Positioned(
right: 0, right: 0,

View File

@@ -4,11 +4,13 @@ import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/main.dart'; import 'package:island/main.dart';
import 'package:island/talker.dart'; import 'package:island/talker.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart';
import 'package:url_launcher/url_launcher.dart';
void showSnackBar(String message, {SnackBarAction? action}) { void showSnackBar(String message, {SnackBarAction? action}) {
final context = globalOverlay.currentState!.context; final context = globalOverlay.currentState!.context;
@@ -373,3 +375,20 @@ Future<bool> showConfirmAlert(
); );
return result ?? false; return result ?? false;
} }
Future<void> openExternalLink(Uri url, WidgetRef ref) async {
final whitelistDomains = ['solian.app', 'solsynth.dev'];
if (whitelistDomains.any(
(domain) => url.host == domain || url.host.endsWith('.$domain'),
)) {
await launchUrl(url, mode: LaunchMode.externalApplication);
} else {
final value = await showConfirmAlert(
'openLinkConfirmDescription'.tr(args: [url.toString()]),
'openLinkConfirm'.tr(),
);
if (value) {
await launchUrl(url, mode: LaunchMode.externalApplication);
}
}
}

View File

@@ -62,7 +62,7 @@ class CloudFileLightbox extends HookConsumerWidget {
controller: photoViewController, controller: photoViewController,
heroAttributes: PhotoViewHeroAttributes(tag: heroTag), heroAttributes: PhotoViewHeroAttributes(tag: heroTag),
imageProvider: CloudImageWidget.provider( imageProvider: CloudImageWidget.provider(
fileId: item.id, file: item,
serverUrl: serverUrl, serverUrl: serverUrl,
original: showOriginal.value, original: showOriginal.value,
), ),
@@ -118,20 +118,21 @@ class CloudFileLightbox extends HookConsumerWidget {
onPressed: showInfoSheet, onPressed: showInfoSheet,
shadows: WhiteShadows.standard, shadows: WhiteShadows.standard,
), ),
FileActionButton.more( if (item.url != null)
onPressed: () { FileActionButton.more(
final router = GoRouter.of(context); onPressed: () {
Navigator.of(context).pop(context); final router = GoRouter.of(context);
Future(() { Navigator.of(context).pop(context);
router.pushNamed( Future(() {
'fileDetail', router.pushNamed(
pathParameters: {'id': item.id}, 'fileDetail',
extra: item, pathParameters: {'id': item.id},
); extra: item,
}); );
}, });
shadows: WhiteShadows.standard, },
), shadows: WhiteShadows.standard,
),
], ],
showExtraOnLeft: true, showExtraOnLeft: true,
), ),

View File

@@ -41,7 +41,7 @@ class CloudFileWidget extends HookConsumerWidget {
appSettingsProvider.select((s) => s.dataSavingMode), appSettingsProvider.select((s) => s.dataSavingMode),
); );
final serverUrl = ref.watch(serverUrlProvider); final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/drive/files/${item.id}'; final uri = item.url ?? '$serverUrl/drive/files/${item.id}';
final unlocked = useState(false); final unlocked = useState(false);
@@ -529,7 +529,7 @@ class CloudImageWidget extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final serverUrl = ref.watch(serverUrlProvider); final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/drive/files/${file?.id ?? fileId}'; final uri = file?.url ?? '$serverUrl/drive/files/${file?.id ?? fileId}';
return AspectRatio( return AspectRatio(
aspectRatio: aspectRatio, aspectRatio: aspectRatio,
@@ -540,13 +540,15 @@ class CloudImageWidget extends ConsumerWidget {
} }
static ImageProvider provider({ static ImageProvider provider({
required String fileId, required SnCloudFile file,
required String serverUrl, required String serverUrl,
bool original = false, bool original = false,
}) { }) {
final uri = original final uri =
? '$serverUrl/drive/files/$fileId?original=true' file.url ??
: '$serverUrl/drive/files/$fileId'; (original
? '$serverUrl/drive/files/${file.id}?original=true'
: '$serverUrl/drive/files/${file.id}');
return CachedNetworkImageProvider(uri); return CachedNetworkImageProvider(uri);
} }
} }

View File

@@ -167,7 +167,7 @@ class ImageFileContent extends HookConsumerWidget {
), ),
controller: photoViewController, controller: photoViewController,
imageProvider: CloudImageWidget.provider( imageProvider: CloudImageWidget.provider(
fileId: item.id, file: item,
serverUrl: ref.watch(serverUrlProvider), serverUrl: ref.watch(serverUrlProvider),
original: showOriginal.value, original: showOriginal.value,
), ),

View File

@@ -21,7 +21,6 @@ import 'package:markdown/markdown.dart' as markdown;
import 'package:markdown_widget/markdown_widget.dart'; import 'package:markdown_widget/markdown_widget.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'image.dart'; import 'image.dart';
@@ -139,7 +138,7 @@ class MarkdownTextContent extends HookConsumerWidget {
style: style:
linkStyle ?? linkStyle ??
TextStyle(color: Theme.of(context).colorScheme.primary), TextStyle(color: Theme.of(context).colorScheme.primary),
onTap: (href) { onTap: (href) async {
final url = Uri.tryParse(href); final url = Uri.tryParse(href);
if (url != null) { if (url != null) {
if (url.scheme == 'solian') { if (url.scheme == 'solian') {
@@ -147,22 +146,7 @@ class MarkdownTextContent extends HookConsumerWidget {
context.push(fullPath); context.push(fullPath);
return; return;
} }
final whitelistDomains = ['solian.app', 'solsynth.dev']; await openExternalLink(url, ref);
if (whitelistDomains.any(
(domain) =>
url.host == domain || url.host.endsWith('.$domain'),
)) {
launchUrl(url, mode: LaunchMode.externalApplication);
return;
}
showConfirmAlert(
'openLinkConfirmDescription'.tr(args: [url.toString()]),
'openLinkConfirm'.tr(),
).then((value) {
if (value) {
launchUrl(url, mode: LaunchMode.externalApplication);
}
});
} else { } else {
showSnackBar( showSnackBar(
'brokenLink'.tr(args: [href]), 'brokenLink'.tr(args: [href]),

View File

@@ -146,7 +146,7 @@ class PostReplyPreview extends HookConsumerWidget {
} }
// Handle actor case // Handle actor case
if (post.actor != null) { if (post.actor != null) {
return ActorAvatarWidget(actor: post.actor!, radius: radius); return ActorPictureWidget(actor: post.actor!, radius: radius);
} }
// Fallback // Fallback
return ProfilePictureWidget(fileId: null, radius: radius); return ProfilePictureWidget(fileId: null, radius: radius);
@@ -452,7 +452,7 @@ class ReferencedPostWidget extends StatelessWidget {
} }
// Handle actor case // Handle actor case
if (post.actor != null) { if (post.actor != null) {
return ActorAvatarWidget(actor: post.actor!, radius: radius); return ActorPictureWidget(actor: post.actor!, radius: radius);
} }
// Fallback // Fallback
return ProfilePictureWidget(fileId: null, radius: radius); return ProfilePictureWidget(fileId: null, radius: radius);
@@ -657,7 +657,7 @@ class ReferencedPostWidget extends StatelessWidget {
} }
} }
class PostHeader extends StatelessWidget { class PostHeader extends HookConsumerWidget {
final SnPost item; final SnPost item;
final bool isFullPost; final bool isFullPost;
final Widget? trailing; final Widget? trailing;
@@ -695,7 +695,7 @@ class PostHeader extends StatelessWidget {
} }
// Handle actor case // Handle actor case
if (post.actor != null) { if (post.actor != null) {
return ActorAvatarWidget(actor: post.actor!, radius: radius); return ActorPictureWidget(actor: post.actor!, radius: radius);
} }
// Fallback // Fallback
return ProfilePictureWidget(fileId: null, radius: radius); return ProfilePictureWidget(fileId: null, radius: radius);
@@ -746,7 +746,7 @@ class PostHeader extends StatelessWidget {
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context, WidgetRef ref) {
return Column( return Column(
children: [ children: [
Row( Row(
@@ -756,12 +756,12 @@ class PostHeader extends StatelessWidget {
GestureDetector( GestureDetector(
onTap: isInteractive && _getPublisherName(item) != null onTap: isInteractive && _getPublisherName(item) != null
? () { ? () {
context.pushNamed( if (item.publisher != null) {
'publisherProfile', context.pushNamed(
pathParameters: { 'publisherProfile',
'name': _getPublisherName(item) as String, pathParameters: {'name': item.publisher!.name},
}, );
); }
} }
: null, : null,
child: _buildProfilePicture(context, item, radius: 16), child: _buildProfilePicture(context, item, radius: 16),