Able to edit publication site config

This commit is contained in:
2025-12-11 23:21:08 +08:00
parent fb51d2076f
commit de20803119
8 changed files with 918 additions and 221 deletions

View File

@@ -3,6 +3,28 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'publication_site.freezed.dart'; part 'publication_site.freezed.dart';
part 'publication_site.g.dart'; part 'publication_site.g.dart';
@freezed
sealed class SnPublicationSiteNavItems with _$SnPublicationSiteNavItems {
const factory SnPublicationSiteNavItems({
required String label,
required String href,
}) = _SnPublicationSiteNavItems;
factory SnPublicationSiteNavItems.fromJson(Map<String, dynamic> json) =>
_$SnPublicationSiteNavItemsFromJson(json);
}
@freezed
sealed class SnPublicationSiteConfig with _$SnPublicationSiteConfig {
const factory SnPublicationSiteConfig({
String? styleOverride,
List<SnPublicationSiteNavItems>? navItems,
}) = _SnPublicationSiteConfig;
factory SnPublicationSiteConfig.fromJson(Map<String, dynamic> json) =>
_$SnPublicationSiteConfigFromJson(json);
}
@freezed @freezed
sealed class SnPublicationSite with _$SnPublicationSite { sealed class SnPublicationSite with _$SnPublicationSite {
const factory SnPublicationSite({ const factory SnPublicationSite({
@@ -16,6 +38,7 @@ sealed class SnPublicationSite with _$SnPublicationSite {
required DateTime createdAt, required DateTime createdAt,
required DateTime updatedAt, required DateTime updatedAt,
required List<SnPublicationPage> pages, required List<SnPublicationPage> pages,
required SnPublicationSiteConfig config,
}) = _SnPublicationSite; }) = _SnPublicationSite;
factory SnPublicationSite.fromJson(Map<String, dynamic> json) => factory SnPublicationSite.fromJson(Map<String, dynamic> json) =>

View File

@@ -12,10 +12,538 @@ part of 'publication_site.dart';
// dart format off // dart format off
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
/// @nodoc
mixin _$SnPublicationSiteNavItems {
String get label; String get href;
/// Create a copy of SnPublicationSiteNavItems
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnPublicationSiteNavItemsCopyWith<SnPublicationSiteNavItems> get copyWith => _$SnPublicationSiteNavItemsCopyWithImpl<SnPublicationSiteNavItems>(this as SnPublicationSiteNavItems, _$identity);
/// Serializes this SnPublicationSiteNavItems to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublicationSiteNavItems&&(identical(other.label, label) || other.label == label)&&(identical(other.href, href) || other.href == href));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,label,href);
@override
String toString() {
return 'SnPublicationSiteNavItems(label: $label, href: $href)';
}
}
/// @nodoc
abstract mixin class $SnPublicationSiteNavItemsCopyWith<$Res> {
factory $SnPublicationSiteNavItemsCopyWith(SnPublicationSiteNavItems value, $Res Function(SnPublicationSiteNavItems) _then) = _$SnPublicationSiteNavItemsCopyWithImpl;
@useResult
$Res call({
String label, String href
});
}
/// @nodoc
class _$SnPublicationSiteNavItemsCopyWithImpl<$Res>
implements $SnPublicationSiteNavItemsCopyWith<$Res> {
_$SnPublicationSiteNavItemsCopyWithImpl(this._self, this._then);
final SnPublicationSiteNavItems _self;
final $Res Function(SnPublicationSiteNavItems) _then;
/// Create a copy of SnPublicationSiteNavItems
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? label = null,Object? href = null,}) {
return _then(_self.copyWith(
label: null == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String,href: null == href ? _self.href : href // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [SnPublicationSiteNavItems].
extension SnPublicationSiteNavItemsPatterns on SnPublicationSiteNavItems {
/// 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( _SnPublicationSiteNavItems value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems() 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( _SnPublicationSiteNavItems value) $default,){
final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems():
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( _SnPublicationSiteNavItems value)? $default,){
final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems() 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 label, String href)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems() when $default != null:
return $default(_that.label,_that.href);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 label, String href) $default,) {final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems():
return $default(_that.label,_that.href);}
}
/// 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 label, String href)? $default,) {final _that = this;
switch (_that) {
case _SnPublicationSiteNavItems() when $default != null:
return $default(_that.label,_that.href);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnPublicationSiteNavItems implements SnPublicationSiteNavItems {
const _SnPublicationSiteNavItems({required this.label, required this.href});
factory _SnPublicationSiteNavItems.fromJson(Map<String, dynamic> json) => _$SnPublicationSiteNavItemsFromJson(json);
@override final String label;
@override final String href;
/// Create a copy of SnPublicationSiteNavItems
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnPublicationSiteNavItemsCopyWith<_SnPublicationSiteNavItems> get copyWith => __$SnPublicationSiteNavItemsCopyWithImpl<_SnPublicationSiteNavItems>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnPublicationSiteNavItemsToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublicationSiteNavItems&&(identical(other.label, label) || other.label == label)&&(identical(other.href, href) || other.href == href));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,label,href);
@override
String toString() {
return 'SnPublicationSiteNavItems(label: $label, href: $href)';
}
}
/// @nodoc
abstract mixin class _$SnPublicationSiteNavItemsCopyWith<$Res> implements $SnPublicationSiteNavItemsCopyWith<$Res> {
factory _$SnPublicationSiteNavItemsCopyWith(_SnPublicationSiteNavItems value, $Res Function(_SnPublicationSiteNavItems) _then) = __$SnPublicationSiteNavItemsCopyWithImpl;
@override @useResult
$Res call({
String label, String href
});
}
/// @nodoc
class __$SnPublicationSiteNavItemsCopyWithImpl<$Res>
implements _$SnPublicationSiteNavItemsCopyWith<$Res> {
__$SnPublicationSiteNavItemsCopyWithImpl(this._self, this._then);
final _SnPublicationSiteNavItems _self;
final $Res Function(_SnPublicationSiteNavItems) _then;
/// Create a copy of SnPublicationSiteNavItems
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? label = null,Object? href = null,}) {
return _then(_SnPublicationSiteNavItems(
label: null == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String,href: null == href ? _self.href : href // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
mixin _$SnPublicationSiteConfig {
String? get styleOverride; List<SnPublicationSiteNavItems>? get navItems;
/// Create a copy of SnPublicationSiteConfig
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnPublicationSiteConfigCopyWith<SnPublicationSiteConfig> get copyWith => _$SnPublicationSiteConfigCopyWithImpl<SnPublicationSiteConfig>(this as SnPublicationSiteConfig, _$identity);
/// Serializes this SnPublicationSiteConfig to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublicationSiteConfig&&(identical(other.styleOverride, styleOverride) || other.styleOverride == styleOverride)&&const DeepCollectionEquality().equals(other.navItems, navItems));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,styleOverride,const DeepCollectionEquality().hash(navItems));
@override
String toString() {
return 'SnPublicationSiteConfig(styleOverride: $styleOverride, navItems: $navItems)';
}
}
/// @nodoc
abstract mixin class $SnPublicationSiteConfigCopyWith<$Res> {
factory $SnPublicationSiteConfigCopyWith(SnPublicationSiteConfig value, $Res Function(SnPublicationSiteConfig) _then) = _$SnPublicationSiteConfigCopyWithImpl;
@useResult
$Res call({
String? styleOverride, List<SnPublicationSiteNavItems>? navItems
});
}
/// @nodoc
class _$SnPublicationSiteConfigCopyWithImpl<$Res>
implements $SnPublicationSiteConfigCopyWith<$Res> {
_$SnPublicationSiteConfigCopyWithImpl(this._self, this._then);
final SnPublicationSiteConfig _self;
final $Res Function(SnPublicationSiteConfig) _then;
/// Create a copy of SnPublicationSiteConfig
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? styleOverride = freezed,Object? navItems = freezed,}) {
return _then(_self.copyWith(
styleOverride: freezed == styleOverride ? _self.styleOverride : styleOverride // ignore: cast_nullable_to_non_nullable
as String?,navItems: freezed == navItems ? _self.navItems : navItems // ignore: cast_nullable_to_non_nullable
as List<SnPublicationSiteNavItems>?,
));
}
}
/// Adds pattern-matching-related methods to [SnPublicationSiteConfig].
extension SnPublicationSiteConfigPatterns on SnPublicationSiteConfig {
/// 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( _SnPublicationSiteConfig value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnPublicationSiteConfig() 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( _SnPublicationSiteConfig value) $default,){
final _that = this;
switch (_that) {
case _SnPublicationSiteConfig():
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( _SnPublicationSiteConfig value)? $default,){
final _that = this;
switch (_that) {
case _SnPublicationSiteConfig() 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? styleOverride, List<SnPublicationSiteNavItems>? navItems)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnPublicationSiteConfig() when $default != null:
return $default(_that.styleOverride,_that.navItems);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? styleOverride, List<SnPublicationSiteNavItems>? navItems) $default,) {final _that = this;
switch (_that) {
case _SnPublicationSiteConfig():
return $default(_that.styleOverride,_that.navItems);}
}
/// 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? styleOverride, List<SnPublicationSiteNavItems>? navItems)? $default,) {final _that = this;
switch (_that) {
case _SnPublicationSiteConfig() when $default != null:
return $default(_that.styleOverride,_that.navItems);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnPublicationSiteConfig implements SnPublicationSiteConfig {
const _SnPublicationSiteConfig({this.styleOverride, final List<SnPublicationSiteNavItems>? navItems}): _navItems = navItems;
factory _SnPublicationSiteConfig.fromJson(Map<String, dynamic> json) => _$SnPublicationSiteConfigFromJson(json);
@override final String? styleOverride;
final List<SnPublicationSiteNavItems>? _navItems;
@override List<SnPublicationSiteNavItems>? get navItems {
final value = _navItems;
if (value == null) return null;
if (_navItems is EqualUnmodifiableListView) return _navItems;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
/// Create a copy of SnPublicationSiteConfig
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnPublicationSiteConfigCopyWith<_SnPublicationSiteConfig> get copyWith => __$SnPublicationSiteConfigCopyWithImpl<_SnPublicationSiteConfig>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnPublicationSiteConfigToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublicationSiteConfig&&(identical(other.styleOverride, styleOverride) || other.styleOverride == styleOverride)&&const DeepCollectionEquality().equals(other._navItems, _navItems));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,styleOverride,const DeepCollectionEquality().hash(_navItems));
@override
String toString() {
return 'SnPublicationSiteConfig(styleOverride: $styleOverride, navItems: $navItems)';
}
}
/// @nodoc
abstract mixin class _$SnPublicationSiteConfigCopyWith<$Res> implements $SnPublicationSiteConfigCopyWith<$Res> {
factory _$SnPublicationSiteConfigCopyWith(_SnPublicationSiteConfig value, $Res Function(_SnPublicationSiteConfig) _then) = __$SnPublicationSiteConfigCopyWithImpl;
@override @useResult
$Res call({
String? styleOverride, List<SnPublicationSiteNavItems>? navItems
});
}
/// @nodoc
class __$SnPublicationSiteConfigCopyWithImpl<$Res>
implements _$SnPublicationSiteConfigCopyWith<$Res> {
__$SnPublicationSiteConfigCopyWithImpl(this._self, this._then);
final _SnPublicationSiteConfig _self;
final $Res Function(_SnPublicationSiteConfig) _then;
/// Create a copy of SnPublicationSiteConfig
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? styleOverride = freezed,Object? navItems = freezed,}) {
return _then(_SnPublicationSiteConfig(
styleOverride: freezed == styleOverride ? _self.styleOverride : styleOverride // ignore: cast_nullable_to_non_nullable
as String?,navItems: freezed == navItems ? _self._navItems : navItems // ignore: cast_nullable_to_non_nullable
as List<SnPublicationSiteNavItems>?,
));
}
}
/// @nodoc /// @nodoc
mixin _$SnPublicationSite { mixin _$SnPublicationSite {
String get id; String get slug; String get name; String? get description; int? get mode; String get publisherId; String get accountId; DateTime get createdAt; DateTime get updatedAt; List<SnPublicationPage> get pages; String get id; String get slug; String get name; String? get description; int? get mode; String get publisherId; String get accountId; DateTime get createdAt; DateTime get updatedAt; List<SnPublicationPage> get pages; SnPublicationSiteConfig get config;
/// Create a copy of SnPublicationSite /// Create a copy of SnPublicationSite
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +556,16 @@ $SnPublicationSiteCopyWith<SnPublicationSite> get copyWith => _$SnPublicationSit
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublicationSite&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&const DeepCollectionEquality().equals(other.pages, pages)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublicationSite&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&const DeepCollectionEquality().equals(other.pages, pages)&&(identical(other.config, config) || other.config == config));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,slug,name,description,mode,publisherId,accountId,createdAt,updatedAt,const DeepCollectionEquality().hash(pages)); int get hashCode => Object.hash(runtimeType,id,slug,name,description,mode,publisherId,accountId,createdAt,updatedAt,const DeepCollectionEquality().hash(pages),config);
@override @override
String toString() { String toString() {
return 'SnPublicationSite(id: $id, slug: $slug, name: $name, description: $description, mode: $mode, publisherId: $publisherId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, pages: $pages)'; return 'SnPublicationSite(id: $id, slug: $slug, name: $name, description: $description, mode: $mode, publisherId: $publisherId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, pages: $pages, config: $config)';
} }
@@ -48,11 +576,11 @@ abstract mixin class $SnPublicationSiteCopyWith<$Res> {
factory $SnPublicationSiteCopyWith(SnPublicationSite value, $Res Function(SnPublicationSite) _then) = _$SnPublicationSiteCopyWithImpl; factory $SnPublicationSiteCopyWith(SnPublicationSite value, $Res Function(SnPublicationSite) _then) = _$SnPublicationSiteCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages, SnPublicationSiteConfig config
}); });
$SnPublicationSiteConfigCopyWith<$Res> get config;
} }
/// @nodoc /// @nodoc
@@ -65,7 +593,7 @@ class _$SnPublicationSiteCopyWithImpl<$Res>
/// Create a copy of SnPublicationSite /// Create a copy of SnPublicationSite
/// 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? slug = null,Object? name = null,Object? description = freezed,Object? mode = freezed,Object? publisherId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? pages = null,}) { @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = null,Object? description = freezed,Object? mode = freezed,Object? publisherId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? pages = null,Object? config = null,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
@@ -77,10 +605,20 @@ as String,accountId: null == accountId ? _self.accountId : accountId // ignore:
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,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable as DateTime,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable
as List<SnPublicationPage>, as List<SnPublicationPage>,config: null == config ? _self.config : config // ignore: cast_nullable_to_non_nullable
as SnPublicationSiteConfig,
)); ));
} }
/// Create a copy of SnPublicationSite
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnPublicationSiteConfigCopyWith<$Res> get config {
return $SnPublicationSiteConfigCopyWith<$Res>(_self.config, (value) {
return _then(_self.copyWith(config: value));
});
}
} }
@@ -159,10 +697,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages, SnPublicationSiteConfig config)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnPublicationSite() when $default != null: case _SnPublicationSite() when $default != null:
return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages);case _: return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages,_that.config);case _:
return orElse(); return orElse();
} }
@@ -180,10 +718,10 @@ return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_tha
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages, SnPublicationSiteConfig config) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnPublicationSite(): case _SnPublicationSite():
return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages);} return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages,_that.config);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -197,10 +735,10 @@ return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_tha
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages, SnPublicationSiteConfig config)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnPublicationSite() when $default != null: case _SnPublicationSite() when $default != null:
return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages);case _: return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_that.publisherId,_that.accountId,_that.createdAt,_that.updatedAt,_that.pages,_that.config);case _:
return null; return null;
} }
@@ -212,7 +750,7 @@ return $default(_that.id,_that.slug,_that.name,_that.description,_that.mode,_tha
@JsonSerializable() @JsonSerializable()
class _SnPublicationSite implements SnPublicationSite { class _SnPublicationSite implements SnPublicationSite {
const _SnPublicationSite({required this.id, required this.slug, required this.name, this.description, this.mode, required this.publisherId, required this.accountId, required this.createdAt, required this.updatedAt, required final List<SnPublicationPage> pages}): _pages = pages; const _SnPublicationSite({required this.id, required this.slug, required this.name, this.description, this.mode, required this.publisherId, required this.accountId, required this.createdAt, required this.updatedAt, required final List<SnPublicationPage> pages, required this.config}): _pages = pages;
factory _SnPublicationSite.fromJson(Map<String, dynamic> json) => _$SnPublicationSiteFromJson(json); factory _SnPublicationSite.fromJson(Map<String, dynamic> json) => _$SnPublicationSiteFromJson(json);
@override final String id; @override final String id;
@@ -231,6 +769,7 @@ class _SnPublicationSite implements SnPublicationSite {
return EqualUnmodifiableListView(_pages); return EqualUnmodifiableListView(_pages);
} }
@override final SnPublicationSiteConfig config;
/// Create a copy of SnPublicationSite /// Create a copy of SnPublicationSite
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@@ -245,16 +784,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublicationSite&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&const DeepCollectionEquality().equals(other._pages, _pages)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublicationSite&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.mode, mode) || other.mode == mode)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&const DeepCollectionEquality().equals(other._pages, _pages)&&(identical(other.config, config) || other.config == config));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,slug,name,description,mode,publisherId,accountId,createdAt,updatedAt,const DeepCollectionEquality().hash(_pages)); int get hashCode => Object.hash(runtimeType,id,slug,name,description,mode,publisherId,accountId,createdAt,updatedAt,const DeepCollectionEquality().hash(_pages),config);
@override @override
String toString() { String toString() {
return 'SnPublicationSite(id: $id, slug: $slug, name: $name, description: $description, mode: $mode, publisherId: $publisherId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, pages: $pages)'; return 'SnPublicationSite(id: $id, slug: $slug, name: $name, description: $description, mode: $mode, publisherId: $publisherId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, pages: $pages, config: $config)';
} }
@@ -265,11 +804,11 @@ abstract mixin class _$SnPublicationSiteCopyWith<$Res> implements $SnPublication
factory _$SnPublicationSiteCopyWith(_SnPublicationSite value, $Res Function(_SnPublicationSite) _then) = __$SnPublicationSiteCopyWithImpl; factory _$SnPublicationSiteCopyWith(_SnPublicationSite value, $Res Function(_SnPublicationSite) _then) = __$SnPublicationSiteCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages String id, String slug, String name, String? description, int? mode, String publisherId, String accountId, DateTime createdAt, DateTime updatedAt, List<SnPublicationPage> pages, SnPublicationSiteConfig config
}); });
@override $SnPublicationSiteConfigCopyWith<$Res> get config;
} }
/// @nodoc /// @nodoc
@@ -282,7 +821,7 @@ class __$SnPublicationSiteCopyWithImpl<$Res>
/// Create a copy of SnPublicationSite /// Create a copy of SnPublicationSite
/// 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? slug = null,Object? name = null,Object? description = freezed,Object? mode = freezed,Object? publisherId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? pages = null,}) { @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = null,Object? description = freezed,Object? mode = freezed,Object? publisherId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? pages = null,Object? config = null,}) {
return _then(_SnPublicationSite( return _then(_SnPublicationSite(
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,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
@@ -294,11 +833,21 @@ as String,accountId: null == accountId ? _self.accountId : accountId // ignore:
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,pages: null == pages ? _self._pages : pages // ignore: cast_nullable_to_non_nullable as DateTime,pages: null == pages ? _self._pages : pages // ignore: cast_nullable_to_non_nullable
as List<SnPublicationPage>, as List<SnPublicationPage>,config: null == config ? _self.config : config // ignore: cast_nullable_to_non_nullable
as SnPublicationSiteConfig,
)); ));
} }
/// Create a copy of SnPublicationSite
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnPublicationSiteConfigCopyWith<$Res> get config {
return $SnPublicationSiteConfigCopyWith<$Res>(_self.config, (value) {
return _then(_self.copyWith(config: value));
});
}
} }

