🔀 Merge pull request #179 from Texas0295/v3
[Feature] add pool-aware file upload with default pool selection
This commit is contained in:
@@ -30,6 +30,8 @@
|
|||||||
"fieldEmailAddressMustBeValid": "The email address must be valid.",
|
"fieldEmailAddressMustBeValid": "The email address must be valid.",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"updateYourProfile": "Profile Settings",
|
"updateYourProfile": "Profile Settings",
|
||||||
|
"settingsDefaultPool": "Default file pool",
|
||||||
|
"settingsDefaultPoolHelper": "Select the default storage pool for file uploads",
|
||||||
"accountBasicInfo": "Basic Info",
|
"accountBasicInfo": "Basic Info",
|
||||||
"accountProfile": "Your Profile",
|
"accountProfile": "Your Profile",
|
||||||
"saveChanges": "Save Changes",
|
"saveChanges": "Save Changes",
|
||||||
@@ -168,6 +170,7 @@
|
|||||||
"addPhoto": "Add photo",
|
"addPhoto": "Add photo",
|
||||||
"addAudio": "Add audio",
|
"addAudio": "Add audio",
|
||||||
"addFile": "Add file",
|
"addFile": "Add file",
|
||||||
|
"uploadFile": "Upload File",
|
||||||
"recordAudio": "Record Audio",
|
"recordAudio": "Record Audio",
|
||||||
"linkAttachment": "Link Attachment",
|
"linkAttachment": "Link Attachment",
|
||||||
"fileIdCannotBeEmpty": "File ID cannot be empty",
|
"fileIdCannotBeEmpty": "File ID cannot be empty",
|
||||||
|
@@ -122,6 +122,9 @@
|
|||||||
"addVideo": "添加视频",
|
"addVideo": "添加视频",
|
||||||
"addPhoto": "添加照片",
|
"addPhoto": "添加照片",
|
||||||
"addFile": "添加文件",
|
"addFile": "添加文件",
|
||||||
|
"uploadFile": "上传文件",
|
||||||
|
"settingsDefaultPool": "选择文件池",
|
||||||
|
"settingsDefaultPoolHelper": "为文件上传选择一个默认池",
|
||||||
"createDirectMessage": "创建新私人消息",
|
"createDirectMessage": "创建新私人消息",
|
||||||
"gotoDirectMessage": "前往私信",
|
"gotoDirectMessage": "前往私信",
|
||||||
"react": "反应",
|
"react": "反应",
|
||||||
|
@@ -122,6 +122,10 @@
|
|||||||
"addVideo": "添加視頻",
|
"addVideo": "添加視頻",
|
||||||
"addPhoto": "添加照片",
|
"addPhoto": "添加照片",
|
||||||
"addFile": "添加文件",
|
"addFile": "添加文件",
|
||||||
|
"uploadFile": "上傳文件",
|
||||||
|
"settingsDefaultPool": "選擇文件池",
|
||||||
|
"settingsDefaultPoolHelper": "爲文件上傳選擇一個默認池",
|
||||||
|
|
||||||
"createDirectMessage": "創建新私人消息",
|
"createDirectMessage": "創建新私人消息",
|
||||||
"gotoDirectMessage": "前往私信",
|
"gotoDirectMessage": "前往私信",
|
||||||
"react": "反應",
|
"react": "反應",
|
||||||
|
53
lib/models/file_pool.dart
Normal file
53
lib/models/file_pool.dart
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'file_pool.freezed.dart';
|
||||||
|
part 'file_pool.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnFilePool with _$SnFilePool {
|
||||||
|
const factory SnFilePool({
|
||||||
|
required String id,
|
||||||
|
required String name,
|
||||||
|
String? description,
|
||||||
|
Map<String, dynamic>? storageConfig,
|
||||||
|
Map<String, dynamic>? billingConfig,
|
||||||
|
Map<String, dynamic>? policyConfig,
|
||||||
|
bool? isHidden,
|
||||||
|
String? accountId,
|
||||||
|
String? resourceIdentifier,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
DateTime? deletedAt,
|
||||||
|
}) = _SnFilePool;
|
||||||
|
|
||||||
|
factory SnFilePool.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnFilePoolFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SnFilePoolList on List<SnFilePool> {
|
||||||
|
static List<SnFilePool> listFromResponse(dynamic data) {
|
||||||
|
if (data is List) {
|
||||||
|
return data
|
||||||
|
.whereType<Map<String, dynamic>>()
|
||||||
|
.map(SnFilePool.fromJson)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
throw ArgumentError('Unexpected response format: $data');
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SnFilePool> filterValid() {
|
||||||
|
return where((p) {
|
||||||
|
final accept = p.policyConfig?['accept_types'];
|
||||||
|
|
||||||
|
if (accept is List) {
|
||||||
|
final acceptsOnlyMedia = accept.every((t) =>
|
||||||
|
t is String &&
|
||||||
|
(t.startsWith('image/') ||
|
||||||
|
t.startsWith('video/') ||
|
||||||
|
t.startsWith('audio/')));
|
||||||
|
if (acceptsOnlyMedia) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
}
|
328
lib/models/file_pool.freezed.dart
Normal file
328
lib/models/file_pool.freezed.dart
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'file_pool.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnFilePool {
|
||||||
|
|
||||||
|
String get id; String get name; String? get description; Map<String, dynamic>? get storageConfig; Map<String, dynamic>? get billingConfig; Map<String, dynamic>? get policyConfig; bool? get isHidden; String? get accountId; String? get resourceIdentifier; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt;
|
||||||
|
/// Create a copy of SnFilePool
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnFilePoolCopyWith<SnFilePool> get copyWith => _$SnFilePoolCopyWithImpl<SnFilePool>(this as SnFilePool, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnFilePool to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnFilePool&&(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.storageConfig, storageConfig)&&const DeepCollectionEquality().equals(other.billingConfig, billingConfig)&&const DeepCollectionEquality().equals(other.policyConfig, policyConfig)&&(identical(other.isHidden, isHidden) || other.isHidden == isHidden)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.resourceIdentifier, resourceIdentifier) || other.resourceIdentifier == resourceIdentifier)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(storageConfig),const DeepCollectionEquality().hash(billingConfig),const DeepCollectionEquality().hash(policyConfig),isHidden,accountId,resourceIdentifier,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFilePool(id: $id, name: $name, description: $description, storageConfig: $storageConfig, billingConfig: $billingConfig, policyConfig: $policyConfig, isHidden: $isHidden, accountId: $accountId, resourceIdentifier: $resourceIdentifier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnFilePoolCopyWith<$Res> {
|
||||||
|
factory $SnFilePoolCopyWith(SnFilePool value, $Res Function(SnFilePool) _then) = _$SnFilePoolCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String name, String? description, Map<String, dynamic>? storageConfig, Map<String, dynamic>? billingConfig, Map<String, dynamic>? policyConfig, bool? isHidden, String? accountId, String? resourceIdentifier, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnFilePoolCopyWithImpl<$Res>
|
||||||
|
implements $SnFilePoolCopyWith<$Res> {
|
||||||
|
_$SnFilePoolCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnFilePool _self;
|
||||||
|
final $Res Function(SnFilePool) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFilePool
|
||||||
|
/// 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? storageConfig = freezed,Object? billingConfig = freezed,Object? policyConfig = freezed,Object? isHidden = freezed,Object? accountId = freezed,Object? resourceIdentifier = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
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,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,storageConfig: freezed == storageConfig ? _self.storageConfig : storageConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,billingConfig: freezed == billingConfig ? _self.billingConfig : billingConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,policyConfig: freezed == policyConfig ? _self.policyConfig : policyConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,isHidden: freezed == isHidden ? _self.isHidden : isHidden // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,resourceIdentifier: freezed == resourceIdentifier ? _self.resourceIdentifier : resourceIdentifier // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [SnFilePool].
|
||||||
|
extension SnFilePoolPatterns on SnFilePool {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnFilePool value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnFilePool value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnFilePool value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? storageConfig, Map<String, dynamic>? billingConfig, Map<String, dynamic>? policyConfig, bool? isHidden, String? accountId, String? resourceIdentifier, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool() when $default != null:
|
||||||
|
return $default(_that.id,_that.name,_that.description,_that.storageConfig,_that.billingConfig,_that.policyConfig,_that.isHidden,_that.accountId,_that.resourceIdentifier,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? storageConfig, Map<String, dynamic>? billingConfig, Map<String, dynamic>? policyConfig, bool? isHidden, String? accountId, String? resourceIdentifier, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool():
|
||||||
|
return $default(_that.id,_that.name,_that.description,_that.storageConfig,_that.billingConfig,_that.policyConfig,_that.isHidden,_that.accountId,_that.resourceIdentifier,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? storageConfig, Map<String, dynamic>? billingConfig, Map<String, dynamic>? policyConfig, bool? isHidden, String? accountId, String? resourceIdentifier, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFilePool() when $default != null:
|
||||||
|
return $default(_that.id,_that.name,_that.description,_that.storageConfig,_that.billingConfig,_that.policyConfig,_that.isHidden,_that.accountId,_that.resourceIdentifier,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnFilePool implements SnFilePool {
|
||||||
|
const _SnFilePool({required this.id, required this.name, this.description, final Map<String, dynamic>? storageConfig, final Map<String, dynamic>? billingConfig, final Map<String, dynamic>? policyConfig, this.isHidden, this.accountId, this.resourceIdentifier, this.createdAt, this.updatedAt, this.deletedAt}): _storageConfig = storageConfig,_billingConfig = billingConfig,_policyConfig = policyConfig;
|
||||||
|
factory _SnFilePool.fromJson(Map<String, dynamic> json) => _$SnFilePoolFromJson(json);
|
||||||
|
|
||||||
|
@override final String id;
|
||||||
|
@override final String name;
|
||||||
|
@override final String? description;
|
||||||
|
final Map<String, dynamic>? _storageConfig;
|
||||||
|
@override Map<String, dynamic>? get storageConfig {
|
||||||
|
final value = _storageConfig;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_storageConfig is EqualUnmodifiableMapView) return _storageConfig;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableMapView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic>? _billingConfig;
|
||||||
|
@override Map<String, dynamic>? get billingConfig {
|
||||||
|
final value = _billingConfig;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_billingConfig is EqualUnmodifiableMapView) return _billingConfig;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableMapView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic>? _policyConfig;
|
||||||
|
@override Map<String, dynamic>? get policyConfig {
|
||||||
|
final value = _policyConfig;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_policyConfig is EqualUnmodifiableMapView) return _policyConfig;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableMapView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override final bool? isHidden;
|
||||||
|
@override final String? accountId;
|
||||||
|
@override final String? resourceIdentifier;
|
||||||
|
@override final DateTime? createdAt;
|
||||||
|
@override final DateTime? updatedAt;
|
||||||
|
@override final DateTime? deletedAt;
|
||||||
|
|
||||||
|
/// Create a copy of SnFilePool
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnFilePoolCopyWith<_SnFilePool> get copyWith => __$SnFilePoolCopyWithImpl<_SnFilePool>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnFilePoolToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnFilePool&&(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._storageConfig, _storageConfig)&&const DeepCollectionEquality().equals(other._billingConfig, _billingConfig)&&const DeepCollectionEquality().equals(other._policyConfig, _policyConfig)&&(identical(other.isHidden, isHidden) || other.isHidden == isHidden)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.resourceIdentifier, resourceIdentifier) || other.resourceIdentifier == resourceIdentifier)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_storageConfig),const DeepCollectionEquality().hash(_billingConfig),const DeepCollectionEquality().hash(_policyConfig),isHidden,accountId,resourceIdentifier,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFilePool(id: $id, name: $name, description: $description, storageConfig: $storageConfig, billingConfig: $billingConfig, policyConfig: $policyConfig, isHidden: $isHidden, accountId: $accountId, resourceIdentifier: $resourceIdentifier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnFilePoolCopyWith<$Res> implements $SnFilePoolCopyWith<$Res> {
|
||||||
|
factory _$SnFilePoolCopyWith(_SnFilePool value, $Res Function(_SnFilePool) _then) = __$SnFilePoolCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String name, String? description, Map<String, dynamic>? storageConfig, Map<String, dynamic>? billingConfig, Map<String, dynamic>? policyConfig, bool? isHidden, String? accountId, String? resourceIdentifier, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnFilePoolCopyWithImpl<$Res>
|
||||||
|
implements _$SnFilePoolCopyWith<$Res> {
|
||||||
|
__$SnFilePoolCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnFilePool _self;
|
||||||
|
final $Res Function(_SnFilePool) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFilePool
|
||||||
|
/// 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? storageConfig = freezed,Object? billingConfig = freezed,Object? policyConfig = freezed,Object? isHidden = freezed,Object? accountId = freezed,Object? resourceIdentifier = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,}) {
|
||||||
|
return _then(_SnFilePool(
|
||||||
|
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,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,storageConfig: freezed == storageConfig ? _self._storageConfig : storageConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,billingConfig: freezed == billingConfig ? _self._billingConfig : billingConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,policyConfig: freezed == policyConfig ? _self._policyConfig : policyConfig // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>?,isHidden: freezed == isHidden ? _self.isHidden : isHidden // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,resourceIdentifier: freezed == resourceIdentifier ? _self.resourceIdentifier : resourceIdentifier // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
47
lib/models/file_pool.g.dart
Normal file
47
lib/models/file_pool.g.dart
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'file_pool.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_SnFilePool _$SnFilePoolFromJson(Map<String, dynamic> json) => _SnFilePool(
|
||||||
|
id: json['id'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
description: json['description'] as String?,
|
||||||
|
storageConfig: json['storage_config'] as Map<String, dynamic>?,
|
||||||
|
billingConfig: json['billing_config'] as Map<String, dynamic>?,
|
||||||
|
policyConfig: json['policy_config'] as Map<String, dynamic>?,
|
||||||
|
isHidden: json['is_hidden'] as bool?,
|
||||||
|
accountId: json['account_id'] as String?,
|
||||||
|
resourceIdentifier: json['resource_identifier'] as String?,
|
||||||
|
createdAt:
|
||||||
|
json['created_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at'] as String),
|
||||||
|
updatedAt:
|
||||||
|
json['updated_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['updated_at'] as String),
|
||||||
|
deletedAt:
|
||||||
|
json['deleted_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnFilePoolToJson(_SnFilePool instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'name': instance.name,
|
||||||
|
'description': instance.description,
|
||||||
|
'storage_config': instance.storageConfig,
|
||||||
|
'billing_config': instance.billingConfig,
|
||||||
|
'policy_config': instance.policyConfig,
|
||||||
|
'is_hidden': instance.isHidden,
|
||||||
|
'account_id': instance.accountId,
|
||||||
|
'resource_identifier': instance.resourceIdentifier,
|
||||||
|
'created_at': instance.createdAt?.toIso8601String(),
|
||||||
|
'updated_at': instance.updatedAt?.toIso8601String(),
|
||||||
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
|
};
|
@@ -25,6 +25,7 @@ const kAppSoundEffects = 'app_sound_effects';
|
|||||||
const kAppAprilFoolFeatures = 'app_april_fool_features';
|
const kAppAprilFoolFeatures = 'app_april_fool_features';
|
||||||
const kAppWindowSize = 'app_window_size';
|
const kAppWindowSize = 'app_window_size';
|
||||||
const kAppEnterToSend = 'app_enter_to_send';
|
const kAppEnterToSend = 'app_enter_to_send';
|
||||||
|
const kAppDefaultPoolId = 'app_default_pool_id';
|
||||||
const kFeaturedPostsCollapsedId =
|
const kFeaturedPostsCollapsedId =
|
||||||
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ sealed class AppSettings with _$AppSettings {
|
|||||||
required String? customFonts,
|
required String? customFonts,
|
||||||
required int? appColorScheme, // The color stored via the int type
|
required int? appColorScheme, // The color stored via the int type
|
||||||
required Size? windowSize, // The window size for desktop platforms
|
required Size? windowSize, // The window size for desktop platforms
|
||||||
|
required String? defaultPoolId,
|
||||||
}) = _AppSettings;
|
}) = _AppSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
customFonts: prefs.getString(kAppCustomFonts),
|
customFonts: prefs.getString(kAppCustomFonts),
|
||||||
appColorScheme: prefs.getInt(kAppColorSchemeStoreKey),
|
appColorScheme: prefs.getInt(kAppColorSchemeStoreKey),
|
||||||
windowSize: _getWindowSizeFromPrefs(prefs),
|
windowSize: _getWindowSizeFromPrefs(prefs),
|
||||||
|
defaultPoolId: prefs.getString(kAppDefaultPoolId),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +106,15 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
void setDefaultPoolId(String? value) {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
if (value != null) {
|
||||||
|
prefs.setString(kAppDefaultPoolId, value);
|
||||||
|
} else {
|
||||||
|
prefs.remove(kAppDefaultPoolId);
|
||||||
|
}
|
||||||
|
state = state.copyWith(defaultPoolId: value);
|
||||||
|
}
|
||||||
|
|
||||||
void setAutoTranslate(bool value) {
|
void setAutoTranslate(bool value) {
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
@@ -15,7 +15,8 @@ T _$identity<T>(T value) => value;
|
|||||||
mixin _$AppSettings {
|
mixin _$AppSettings {
|
||||||
|
|
||||||
bool get autoTranslate; bool get dataSavingMode; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; bool get showBackgroundImage; String? get customFonts; int? get appColorScheme;// The color stored via the int type
|
bool get autoTranslate; bool get dataSavingMode; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; bool get showBackgroundImage; String? get customFonts; int? get appColorScheme;// The color stored via the int type
|
||||||
Size? get windowSize;
|
Size? get windowSize;// The window size for desktop platforms
|
||||||
|
String? get defaultPoolId;
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// 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)
|
||||||
@@ -26,16 +27,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize);
|
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize,defaultPoolId);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize, defaultPoolId: $defaultPoolId)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
|||||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize
|
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize, String? defaultPoolId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ class _$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// 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? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,Object? defaultPoolId = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -75,7 +76,8 @@ as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundI
|
|||||||
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
||||||
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
||||||
as Size?,
|
as Size?,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,10 +159,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize, String? defaultPoolId)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize,_that.defaultPoolId);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -178,10 +180,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize, String? defaultPoolId) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings():
|
case _AppSettings():
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);}
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize,_that.defaultPoolId);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -195,10 +197,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize, String? defaultPoolId)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize,_that.defaultPoolId);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -210,7 +212,7 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
|
|
||||||
|
|
||||||
class _AppSettings implements AppSettings {
|
class _AppSettings implements AppSettings {
|
||||||
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.windowSize});
|
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.windowSize, required this.defaultPoolId});
|
||||||
|
|
||||||
|
|
||||||
@override final bool autoTranslate;
|
@override final bool autoTranslate;
|
||||||
@@ -224,6 +226,8 @@ class _AppSettings implements AppSettings {
|
|||||||
@override final int? appColorScheme;
|
@override final int? appColorScheme;
|
||||||
// The color stored via the int type
|
// The color stored via the int type
|
||||||
@override final Size? windowSize;
|
@override final Size? windowSize;
|
||||||
|
// The window size for desktop platforms
|
||||||
|
@override final String? defaultPoolId;
|
||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -235,16 +239,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize);
|
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize,defaultPoolId);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize, defaultPoolId: $defaultPoolId)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +259,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
|||||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize
|
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize, String? defaultPoolId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -272,7 +276,7 @@ class __$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// 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? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,Object? defaultPoolId = freezed,}) {
|
||||||
return _then(_AppSettings(
|
return _then(_AppSettings(
|
||||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -284,7 +288,8 @@ as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundI
|
|||||||
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
||||||
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
||||||
as Size?,
|
as Size?,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ part of 'config.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$appSettingsNotifierHash() =>
|
String _$appSettingsNotifierHash() =>
|
||||||
r'cd18bff2614a94e3523634e6c577cefad0367eba';
|
r'a623ad859b71f42d0527b7f8b75bd37a6fd5d5c7';
|
||||||
|
|
||||||
/// See also [AppSettingsNotifier].
|
/// See also [AppSettingsNotifier].
|
||||||
@ProviderFor(AppSettingsNotifier)
|
@ProviderFor(AppSettingsNotifier)
|
||||||
|
28
lib/pods/pool_provider.dart
Normal file
28
lib/pods/pool_provider.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/file_pool.dart';
|
||||||
|
import 'package:island/pods/config.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
|
||||||
|
final poolsProvider = FutureProvider<List<SnFilePool>>((ref) async {
|
||||||
|
final dio = ref.watch(apiClientProvider);
|
||||||
|
final response = await dio.get('/drive/pools');
|
||||||
|
final pools = SnFilePoolList.listFromResponse(response.data);
|
||||||
|
return pools.filterValid();
|
||||||
|
});
|
||||||
|
|
||||||
|
String resolveDefaultPoolId(WidgetRef ref, List<SnFilePool> pools) {
|
||||||
|
final settings = ref.watch(appSettingsNotifierProvider);
|
||||||
|
final validPools = pools.filterValid();
|
||||||
|
|
||||||
|
final configuredId = settings.defaultPoolId;
|
||||||
|
if (configuredId != null && validPools.any((p) => p.id == configuredId)) {
|
||||||
|
return configuredId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validPools.isNotEmpty) {
|
||||||
|
return validPools.first.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEFAULT: Solar Network Driver
|
||||||
|
return '500e5ed8-bd44-4359-bc0a-ec85e2adf447'; }
|
||||||
|
|
@@ -66,7 +66,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -268,7 +268,7 @@ class _AccountBadgesProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountAppbarForcegroundColorHash() =>
|
String _$accountAppbarForcegroundColorHash() =>
|
||||||
r'8ee0cae10817b77fb09548a482f5247662b4374c';
|
r'127fcc7fd6ec6a41ac4a6975276b5271aa4fa7d0';
|
||||||
|
|
||||||
/// See also [accountAppbarForcegroundColor].
|
/// See also [accountAppbarForcegroundColor].
|
||||||
@ProviderFor(accountAppbarForcegroundColor)
|
@ProviderFor(accountAppbarForcegroundColor)
|
||||||
|
@@ -6,7 +6,7 @@ part of 'captcha.config.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$captchaUrlHash() => r'bbed0d18272dd205069642b3c6583ea2eef735d1';
|
String _$captchaUrlHash() => r'd46bc43032cef504547cd528a40c23cf76f27cc8';
|
||||||
|
|
||||||
/// See also [captchaUrl].
|
/// See also [captchaUrl].
|
||||||
@ProviderFor(captchaUrl)
|
@ProviderFor(captchaUrl)
|
||||||
|
@@ -543,7 +543,7 @@ class EditChatScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -649,7 +649,7 @@ Future<void> loadMore() async {
|
|||||||
var cloudAttachments = List.empty(growable: true);
|
var cloudAttachments = List.empty(growable: true);
|
||||||
for (var idx = 0; idx < attachments.length; idx++) {
|
for (var idx = 0; idx < attachments.length; idx++) {
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: attachments[idx],
|
fileData: attachments[idx],
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
|
@@ -6,7 +6,7 @@ part of 'room.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$messagesNotifierHash() => r'fc3b66dfb8dd3fc55d142dae5c5e7bdc67eca5d4';
|
String _$messagesNotifierHash() => r'82a91344328ec44dfe934c80a4a770431d864bff';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@@ -98,7 +98,7 @@ class EditPublisherScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -141,7 +141,7 @@ class EditAppScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -127,7 +127,7 @@ class EditBotScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -7,7 +7,7 @@ part of 'notification.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$notificationUnreadCountNotifierHash() =>
|
String _$notificationUnreadCountNotifierHash() =>
|
||||||
r'0763b66bd64e5a9b7c317887e109ab367515dfa4';
|
r'08c773809958d96a7ce82acf04af1f9e0b23e119';
|
||||||
|
|
||||||
/// See also [NotificationUnreadCountNotifier].
|
/// See also [NotificationUnreadCountNotifier].
|
||||||
@ProviderFor(NotificationUnreadCountNotifier)
|
@ProviderFor(NotificationUnreadCountNotifier)
|
||||||
@@ -28,7 +28,7 @@ final notificationUnreadCountNotifierProvider =
|
|||||||
|
|
||||||
typedef _$NotificationUnreadCountNotifier = AutoDisposeAsyncNotifier<int>;
|
typedef _$NotificationUnreadCountNotifier = AutoDisposeAsyncNotifier<int>;
|
||||||
String _$notificationListNotifierHash() =>
|
String _$notificationListNotifierHash() =>
|
||||||
r'5099466db475bbcf1ab6b514eb072f1dc4c6f930';
|
r'260046e11f45b0d67ab25bcbdc8604890d71ccc7';
|
||||||
|
|
||||||
/// See also [NotificationListNotifier].
|
/// See also [NotificationListNotifier].
|
||||||
@ProviderFor(NotificationListNotifier)
|
@ProviderFor(NotificationListNotifier)
|
||||||
|
@@ -400,7 +400,7 @@ class _PublisherSubscriptionStatusProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$publisherAppbarForcegroundColorHash() =>
|
String _$publisherAppbarForcegroundColorHash() =>
|
||||||
r'd781a806a242aea5c1609ec98c97c52fdd9f7db1';
|
r'cd9a9816177a6eecc2bc354acebbbd48892ffdd7';
|
||||||
|
|
||||||
/// See also [publisherAppbarForcegroundColor].
|
/// See also [publisherAppbarForcegroundColor].
|
||||||
@ProviderFor(publisherAppbarForcegroundColor)
|
@ProviderFor(publisherAppbarForcegroundColor)
|
||||||
|
@@ -7,7 +7,7 @@ part of 'realm_detail.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$realmAppbarForegroundColorHash() =>
|
String _$realmAppbarForegroundColorHash() =>
|
||||||
r'14b5563d861996ea182d0d2db7aa5c2bb3bbaf48';
|
r'8131c047a984318a4cc3fbb5daa5ef0ce44dfae5';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@@ -211,7 +211,7 @@ class EditRealmScreen extends HookConsumerWidget {
|
|||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
if (token == null) throw ArgumentError('Access token is null');
|
if (token == null) throw ArgumentError('Access token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: UniversalFile(
|
fileData: UniversalFile(
|
||||||
data: result,
|
data: result,
|
||||||
type: UniversalFileType.image,
|
type: UniversalFileType.image,
|
||||||
|
@@ -20,6 +20,8 @@ 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/pool_provider.dart';
|
||||||
|
import 'package:island/models/file_pool.dart';
|
||||||
|
|
||||||
class SettingsScreen extends HookConsumerWidget {
|
class SettingsScreen extends HookConsumerWidget {
|
||||||
const SettingsScreen({super.key});
|
const SettingsScreen({super.key});
|
||||||
@@ -33,7 +35,7 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
final isDesktop =
|
final isDesktop =
|
||||||
!kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);
|
!kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);
|
||||||
final isWide = isWideScreen(context);
|
final isWide = isWideScreen(context);
|
||||||
|
final poolsAsync = ref.watch(poolsProvider);
|
||||||
final docBasepath = useState<String?>(null);
|
final docBasepath = useState<String?>(null);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
@@ -367,6 +369,66 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
poolsAsync.when(
|
||||||
|
data: (pools) {
|
||||||
|
final validPools = pools.filterValid();
|
||||||
|
final currentPoolId = resolveDefaultPoolId(ref, pools);
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
isThreeLine: true,
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
title: Text('settingsDefaultPool').tr(),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
|
leading: const Icon(Symbols.cloud),
|
||||||
|
subtitle: Text(
|
||||||
|
validPools
|
||||||
|
.firstWhereOrNull((p) => p.id == currentPoolId)
|
||||||
|
?.description ??
|
||||||
|
'settingsDefaultPoolHelper'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
trailing: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<String>(
|
||||||
|
isExpanded: true,
|
||||||
|
items:
|
||||||
|
validPools.map((p) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: p.id,
|
||||||
|
child: Text(p.name).fontSize(14),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
value: currentPoolId,
|
||||||
|
onChanged: (value) {
|
||||||
|
ref
|
||||||
|
.read(appSettingsNotifierProvider.notifier)
|
||||||
|
.setDefaultPoolId(value);
|
||||||
|
showSnackBar('settingsApplied'.tr());
|
||||||
|
},
|
||||||
|
buttonStyleData: const ButtonStyleData(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 5),
|
||||||
|
height: 40,
|
||||||
|
width: 220,
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(height: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading:
|
||||||
|
() => const ListTile(
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
title: Text('Loading pools...'),
|
||||||
|
leading: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(err, st) => ListTile(
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
title: Text('settingsDefaultPool').tr(),
|
||||||
|
subtitle: Text('Error: $err'),
|
||||||
|
leading: const Icon(Icons.error, color: Colors.red),
|
||||||
|
),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
final behaviorSettings = [
|
final behaviorSettings = [
|
||||||
|
@@ -11,6 +11,8 @@ import 'package:island/services/file_uploader.dart';
|
|||||||
import 'package:native_exif/native_exif.dart';
|
import 'package:native_exif/native_exif.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
enum FileUploadMode { generic, mediaSafe }
|
||||||
|
|
||||||
Future<XFile?> cropImage(
|
Future<XFile?> cropImage(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required XFile image,
|
required XFile image,
|
||||||
@@ -40,49 +42,46 @@ Future<XFile?> cropImage(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Completer<SnCloudFile?> putMediaToCloud({
|
Completer<SnCloudFile?> putFileToCloud({
|
||||||
required UniversalFile fileData,
|
required UniversalFile fileData,
|
||||||
required String atk,
|
required String atk,
|
||||||
required String baseUrl,
|
required String baseUrl,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
String? filename,
|
String? filename,
|
||||||
String? mimetype,
|
String? mimetype,
|
||||||
|
FileUploadMode? mode,
|
||||||
Function(double progress, Duration estimate)? onProgress,
|
Function(double progress, Duration estimate)? onProgress,
|
||||||
}) {
|
}) {
|
||||||
final completer = Completer<SnCloudFile?>();
|
final completer = Completer<SnCloudFile?>();
|
||||||
|
|
||||||
// Process the image to remove GPS EXIF data if needed
|
final effectiveMode =
|
||||||
if (fileData.isOnDevice && fileData.type == UniversalFileType.image) {
|
mode ??
|
||||||
|
(fileData.type == UniversalFileType.file
|
||||||
|
? FileUploadMode.generic
|
||||||
|
: FileUploadMode.mediaSafe);
|
||||||
|
|
||||||
|
if (effectiveMode == FileUploadMode.mediaSafe &&
|
||||||
|
fileData.isOnDevice &&
|
||||||
|
fileData.type == UniversalFileType.image) {
|
||||||
final data = fileData.data;
|
final data = fileData.data;
|
||||||
if (data is XFile && !kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
if (data is XFile && !kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
||||||
// Use native_exif to selectively remove GPS data
|
|
||||||
Exif.fromPath(data.path)
|
Exif.fromPath(data.path)
|
||||||
.then((exif) {
|
.then((exif) async {
|
||||||
// Remove GPS-related attributes
|
final gpsAttributes = {
|
||||||
final gpsAttributes = [
|
'GPSLatitude': '',
|
||||||
'GPSLatitude',
|
'GPSLatitudeRef': '',
|
||||||
'GPSLatitudeRef',
|
'GPSLongitude': '',
|
||||||
'GPSLongitude',
|
'GPSLongitudeRef': '',
|
||||||
'GPSLongitudeRef',
|
'GPSAltitude': '',
|
||||||
'GPSAltitude',
|
'GPSAltitudeRef': '',
|
||||||
'GPSAltitudeRef',
|
'GPSTimeStamp': '',
|
||||||
'GPSTimeStamp',
|
'GPSProcessingMethod': '',
|
||||||
'GPSProcessingMethod',
|
'GPSDateStamp': '',
|
||||||
'GPSDateStamp',
|
};
|
||||||
];
|
await exif.writeAttributes(gpsAttributes);
|
||||||
|
|
||||||
// Create a map of attributes to clear
|
|
||||||
final clearAttributes = <String, String>{};
|
|
||||||
for (final attr in gpsAttributes) {
|
|
||||||
clearAttributes[attr] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write empty values to remove GPS data
|
|
||||||
return exif.writeAttributes(clearAttributes);
|
|
||||||
})
|
})
|
||||||
.then((_) {
|
.then(
|
||||||
// Continue with upload after GPS data is removed
|
(_) => _processUpload(
|
||||||
_processUpload(
|
|
||||||
fileData,
|
fileData,
|
||||||
atk,
|
atk,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@@ -91,12 +90,11 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
mimetype,
|
mimetype,
|
||||||
onProgress,
|
onProgress,
|
||||||
completer,
|
completer,
|
||||||
);
|
),
|
||||||
})
|
)
|
||||||
.catchError((e) {
|
.catchError((e) {
|
||||||
// If there's an error, continue with the original file
|
|
||||||
debugPrint('Error removing GPS EXIF data: $e');
|
debugPrint('Error removing GPS EXIF data: $e');
|
||||||
_processUpload(
|
return _processUpload(
|
||||||
fileData,
|
fileData,
|
||||||
atk,
|
atk,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@@ -112,7 +110,6 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not an image or on web, continue with normal upload
|
|
||||||
_processUpload(
|
_processUpload(
|
||||||
fileData,
|
fileData,
|
||||||
atk,
|
atk,
|
||||||
|
@@ -55,7 +55,7 @@ class CloudFilePicker extends HookConsumerWidget {
|
|||||||
uploadPosition.value = idx;
|
uploadPosition.value = idx;
|
||||||
final file = files.value[idx];
|
final file = files.value[idx];
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: file,
|
fileData: file,
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
@@ -19,6 +20,7 @@ import 'package:island/widgets/alert.dart';
|
|||||||
import 'package:island/widgets/post/compose_link_attachments.dart';
|
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_recorder.dart';
|
import 'package:island/widgets/post/compose_recorder.dart';
|
||||||
|
import 'package:island/pods/pool_provider.dart';
|
||||||
import 'package:pasteboard/pasteboard.dart';
|
import 'package:pasteboard/pasteboard.dart';
|
||||||
import 'package:textfield_tags/textfield_tags.dart';
|
import 'package:textfield_tags/textfield_tags.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
@@ -183,7 +185,7 @@ class ComposeLogic {
|
|||||||
if (attachment.data is! SnCloudFile) {
|
if (attachment.data is! SnCloudFile) {
|
||||||
try {
|
try {
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: attachment,
|
fileData: attachment,
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
@@ -386,6 +388,30 @@ class ComposeLogic {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<void> pickGeneralFile(WidgetRef ref, ComposeState state) async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.any,
|
||||||
|
allowMultiple: true,
|
||||||
|
);
|
||||||
|
if (result == null || result.count == 0) return;
|
||||||
|
|
||||||
|
final newFiles = <UniversalFile>[];
|
||||||
|
|
||||||
|
for (final f in result.files) {
|
||||||
|
if (f.path == null) continue;
|
||||||
|
|
||||||
|
final mimeType =
|
||||||
|
lookupMimeType(f.path!, headerBytes: f.bytes) ??
|
||||||
|
'application/octet-stream';
|
||||||
|
final xfile = XFile(f.path!, name: f.name, mimeType: mimeType);
|
||||||
|
|
||||||
|
final uf = UniversalFile(data: xfile, type: UniversalFileType.file);
|
||||||
|
newFiles.add(uf);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.attachments.value = [...state.attachments.value, ...newFiles];
|
||||||
|
}
|
||||||
|
|
||||||
static Future<void> pickPhotoMedia(WidgetRef ref, ComposeState state) async {
|
static Future<void> pickPhotoMedia(WidgetRef ref, ComposeState state) async {
|
||||||
final result = await FilePicker.platform.pickFiles(
|
final result = await FilePicker.platform.pickFiles(
|
||||||
type: FileType.image,
|
type: FileType.image,
|
||||||
@@ -479,8 +505,9 @@ class ComposeLogic {
|
|||||||
static Future<void> uploadAttachment(
|
static Future<void> uploadAttachment(
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
ComposeState state,
|
ComposeState state,
|
||||||
int index,
|
int index, {
|
||||||
) async {
|
String? poolId, // For Unit Test
|
||||||
|
}) async {
|
||||||
final attachment = state.attachments.value[index];
|
final attachment = state.attachments.value[index];
|
||||||
if (attachment.isOnCloud) return;
|
if (attachment.isOnCloud) return;
|
||||||
|
|
||||||
@@ -489,22 +516,34 @@ class ComposeLogic {
|
|||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update progress state
|
|
||||||
state.attachmentProgress.value = {
|
state.attachmentProgress.value = {
|
||||||
...state.attachmentProgress.value,
|
...state.attachmentProgress.value,
|
||||||
index: 0,
|
index: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Upload file to cloud
|
SnCloudFile? cloudFile;
|
||||||
final cloudFile =
|
|
||||||
await putMediaToCloud(
|
final pools = await ref.read(poolsProvider.future);
|
||||||
|
final selectedPoolId = resolveDefaultPoolId(ref, pools);
|
||||||
|
|
||||||
|
cloudFile =
|
||||||
|
await putFileToCloud(
|
||||||
fileData: attachment,
|
fileData: attachment,
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename: attachment.data.name ?? 'Post media',
|
poolId: selectedPoolId,
|
||||||
|
filename:
|
||||||
|
attachment.data.name ??
|
||||||
|
(attachment.type == UniversalFileType.file
|
||||||
|
? 'General file'
|
||||||
|
: 'Post media'),
|
||||||
mimetype:
|
mimetype:
|
||||||
attachment.data.mimeType ??
|
attachment.data.mimeType ??
|
||||||
getMimeTypeFromFileType(attachment.type),
|
getMimeTypeFromFileType(attachment.type),
|
||||||
|
mode:
|
||||||
|
attachment.type == UniversalFileType.file
|
||||||
|
? FileUploadMode.generic
|
||||||
|
: FileUploadMode.mediaSafe,
|
||||||
onProgress: (progress, _) {
|
onProgress: (progress, _) {
|
||||||
state.attachmentProgress.value = {
|
state.attachmentProgress.value = {
|
||||||
...state.attachmentProgress.value,
|
...state.attachmentProgress.value,
|
||||||
@@ -517,14 +556,12 @@ class ComposeLogic {
|
|||||||
throw ArgumentError('Failed to upload the file...');
|
throw ArgumentError('Failed to upload the file...');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update attachments list with cloud file
|
|
||||||
final clone = List.of(state.attachments.value);
|
final clone = List.of(state.attachments.value);
|
||||||
clone[index] = UniversalFile(data: cloudFile, type: attachment.type);
|
clone[index] = UniversalFile(data: cloudFile, type: attachment.type);
|
||||||
state.attachments.value = clone;
|
state.attachments.value = clone;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err.toString());
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up progress state
|
|
||||||
state.attachmentProgress.value = {...state.attachmentProgress.value}
|
state.attachmentProgress.value = {...state.attachmentProgress.value}
|
||||||
..remove(index);
|
..remove(index);
|
||||||
}
|
}
|
||||||
@@ -643,7 +680,6 @@ class ComposeLogic {
|
|||||||
.where((entry) => entry.value.isOnDevice)
|
.where((entry) => entry.value.isOnDevice)
|
||||||
.map((entry) => uploadAttachment(ref, state, entry.key)),
|
.map((entry) => uploadAttachment(ref, state, entry.key)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prepare API request
|
// Prepare API request
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final isNewPost = originalPost == null;
|
final isNewPost = originalPost == null;
|
||||||
|
@@ -25,6 +25,10 @@ class ComposeToolbar extends HookConsumerWidget {
|
|||||||
ComposeLogic.pickVideoMedia(ref, state);
|
ComposeLogic.pickVideoMedia(ref, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pickGeneralFile() {
|
||||||
|
ComposeLogic.pickGeneralFile(ref, state);
|
||||||
|
}
|
||||||
|
|
||||||
void addAudio() {
|
void addAudio() {
|
||||||
ComposeLogic.recordAudioMedia(ref, state, context);
|
ComposeLogic.recordAudioMedia(ref, state, context);
|
||||||
}
|
}
|
||||||
@@ -96,6 +100,12 @@ class ComposeToolbar extends HookConsumerWidget {
|
|||||||
icon: const Icon(Symbols.mic),
|
icon: const Icon(Symbols.mic),
|
||||||
color: colorScheme.primary,
|
color: colorScheme.primary,
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: pickGeneralFile,
|
||||||
|
tooltip: 'uploadFile'.tr(),
|
||||||
|
icon: const Icon(Symbols.file_upload),
|
||||||
|
color: colorScheme.primary,
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: linkAttachment,
|
onPressed: linkAttachment,
|
||||||
icon: const Icon(Symbols.attach_file),
|
icon: const Icon(Symbols.attach_file),
|
||||||
|
@@ -247,7 +247,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
for (var idx = 0; idx < universalFiles.length; idx++) {
|
for (var idx = 0; idx < universalFiles.length; idx++) {
|
||||||
final file = universalFiles[idx];
|
final file = universalFiles[idx];
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putFileToCloud(
|
||||||
fileData: file,
|
fileData: file,
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: serverUrl,
|
baseUrl: serverUrl,
|
||||||
|
Reference in New Issue
Block a user