View File

@@ -6,6 +6,35 @@ part of 'publication_site.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
_SnPublicationSiteNavItems _$SnPublicationSiteNavItemsFromJson(
Map<String, dynamic> json,
) => _SnPublicationSiteNavItems(
label: json['label'] as String,
href: json['href'] as String,
);
Map<String, dynamic> _$SnPublicationSiteNavItemsToJson(
_SnPublicationSiteNavItems instance,
) => <String, dynamic>{'label': instance.label, 'href': instance.href};
_SnPublicationSiteConfig _$SnPublicationSiteConfigFromJson(
Map<String, dynamic> json,
) => _SnPublicationSiteConfig(
styleOverride: json['style_override'] as String?,
navItems: (json['nav_items'] as List<dynamic>?)
?.map(
(e) => SnPublicationSiteNavItems.fromJson(e as Map<String, dynamic>),
)
.toList(),
);
Map<String, dynamic> _$SnPublicationSiteConfigToJson(
_SnPublicationSiteConfig instance,
) => <String, dynamic>{
'style_override': instance.styleOverride,
'nav_items': instance.navItems?.map((e) => e.toJson()).toList(),
};
_SnPublicationSite _$SnPublicationSiteFromJson(Map<String, dynamic> json) => _SnPublicationSite _$SnPublicationSiteFromJson(Map<String, dynamic> json) =>
_SnPublicationSite( _SnPublicationSite(
id: json['id'] as String, id: json['id'] as String,
@@ -20,6 +49,9 @@ _SnPublicationSite _$SnPublicationSiteFromJson(Map<String, dynamic> json) =>
pages: (json['pages'] as List<dynamic>) pages: (json['pages'] as List<dynamic>)
.map((e) => SnPublicationPage.fromJson(e as Map<String, dynamic>)) .map((e) => SnPublicationPage.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
config: SnPublicationSiteConfig.fromJson(
json['config'] as Map<String, dynamic>,
),
); );
Map<String, dynamic> _$SnPublicationSiteToJson(_SnPublicationSite instance) => Map<String, dynamic> _$SnPublicationSiteToJson(_SnPublicationSite instance) =>
@@ -34,6 +66,7 @@ Map<String, dynamic> _$SnPublicationSiteToJson(_SnPublicationSite instance) =>
'created_at': instance.createdAt.toIso8601String(), 'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(),
'pages': instance.pages.map((e) => e.toJson()).toList(), 'pages': instance.pages.map((e) => e.toJson()).toList(),
'config': instance.config.toJson(),
}; };
_SnPublicationPage _$SnPublicationPageFromJson(Map<String, dynamic> json) => _SnPublicationPage _$SnPublicationPageFromJson(Map<String, dynamic> json) =>

View File

@@ -1,84 +0,0 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:island/models/publication_site.dart';
import 'package:island/pods/network.dart';
class SiteNotifier extends AsyncNotifier<SnPublicationSite> {
final ({String pubName, String? siteId}) arg;
SiteNotifier(this.arg);
@override
FutureOr<SnPublicationSite> build() async {
if (arg.siteId == null || arg.siteId!.isEmpty) {
return SnPublicationSite(
id: '',
slug: '',
name: '',
publisherId: arg.pubName,
accountId: '',
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
pages: [],
);
}
try {
final client = ref.read(apiClientProvider);
final response = await client.get('/sphere/sites/${arg.siteId}');
return SnPublicationSite.fromJson(response.data);
} catch (e) {
rethrow;
}
}
Future<void> saveSite(SnPublicationSite site) async {
state = const AsyncValue.loading();
try {
final client = ref.read(apiClientProvider);
final url = '/sphere/sites';
final response =
site.id.isEmpty
? await client.post(url, data: site.toJson())
: await client.patch('$url/${site.id}', data: site.toJson());
state = AsyncValue.data(SnPublicationSite.fromJson(response.data));
} catch (error, stackTrace) {
state = AsyncValue.error(error, stackTrace);
rethrow;
}
}
Future<void> deleteSite() async {
final siteId = arg.siteId;
if (siteId == null || siteId.isEmpty) return;
state = const AsyncValue.loading();
try {
final client = ref.read(apiClientProvider);
await client.delete('/sphere/sites/$siteId');
state = AsyncValue.data(
SnPublicationSite(
id: '',
slug: '',
name: '',
publisherId: arg.pubName,
accountId: '',
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
pages: [],
),
);
} catch (error, stackTrace) {
state = AsyncValue.error(error, stackTrace);
rethrow;
}
}
}
final siteNotifierProvider = AsyncNotifierProvider.autoDispose.family<
SiteNotifier,
SnPublicationSite,
({String pubName, String? siteId})
>(SiteNotifier.new);

View File

@@ -2,9 +2,11 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/publication_site.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/screens/creators/sites/site_detail.dart'; import 'package:island/screens/creators/sites/site_detail.dart';
import 'package:island/screens/creators/sites/site_list.dart'; import 'package:island/screens/creators/sites/site_list.dart';
import 'package:island/screens/creators/sites/widgets/site_config_form.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/response.dart'; import 'package:island/widgets/response.dart';
@@ -23,6 +25,7 @@ class SiteForm extends HookConsumerWidget {
TextEditingController nameController, TextEditingController nameController,
TextEditingController descriptionController, TextEditingController descriptionController,
ValueNotifier<int> modeController, ValueNotifier<int> modeController,
ValueNotifier<SnPublicationSiteConfig> configController,
Function() saveSite, Function() saveSite,
Function() deleteSite, Function() deleteSite,
String siteSlug, String siteSlug,
@@ -103,38 +106,40 @@ class SiteForm extends HookConsumerWidget {
} }
}, },
), ),
const SizedBox(height: 16),
SiteConfigForm(
initialConfig: configController.value,
onChanged: (value) => configController.value = value,
),
], ],
).padding(all: 20); ).padding(all: 20);
return SheetScaffold( return SheetScaffold(
titleText: 'editPublicationSite'.tr(), titleText: 'editPublicationSite'.tr(),
child: Builder( child: Builder(
builder: builder: (context) => SingleChildScrollView(
(context) => SingleChildScrollView( child: Column(
child: Column( children: [
Form(key: formKey, child: formFields),
Row(
children: [ children: [
Form(key: formKey, child: formFields), TextButton.icon(
Row( onPressed: deleteSite,
children: [ icon: const Icon(Symbols.delete_forever),
TextButton.icon( label: Text('deletePublicationSite'.tr()),
onPressed: deleteSite, style: TextButton.styleFrom(foregroundColor: Colors.red),
icon: const Icon(Symbols.delete_forever), ).alignment(Alignment.centerRight),
label: Text('deletePublicationSite'.tr()), const Spacer(),
style: TextButton.styleFrom( TextButton.icon(
foregroundColor: Colors.red, onPressed: saveSite,
), icon: const Icon(Symbols.save),
).alignment(Alignment.centerRight), label: Text('saveChanges').tr(),
const Spacer(), ),
TextButton.icon(
onPressed: saveSite,
icon: const Icon(Symbols.save),
label: Text('saveChanges').tr(),
),
],
).padding(horizontal: 20, vertical: 12),
], ],
), ).padding(horizontal: 20, vertical: 12),
), ],
),
),
), ),
); );
} }
@@ -146,6 +151,9 @@ class SiteForm extends HookConsumerWidget {
final nameController = useTextEditingController(); final nameController = useTextEditingController();
final descriptionController = useTextEditingController(); final descriptionController = useTextEditingController();
final modeController = useState<int>(0); // Default to fully managed (0) final modeController = useState<int>(0); // Default to fully managed (0)
final configController = useState<SnPublicationSiteConfig>(
const SnPublicationSiteConfig(),
);
final isLoading = useState(false); final isLoading = useState(false);
final saveSite = useCallback(() async { final saveSite = useCallback(() async {
@@ -162,6 +170,7 @@ class SiteForm extends HookConsumerWidget {
'mode': modeController.value, 'mode': modeController.value,
if (descriptionController.text.isNotEmpty) if (descriptionController.text.isNotEmpty)
'description': descriptionController.text, 'description': descriptionController.text,
'config': configController.value.toJson(),
}; };
if (siteSlug != null) { if (siteSlug != null) {
@@ -229,40 +238,39 @@ class SiteForm extends HookConsumerWidget {
nameController.text = site.name; nameController.text = site.name;
descriptionController.text = site.description ?? ''; descriptionController.text = site.description ?? '';
modeController.value = site.mode ?? 0; modeController.value = site.mode ?? 0;
configController.value = site.config;
} }
return null; return null;
}, [siteAsync]); }, [siteAsync]);
// Handle loading and error states for editing using AsyncValue // Handle loading and error states for editing using AsyncValue
return siteAsync.when( return siteAsync.when(
data: data: (_) => _buildForm(
(_) => _buildForm( formKey,
formKey, slugController,
slugController, nameController,
nameController, descriptionController,
descriptionController, modeController,
modeController, configController,
saveSite, saveSite,
deleteSite, deleteSite,
editingSiteSlug, editingSiteSlug,
), ),
loading: loading: () => SheetScaffold(
() => SheetScaffold( titleText: 'editPublicationSite'.tr(),
titleText: 'editPublicationSite'.tr(), child: Center(child: CircularProgressIndicator()),
child: Center(child: CircularProgressIndicator()), ),
), error: (error, _) => SheetScaffold(
error: titleText: 'editPublicationSite'.tr(),
(error, _) => SheetScaffold( child: ResponseErrorWidget(
titleText: 'editPublicationSite'.tr(), error: error.toString(),
child: ResponseErrorWidget( onRetry: () {
error: error.toString(), ref.invalidate(
onRetry: () { publicationSiteDetailProvider(pubName, editingSiteSlug),
ref.invalidate( );
publicationSiteDetailProvider(pubName, editingSiteSlug), },
); ),
}, ),
),
),
); );
} }
@@ -344,6 +352,11 @@ class SiteForm extends HookConsumerWidget {
} }
}, },
), ),
const SizedBox(height: 16),
SiteConfigForm(
initialConfig: configController.value,
onChanged: (value) => configController.value = value,
),
], ],
).padding(all: 20); ).padding(all: 20);
@@ -354,10 +367,9 @@ class SiteForm extends HookConsumerWidget {
).padding(horizontal: 20, vertical: 12); ).padding(horizontal: 20, vertical: 12);
return SheetScaffold( return SheetScaffold(
titleText: titleText: siteSlug == null
siteSlug == null ? 'newPublicationSite'.tr()
? 'newPublicationSite'.tr() : 'editPublicationSite'.tr(),
: 'editPublicationSite'.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [

View File

@@ -0,0 +1,172 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:island/models/publication_site.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart';
class SiteConfigForm extends HookWidget {
final SnPublicationSiteConfig? initialConfig;
final ValueChanged<SnPublicationSiteConfig> onChanged;
const SiteConfigForm({
super.key,
this.initialConfig,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
final styleOverrideController = useTextEditingController(
text: initialConfig?.styleOverride,
);
final navItems = useState<List<SnPublicationSiteNavItems>>(
initialConfig?.navItems ?? [],
);
useEffect(() {
void listener() {
onChanged(
SnPublicationSiteConfig(
styleOverride: styleOverrideController.text,
navItems: navItems.value,
),
);
}
styleOverrideController.addListener(listener);
return () => styleOverrideController.removeListener(listener);
}, [styleOverrideController, navItems.value]);
return Card(
margin: EdgeInsets.zero,
child: ExpansionTile(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
title: Text('siteConfig'.tr()),
children: [
Column(
spacing: 8,
children: [
TextFormField(
controller: styleOverrideController,
decoration: InputDecoration(
labelText: 'siteConfigStyleOverride'.tr(),
hintText: "You can paste your CSS here...",
alignLabelWithHint: true,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
minLines: 3,
maxLines: null,
).padding(bottom: 8),
Row(
children: [
Text('siteConfigNavItems'.tr()).bold(),
const Spacer(),
TextButton.icon(
onPressed: () {
navItems.value = [
...navItems.value,
const SnPublicationSiteNavItems(label: '', href: ''),
];
// Trigger update manually as list mutation doesn't trigger controller listener
onChanged(
SnPublicationSiteConfig(
styleOverride: styleOverrideController.text,
navItems: navItems.value,
),
);
},
icon: const Icon(Symbols.add),
label: Text('siteConfigAddNavItem'.tr()),
),
],
).padding(bottom: 4),
if (navItems.value.isEmpty)
Text('dataEmpty'.tr()).center().padding(vertical: 20),
...navItems.value.asMap().entries.map((entry) {
final index = entry.key;
final item = entry.value;
return Container(
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.outline,
width: 1,
),
borderRadius: BorderRadius.circular(10),
),
child: Column(
spacing: 12,
children: [
TextFormField(
initialValue: item.label,
decoration: InputDecoration(
labelText: 'siteConfigNavItemLabel'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onChanged: (value) {
final newItems = [...navItems.value];
newItems[index] = item.copyWith(label: value);
navItems.value = newItems;
onChanged(
SnPublicationSiteConfig(
styleOverride: styleOverrideController.text,
navItems: newItems,
),
);
},
),
TextFormField(
initialValue: item.href,
decoration: InputDecoration(
labelText: 'siteConfigNavItemHref'.tr(),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onChanged: (value) {
final newItems = [...navItems.value];
newItems[index] = item.copyWith(href: value);
navItems.value = newItems;
onChanged(
SnPublicationSiteConfig(
styleOverride: styleOverrideController.text,
navItems: newItems,
),
);
},
),
TextButton.icon(
onPressed: () {
final newItems = [...navItems.value];
newItems.removeAt(index);
navItems.value = newItems;
onChanged(
SnPublicationSiteConfig(
styleOverride: styleOverrideController.text,
navItems: newItems,
),
);
},
icon: const Icon(Symbols.delete),
label: Text('delete'.tr()),
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
).alignment(Alignment.centerRight),
],
).padding(horizontal: 16, vertical: 20),
);
}),
],
).padding(all: 16),
],
),
);
}
}

View File

@@ -114,10 +114,7 @@ return $default(_that);case _:
final _that = this; final _that = this;
switch (_that) { switch (_that) {
case _ProfileDecoration(): case _ProfileDecoration():
return $default(_that);case _: return $default(_that);}
throw StateError('Unexpected subclass');
}
} }
/// A variant of `map` that fallback to returning `null`. /// A variant of `map` that fallback to returning `null`.
/// ///
@@ -176,10 +173,7 @@ return $default(_that.text,_that.color,_that.textColor);case _:
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String text, Color color, Color? textColor) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String text, Color color, Color? textColor) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _ProfileDecoration(): case _ProfileDecoration():
return $default(_that.text,_that.color,_that.textColor);case _: return $default(_that.text,_that.color,_that.textColor);}
throw StateError('Unexpected subclass');
}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///

View File

@@ -37,10 +37,9 @@ class PageForm extends HookConsumerWidget {
final pageType = useState(initialType); final pageType = useState(initialType);
final htmlController = useTextEditingController( final htmlController = useTextEditingController(
text: text: pageType.value == 0
pageType.value == 0 ? (page?.config?['html'] ?? page?.config?['content'] ?? '')
? (page?.config?['html'] ?? page?.config?['content'] ?? '') : '',
: '',
); );
final titleController = useTextEditingController( final titleController = useTextEditingController(
text: pageType.value == 0 ? (page?.config?['title'] ?? '') : '', text: pageType.value == 0 ? (page?.config?['title'] ?? '') : '',
@@ -147,21 +146,20 @@ class PageForm extends HookConsumerWidget {
final confirmed = await showDialog<bool>( final confirmed = await showDialog<bool>(
context: context, context: context,
builder: builder: (context) => AlertDialog(
(context) => AlertDialog( title: const Text('Delete Page'),
title: const Text('Delete Page'), content: const Text('Are you sure you want to delete this page?'),
content: const Text('Are you sure you want to delete this page?'), actions: [
actions: [ TextButton(
TextButton( onPressed: () => Navigator.of(context).pop(false),
onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Delete'),
),
],
), ),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Delete'),
),
],
),
); );
if (confirmed != true) return; if (confirmed != true) return;
@@ -267,8 +265,8 @@ class PageForm extends HookConsumerWidget {
} }
return null; return null;
}, },
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
).padding(horizontal: 20), ).padding(horizontal: 20),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
@@ -286,8 +284,8 @@ class PageForm extends HookConsumerWidget {
} }
return null; return null;
}, },
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
).padding(horizontal: 20), ).padding(horizontal: 20),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
@@ -302,8 +300,8 @@ class PageForm extends HookConsumerWidget {
alignLabelWithHint: true, alignLabelWithHint: true,
), ),
maxLines: 10, maxLines: 10,
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter HTML content for the page'; return 'Please enter HTML content for the page';
@@ -337,8 +335,8 @@ class PageForm extends HookConsumerWidget {
} }
return null; return null;
}, },
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
).padding(horizontal: 20), ).padding(horizontal: 20),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
@@ -361,31 +359,31 @@ class PageForm extends HookConsumerWidget {
} }
return null; return null;
}, },
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
).padding(horizontal: 20), ).padding(horizontal: 20),
Row(
children: [
if (page != null) ...[
TextButton.icon(
onPressed: deletePage,
icon: const Icon(Symbols.delete_forever),
label: const Text('Delete Page'),
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
).alignment(Alignment.centerRight),
const Spacer(),
] else
const Spacer(),
TextButton.icon(
onPressed: savePage,
icon: const Icon(Symbols.save),
label: const Text('Save Page'),
),
],
).padding(horizontal: 20, vertical: 16),
], ],
Row(
children: [
if (page != null) ...[
TextButton.icon(
onPressed: deletePage,
icon: const Icon(Symbols.delete_forever),
label: const Text('Delete Page'),
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
).alignment(Alignment.centerRight),
const Spacer(),
] else
const Spacer(),
TextButton.icon(
onPressed: savePage,
icon: const Icon(Symbols.save),
label: const Text('Save Page'),
),
],
).padding(horizontal: 20, vertical: 16),
], ],
), ),
), ),