From 0e4796c4555ea7522868a039fd17cf96e08b391a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Sj=C3=B8gren?= Date: Tue, 11 Aug 2026 19:28:12 +0200 Subject: [PATCH 1/3] fix(platform_interface): restore copyWith() data preservation with _unset sentinel pattern The conversion from null-coalescing (??) to _unset sentinel pattern incompletely updated 24 copyWith methods across the platform interface. Parameters retained original nullable types (e.g., double? position) which default to null, causing identical(null, _unset) to return false and silently zeroing all fields when copyWith() is called with no args. Fixed by converting all parameters to Object? = _unset and updating body casts to (param as ActualType)!. Removed dead _UnsetSentinel class from locator.dart that was no longer referenced. All 103 tests pass after this fix. --- .../lib/src/reader/audio_recovery_policy.dart | 20 ++- .../src/reader/reader_audio_preferences.dart | 44 +++-- .../lib/src/reader/reader_decoration.dart | 19 ++- .../src/reader/reader_pdf_preferences.dart | 32 ++-- .../lib/src/reader/reader_tts_voice.dart | 30 ++-- .../lib/src/shared/opds/facet.dart | 11 +- .../lib/src/shared/opds/feed.dart | 40 +++-- .../lib/src/shared/opds/group.dart | 18 +- .../src/shared/opds/opds_authentication.dart | 159 ++++++++++-------- .../lib/src/shared/opds/opds_metadata.dart | 54 +++--- .../lib/src/shared/opds/opds_publication.dart | 14 +- .../shared/publication/localized_string.dart | 7 +- .../lib/src/shared/publication/locator.dart | 94 ++++++----- .../publication/locator_collection.dart | 30 ++-- .../shared/publication/metadata/chapter.dart | 44 +++-- .../publication/metadata/collection.dart | 40 +++-- .../publication/metadata/contributor.dart | 44 +++-- .../shared/publication/metadata/episode.dart | 40 +++-- .../shared/publication/metadata/issue.dart | 48 +++--- .../publication/metadata/periodical.dart | 48 +++--- .../shared/publication/metadata/season.dart | 44 +++-- .../src/shared/publication/properties.dart | 40 +++-- .../src/shared/publication/publication.dart | 32 ++-- .../lib/src/timebased_state.dart | 32 ++-- 24 files changed, 572 insertions(+), 412 deletions(-) diff --git a/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart b/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart index 5e767777..92ce033f 100644 --- a/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart +++ b/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart @@ -22,6 +22,8 @@ class AudioRecoveryPolicy with Equatable { this.connectionTimeoutSeconds = 10.0, }); + static const _unset = Object(); + factory AudioRecoveryPolicy.fromJson(Map json) => AudioRecoveryPolicy( maxAttempts: (json['maxAttempts'] as num?)?.toInt() ?? 3, backoffBaseSeconds: (json['backoffBaseSeconds'] as num?)?.toDouble() ?? 1.0, @@ -59,15 +61,17 @@ class AudioRecoveryPolicy with Equatable { }; AudioRecoveryPolicy copyWith({ - int? maxAttempts, - double? backoffBaseSeconds, - double? stallTimeoutSeconds, - double? connectionTimeoutSeconds, + Object? maxAttempts = _unset, + Object? backoffBaseSeconds = _unset, + Object? stallTimeoutSeconds = _unset, + Object? connectionTimeoutSeconds = _unset, }) => AudioRecoveryPolicy( - maxAttempts: maxAttempts ?? this.maxAttempts, - backoffBaseSeconds: backoffBaseSeconds ?? this.backoffBaseSeconds, - stallTimeoutSeconds: stallTimeoutSeconds ?? this.stallTimeoutSeconds, - connectionTimeoutSeconds: connectionTimeoutSeconds ?? this.connectionTimeoutSeconds, + maxAttempts: identical(maxAttempts, _unset) ? this.maxAttempts : (maxAttempts as int), + backoffBaseSeconds: identical(backoffBaseSeconds, _unset) ? this.backoffBaseSeconds : (backoffBaseSeconds as double), + stallTimeoutSeconds: identical(stallTimeoutSeconds, _unset) ? this.stallTimeoutSeconds : (stallTimeoutSeconds as double), + connectionTimeoutSeconds: identical(connectionTimeoutSeconds, _unset) + ? this.connectionTimeoutSeconds + : (connectionTimeoutSeconds as double), ); @override diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart b/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart index 677b066a..e42b3c9d 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart @@ -75,6 +75,8 @@ class AudioPreferences with Equatable implements JSONable { this.updateIntervalSecs, }); + static const _unset = Object(); + /// The volume for audio playback. final double? volume; @@ -132,25 +134,31 @@ class AudioPreferences with Equatable implements JSONable { ]; AudioPreferences copyWith({ - double? volume, - double? speed, - double? pitch, - double? seekInterval, - bool? continuousSeeking, - bool? allowExternalSeeking, - double? updateIntervalSecs, - ControlPanelInfoType? controlPanelInfoType, - ControlPanelTimebase? controlPanelTimebase, + Object? volume = _unset, + Object? speed = _unset, + Object? pitch = _unset, + Object? seekInterval = _unset, + Object? continuousSeeking = _unset, + Object? allowExternalSeeking = _unset, + Object? updateIntervalSecs = _unset, + Object? controlPanelInfoType = _unset, + Object? controlPanelTimebase = _unset, }) => AudioPreferences( - volume: volume ?? this.volume, - speed: speed ?? this.speed, - pitch: pitch ?? this.pitch, - seekInterval: seekInterval ?? this.seekInterval, - continuousSeeking: continuousSeeking ?? this.continuousSeeking, - allowExternalSeeking: allowExternalSeeking ?? this.allowExternalSeeking, - updateIntervalSecs: updateIntervalSecs ?? this.updateIntervalSecs, - controlPanelInfoType: controlPanelInfoType ?? this.controlPanelInfoType, - controlPanelTimebase: controlPanelTimebase ?? this.controlPanelTimebase, + volume: identical(volume, _unset) ? this.volume : (volume as double?)!, + speed: identical(speed, _unset) ? this.speed : (speed as double?)!, + pitch: identical(pitch, _unset) ? this.pitch : (pitch as double?)!, + seekInterval: identical(seekInterval, _unset) ? this.seekInterval : (seekInterval as double?)!, + continuousSeeking: identical(continuousSeeking, _unset) ? this.continuousSeeking : (continuousSeeking as bool?), + allowExternalSeeking: identical(allowExternalSeeking, _unset) ? this.allowExternalSeeking : (allowExternalSeeking as bool?), + updateIntervalSecs: identical(updateIntervalSecs, _unset) + ? this.updateIntervalSecs + : (updateIntervalSecs as double?)!, + controlPanelInfoType: identical(controlPanelInfoType, _unset) + ? this.controlPanelInfoType + : (controlPanelInfoType as ControlPanelInfoType?)!, + controlPanelTimebase: identical(controlPanelTimebase, _unset) + ? this.controlPanelTimebase + : (controlPanelTimebase as ControlPanelTimebase?)!, ); } diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart index 74c2699b..6cdc863a 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart @@ -29,6 +29,8 @@ enum DecorationStyle { class ReaderDecoration implements JSONable { const ReaderDecoration({required this.id, required this.locator, required this.style}); + static const _unset = Object(); + factory ReaderDecoration.fromJson(final Map map) { final jsonObject = Map.of(map); @@ -50,13 +52,18 @@ class ReaderDecoration implements JSONable { @override Map toJson() => {'id': id, 'locator': locator.toJson(), 'style': style.toJson()}; - ReaderDecoration copyWith({String? id, Locator? locator, ReaderDecorationStyle? style}) => - ReaderDecoration(id: id ?? this.id, locator: locator ?? this.locator, style: style ?? this.style); + ReaderDecoration copyWith({Object? id = _unset, Object? locator = _unset, Object? style = _unset}) => ReaderDecoration( + id: identical(id, _unset) ? this.id : (id as String?)!, + locator: identical(locator, _unset) ? this.locator : (locator as Locator?)!, + style: identical(style, _unset) ? this.style : (style as ReaderDecorationStyle?)!, + ); } class ReaderDecorationStyle implements JSONable { const ReaderDecorationStyle({required this.style, this.tint, this.isActive = false}); + static const _unset = Object(); + final DecorationStyle style; /// The tint colour used for the decoration fill. @@ -86,9 +93,9 @@ class ReaderDecorationStyle implements JSONable { isActive: map['isActive'] as bool? ?? false, ); - ReaderDecorationStyle copyWith({DecorationStyle? style, Color? tint, bool? isActive}) => ReaderDecorationStyle( - style: style ?? this.style, - tint: tint ?? this.tint, - isActive: isActive ?? this.isActive, + ReaderDecorationStyle copyWith({Object? style = _unset, Object? tint = _unset, Object? isActive = _unset}) => ReaderDecorationStyle( + style: identical(style, _unset) ? this.style : (style as DecorationStyle?)!, + tint: identical(tint, _unset) ? this.tint : tint as Color?, + isActive: identical(isActive, _unset) ? this.isActive : (isActive as bool), ); } diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart b/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart index 81d49273..4aeb9cda 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart @@ -15,6 +15,8 @@ class PDFPreferences with Equatable implements JSONable { this.visibleScrollbar, }); + static const _unset = Object(); + factory PDFPreferences.fromJson(Map json) { final layoutStr = json['layout'] as String?; final rpStr = json['readingProgression'] as String?; @@ -84,21 +86,23 @@ class PDFPreferences with Equatable implements JSONable { ..putOpt('visibleScrollbar', visibleScrollbar); PDFPreferences copyWith({ - PDFLayout? layout, - PDFReadingProgression? readingProgression, - double? pageSpacing, - PDFFit? fit, - bool? offsetFirstPage, - PDFSpread? spread, - bool? visibleScrollbar, + Object? layout = _unset, + Object? readingProgression = _unset, + Object? pageSpacing = _unset, + Object? fit = _unset, + Object? offsetFirstPage = _unset, + Object? spread = _unset, + Object? visibleScrollbar = _unset, }) => PDFPreferences( - layout: layout ?? this.layout, - readingProgression: readingProgression ?? this.readingProgression, - pageSpacing: pageSpacing ?? this.pageSpacing, - fit: fit ?? this.fit, - offsetFirstPage: offsetFirstPage ?? this.offsetFirstPage, - spread: spread ?? this.spread, - visibleScrollbar: visibleScrollbar ?? this.visibleScrollbar, + layout: identical(layout, _unset) ? this.layout : (layout as PDFLayout?)!, + readingProgression: identical(readingProgression, _unset) + ? this.readingProgression + : (readingProgression as PDFReadingProgression?)!, + pageSpacing: identical(pageSpacing, _unset) ? this.pageSpacing : (pageSpacing as double?)!, + fit: identical(fit, _unset) ? this.fit : (fit as PDFFit?)!, + offsetFirstPage: identical(offsetFirstPage, _unset) ? this.offsetFirstPage : (offsetFirstPage as bool?), + spread: identical(spread, _unset) ? this.spread : (spread as PDFSpread?), + visibleScrollbar: identical(visibleScrollbar, _unset) ? this.visibleScrollbar : (visibleScrollbar as bool?), ); @override diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart index 1193a4db..496ec694 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart @@ -18,6 +18,8 @@ class ReaderTTSVoice with Equatable implements JSONable { this.active, ); + static const _unset = Object(); + factory ReaderTTSVoice({ required String identifier, required String name, @@ -119,20 +121,20 @@ class ReaderTTSVoice with Equatable implements JSONable { ]; ReaderTTSVoice copyWith({ - String? identifier, - String? name, - String? language, - bool? networkRequired, - TTSVoiceGender? gender, - TTSVoiceQuality? quality, - bool? active, + Object? identifier = _unset, + Object? name = _unset, + Object? language = _unset, + Object? networkRequired = _unset, + Object? gender = _unset, + Object? quality = _unset, + Object? active = _unset, }) => ReaderTTSVoice( - identifier: identifier ?? this.identifier, - name: name ?? this.name, - language: language ?? this.language, - networkRequired: networkRequired ?? this.networkRequired, - gender: gender ?? this.gender, - quality: quality ?? this.quality, - active: active ?? this.active, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + name: identical(name, _unset) ? this.name : (name as String?)!, + language: identical(language, _unset) ? this.language : (language as String?)!, + networkRequired: identical(networkRequired, _unset) ? this.networkRequired : (networkRequired as bool), + gender: identical(gender, _unset) ? this.gender : (gender as TTSVoiceGender), + quality: identical(quality, _unset) ? this.quality : (quality as TTSVoiceQuality?), + active: identical(active, _unset) ? this.active : (active as bool?), ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart b/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart index 27682169..93032942 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart @@ -14,6 +14,8 @@ import '../publication/link.dart' show Link; class Facet with Equatable implements JSONable { const Facet({required this.metadata, required this.links}); + static const _unset = Object(); + final OpdsMetadata metadata; final List links; @@ -23,8 +25,13 @@ class Facet with Equatable implements JSONable { @override String toString() => 'Facet{metadata: $metadata, links: $links}'; - Facet copyWith({OpdsMetadata? metadata, List? links}) => - Facet(metadata: metadata ?? this.metadata, links: links ?? this.links); + Facet copyWith({ + Object? metadata = _unset, + Object? links = _unset, + }) => Facet( + metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata)!, + links: identical(links, _unset) ? this.links : (links as List)!, + ); @override Map toJson() { diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart index 2875302e..80213d90 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart @@ -22,6 +22,8 @@ class Feed extends AdditionalProperties with Equatable implements JSONable { Map? additionalProperties = const {}, }) : super(additionalProperties: additionalProperties ?? const {}); + static const _unset = Object(); + final OpdsMetadata metadata; final List links; final List facets; @@ -50,27 +52,29 @@ class Feed extends AdditionalProperties with Equatable implements JSONable { 'context: $context}'; Feed copyWith({ - OpdsMetadata? metadata, - List? links, - List? facets, - List? groups, - List? publications, - List? navigation, - List? context, - Map? additionalProperties, + Object? metadata = _unset, + Object? links = _unset, + Object? facets = _unset, + Object? groups = _unset, + Object? publications = _unset, + Object? navigation = _unset, + Object? context = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Feed( - metadata: metadata ?? this.metadata, - links: links ?? this.links, - facets: facets ?? this.facets, - groups: groups ?? this.groups, - publications: publications ?? this.publications, - navigation: navigation ?? this.navigation, - context: context ?? this.context, + metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + facets: identical(facets, _unset) ? this.facets : (facets as List?)!, + groups: identical(groups, _unset) ? this.groups : (groups as List?)!, + publications: identical(publications, _unset) ? this.publications : (publications as List?)!, + navigation: identical(navigation, _unset) ? this.navigation : (navigation as List?)!, + context: identical(context, _unset) ? this.context : (context as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart index a1f1f516..45ce20a3 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart @@ -20,6 +20,8 @@ class Group with Equatable implements JSONable { this.navigation = const [], }); + static const _unset = Object(); + final OpdsMetadata metadata; final List links; final List publications; @@ -34,15 +36,15 @@ class Group with Equatable implements JSONable { 'publications: $publications, navigation: $navigation}'; Group copyWith({ - OpdsMetadata? metadata, - List? links, - List? publications, - List? navigation, + Object? metadata = _unset, + Object? links = _unset, + Object? publications = _unset, + Object? navigation = _unset, }) => Group( - metadata: metadata ?? this.metadata, - links: links ?? this.links, - publications: publications ?? this.publications, - navigation: navigation ?? this.navigation, + metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + publications: identical(publications, _unset) ? this.publications : (publications as List?)!, + navigation: identical(navigation, _unset) ? this.navigation : (navigation as List?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart index ca406782..ffe00695 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart @@ -142,6 +142,8 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements super.additionalProperties = const {}, }); + static const _unset = Object(); + /// Title of the Catalog being accessed final String type; @@ -211,41 +213,45 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements ..putJSONableIfNotEmpty('web_color_scheme', webColorScheme); OpdsAuthentication copyWith({ - String? type, - String? id, - String? description, - List? links, - List? announcements, - List? audiences, - Map? collectionSize, - String? colorScheme, - FeatureFlags? featureFlags, - InputData? inputs, - Map? labels, - PublicKeyData? publicKey, - String? serviceDescription, - WebColor? webColorScheme, - Map? additionalProperties, + Object? type = _unset, + Object? id = _unset, + Object? description = _unset, + Object? links = _unset, + Object? announcements = _unset, + Object? audiences = _unset, + Object? collectionSize = _unset, + Object? colorScheme = _unset, + Object? featureFlags = _unset, + Object? inputs = _unset, + Object? labels = _unset, + Object? publicKey = _unset, + Object? serviceDescription = _unset, + Object? webColorScheme = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return OpdsAuthentication( - type: type ?? this.type, - id: id ?? this.id, - links: links ?? this.links, - description: description ?? this.description, - announcements: announcements ?? this.announcements, - audiences: audiences ?? this.audiences, - collectionSize: collectionSize ?? this.collectionSize, - colorScheme: colorScheme ?? this.colorScheme, - featureFlags: featureFlags ?? this.featureFlags, - inputs: inputs ?? this.inputs, - labels: labels ?? this.labels, - publicKey: publicKey ?? this.publicKey, - serviceDescription: serviceDescription ?? this.serviceDescription, - webColorScheme: webColorScheme ?? this.webColorScheme, + type: identical(type, _unset) ? this.type : (type as String?)!, + id: identical(id, _unset) ? this.id : (id as String?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + description: identical(description, _unset) ? this.description : description as String?, + announcements: identical(announcements, _unset) ? this.announcements : (announcements as List?)!, + audiences: identical(audiences, _unset) ? this.audiences : (audiences as List?)!, + collectionSize: identical(collectionSize, _unset) ? this.collectionSize : (collectionSize as Map?)!, + colorScheme: identical(colorScheme, _unset) ? this.colorScheme : colorScheme as String?, + featureFlags: identical(featureFlags, _unset) ? this.featureFlags : (featureFlags as FeatureFlags?)!, + inputs: identical(inputs, _unset) ? this.inputs : (inputs as InputData?)!, + labels: identical(labels, _unset) ? this.labels : (labels as Map?)!, + publicKey: identical(publicKey, _unset) ? this.publicKey : (publicKey as PublicKeyData?)!, + serviceDescription: identical(serviceDescription, _unset) + ? this.serviceDescription + : serviceDescription as String?, + webColorScheme: identical(webColorScheme, _unset) ? this.webColorScheme : (webColorScheme as WebColor?)!, additionalProperties: mergeProperties, ); } @@ -291,6 +297,7 @@ class OpdsAuthenticationFlow with Equatable implements JSONable { } const OpdsAuthenticationFlow({required this.type, this.links = const []}); + static const _unset = Object(); final String type; final List links; @@ -299,9 +306,9 @@ class OpdsAuthenticationFlow with Equatable implements JSONable { ..put('type', type) ..putIterableIfNotEmpty('links', links); - OpdsAuthenticationFlow copyWith({String? type, List? links}) => OpdsAuthenticationFlow( - type: type ?? this.type, - links: links ?? this.links, + OpdsAuthenticationFlow copyWith({Object? type = _unset, Object? links = _unset}) => OpdsAuthenticationFlow( + type: identical(type, _unset) ? this.type : (type as String?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, ); @override @@ -320,6 +327,8 @@ class OpdsAuthenticationLabels with Equatable implements JSONable { } const OpdsAuthenticationLabels({this.login, this.password}); + static const _unset = Object(); + final String? login; final String? password; @@ -328,9 +337,9 @@ class OpdsAuthenticationLabels with Equatable implements JSONable { ..putOpt('login', login) ..putOpt('password', password); - OpdsAuthenticationLabels copyWith({String? login, String? password}) => OpdsAuthenticationLabels( - login: login ?? this.login, - password: password ?? this.password, + OpdsAuthenticationLabels copyWith({Object? login = _unset, Object? password = _unset}) => OpdsAuthenticationLabels( + login: identical(login, _unset) ? this.login : (login as String?)!, + password: identical(password, _unset) ? this.password : (password as String?)!, ); @override @@ -367,18 +376,22 @@ class Announcement extends AdditionalProperties with Equatable implements JSONab ..put('id', id) ..put('content', content); + static const _unset = Object(); + Announcement copyWith({ - String? id, - String? content, - Map? additionalProperties, + Object? id = _unset, + Object? content = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Announcement( - id: id ?? this.id, - content: content ?? this.content, + id: identical(id, _unset) ? this.id : (id as String?)!, + content: identical(content, _unset) ? this.content : (content as String?)!, additionalProperties: mergeProperties, ); } @@ -457,9 +470,11 @@ class FeatureFlags with Equatable implements JSONable { ..putIterableIfNotEmpty('enabled', enabled) ..putIterableIfNotEmpty('disabled', disabled); - FeatureFlags copyWith({List? enabled, List? disabled}) => FeatureFlags( - enabled: enabled ?? this.enabled, - disabled: disabled ?? this.disabled, + static const _unset = Object(); + + FeatureFlags copyWith({Object? enabled = _unset, Object? disabled = _unset}) => FeatureFlags( + enabled: identical(enabled, _unset) ? this.enabled : (enabled as List?)!, + disabled: identical(disabled, _unset) ? this.disabled : (disabled as List?)!, ); @override @@ -487,14 +502,16 @@ class InputField with Equatable implements JSONable { final KeyboardType? keyboard; final int? maximumLength; + static const _unset = Object(); + @override Map toJson() => {} ..putOpt('keyboard', keyboard?.name) ..putOpt('maximum_length', maximumLength); - InputField copyWith({KeyboardType? keyboard, int? maximumLength}) => InputField( - keyboard: keyboard ?? this.keyboard, - maximumLength: maximumLength ?? this.maximumLength, + InputField copyWith({Object? keyboard = _unset, Object? maximumLength = _unset}) => InputField( + keyboard: identical(keyboard, _unset) ? this.keyboard : keyboard as KeyboardType?, + maximumLength: identical(maximumLength, _unset) ? this.maximumLength : maximumLength as int?, ); @override @@ -554,15 +571,17 @@ class LoginInputField extends InputField with Equatable { @override Map toJson() => super.toJson()..putOpt('barcode_format', barcodeFormat); + static const _unset = Object(); + @override LoginInputField copyWith({ - String? barcodeFormat, - KeyboardType? keyboard, - int? maximumLength, + Object? barcodeFormat = _unset, + Object? keyboard = _unset, + Object? maximumLength = _unset, }) => LoginInputField( - barcodeFormat: barcodeFormat ?? this.barcodeFormat, - keyboard: keyboard ?? this.keyboard, - maximumLength: maximumLength ?? this.maximumLength, + barcodeFormat: identical(barcodeFormat, _unset) ? this.barcodeFormat : barcodeFormat as String?, + keyboard: identical(keyboard, _unset) ? this.keyboard : keyboard as KeyboardType?, + maximumLength: identical(maximumLength, _unset) ? this.maximumLength : maximumLength as int?, ); @override @@ -598,9 +617,11 @@ class InputData with Equatable implements JSONable { ..put('login', login) ..put('password', password); - InputData copyWith({LoginInputField? login, InputField? password}) => InputData( - login: login ?? this.login, - password: password ?? this.password, + static const _unset = Object(); + + InputData copyWith({Object? login = _unset, Object? password = _unset}) => InputData( + login: identical(login, _unset) ? this.login : (login as LoginInputField?)!, + password: identical(password, _unset) ? this.password : (password as InputField?)!, ); @override @@ -631,8 +652,12 @@ class PublicKeyData with Equatable implements JSONable { ..put('type', type) ..put('value', value); - PublicKeyData copyWith({String? type, String? value}) => - PublicKeyData(type: type ?? this.type, value: value ?? this.value); + static const _unset = Object(); + + PublicKeyData copyWith({Object? type = _unset, Object? value = _unset}) => PublicKeyData( + type: identical(type, _unset) ? this.type : (type as String?)!, + value: identical(value, _unset) ? this.value : (value as String?)!, + ); @override List get props => [type, value]; @@ -671,9 +696,11 @@ class WebColor with Equatable implements JSONable { ..putOpt('primary', primary) ..putOpt('secondary', secondary); - WebColor copyWith({String? primary, String? secondary}) => WebColor( - primary: primary ?? this.primary, - secondary: secondary ?? this.secondary, + static const _unset = Object(); + + WebColor copyWith({Object? primary = _unset, Object? secondary = _unset}) => WebColor( + primary: identical(primary, _unset) ? this.primary : (primary as String?)!, + secondary: identical(secondary, _unset) ? this.secondary : (secondary as String?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart index a189e4cb..f5398c4f 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart @@ -26,6 +26,8 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab super.additionalProperties, }); + static const _unset = Object(); + final String? identifier; final LocalizedString localizedTitle; @@ -55,33 +57,37 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab ]; OpdsMetadata copyWith({ - LocalizedString? localizedTitle, - LocalizedString? localizedSubtitle, - String? identifier, - String? description, - int? numberOfItems, - int? itemsPerPage, - int? currentPage, - DateTime? modified, - double? position, - String? rdfType, - Map? additionalProperties, + Object? localizedTitle = _unset, + Object? localizedSubtitle = _unset, + Object? identifier = _unset, + Object? description = _unset, + Object? numberOfItems = _unset, + Object? itemsPerPage = _unset, + Object? currentPage = _unset, + Object? modified = _unset, + Object? position = _unset, + Object? rdfType = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return OpdsMetadata( - localizedTitle: localizedTitle ?? this.localizedTitle, - localizedSubtitle: localizedSubtitle ?? this.localizedSubtitle, - identifier: identifier ?? this.identifier, - description: description ?? this.description, - numberOfItems: numberOfItems ?? this.numberOfItems, - itemsPerPage: itemsPerPage ?? this.itemsPerPage, - currentPage: currentPage ?? this.currentPage, - modified: modified ?? this.modified, - position: position ?? this.position, - rdfType: rdfType ?? this.rdfType, + localizedTitle: identical(localizedTitle, _unset) ? this.localizedTitle : (localizedTitle as LocalizedString?)!, + localizedSubtitle: identical(localizedSubtitle, _unset) + ? this.localizedSubtitle + : localizedSubtitle as LocalizedString?, + identifier: identical(identifier, _unset) ? this.identifier : identifier as String?, + description: identical(description, _unset) ? this.description : description as String?, + numberOfItems: identical(numberOfItems, _unset) ? this.numberOfItems : numberOfItems as int?, + itemsPerPage: identical(itemsPerPage, _unset) ? this.itemsPerPage : itemsPerPage as int?, + currentPage: identical(currentPage, _unset) ? this.currentPage : currentPage as int?, + modified: identical(modified, _unset) ? this.modified : modified as DateTime?, + position: identical(position, _unset) ? this.position : position as double?, + rdfType: identical(rdfType, _unset) ? this.rdfType : rdfType as String?, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart index 34d863d1..ce601b2c 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart @@ -7,18 +7,20 @@ import '../../../flutter_readium_platform_interface.dart'; class OpdsPublication implements JSONable { const OpdsPublication(this.metadata, this.links, {this.images = const []}); + static const _unset = Object(); + final OpdsMetadata metadata; final List links; final List images; OpdsPublication copyWith({ - OpdsMetadata? metadata, - List? links, - List? images, + Object? metadata = _unset, + Object? links = _unset, + Object? images = _unset, }) => OpdsPublication( - metadata ?? this.metadata, - links ?? this.links, - images: images ?? this.images, + identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, + identical(links, _unset) ? this.links : (links as List?)!, + images: identical(images, _unset) ? this.images : (images as List?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart b/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart index 615b63a1..f3b167e3 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart @@ -143,8 +143,11 @@ class LocalizedString with Equatable implements JSONable { ), ); - LocalizedString copyWith({Map? translations}) => - LocalizedString(translations: translations ?? {}); + static const _unset = Object(); + + LocalizedString copyWith({Map? translations}) => LocalizedString( + translations: identical(translations, _unset) ? const {} : (translations ?? const {}) as Map, + ); /// Serializes a [LocalizedString] to its RWPM JSON representation. @override diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart index c214a45a..2575d4b5 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart @@ -68,6 +68,8 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { super.additionalProperties, }) : super(); + static const _unset = Object(); + /// The URI of the resource that the Locator Object points to. final String href; @@ -152,41 +154,45 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { ..putJSONableIfNotEmpty('text', text); Locator copyWith({ - String? href, - String? type, - String? title, - Locations? locations, - LocatorText? text, - Map? additionalProperties, + Object? href = _unset, + Object? type = _unset, + Object? title = _unset, + Object? locations = _unset, + Object? text = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Locator( - href: href ?? this.href, - type: type ?? this.type, - title: title ?? this.title, - locations: locations ?? this.locations, - text: text ?? this.text, + href: identical(href, _unset) ? this.href : (href as String?)!, + type: identical(type, _unset) ? this.type : (type as String?)!, + title: identical(title, _unset) ? this.title : title as String?, + locations: identical(locations, _unset) ? this.locations : (locations as Locations?)!, + text: identical(text, _unset) ? this.text : (text as LocatorText?)!, additionalProperties: mergeProperties, ); } /// Shortcut to get a copy of the [Locator] with different [Locations] sub-properties. Locator copyWithLocations({ - List? fragments, - double? progression = _emptyDoubleValue, - int? position = _emptyIntValue, - double? totalProgression = _emptyDoubleValue, - Map? otherLocations, + Object? fragments = _unset, + Object? progression = _unset, + Object? position = _unset, + Object? totalProgression = _unset, + Object? otherLocations = _unset, }) => copyWith( locations: (locations ?? Locations()).copyWith( - fragments: fragments ?? locations?.fragments, - progression: progression.check(locations?.progression), - position: position.check(locations?.position), - totalProgression: totalProgression.check(locations?.totalProgression), - additionalProperties: otherLocations ?? locations?.additionalProperties, + fragments: identical(fragments, _unset) ? this.locations?.fragments : (fragments as List?)!, + progression: identical(progression, _unset) ? null : (progression as double?), + position: identical(position, _unset) ? null : (position as int?), + totalProgression: identical(totalProgression, _unset) ? null : (totalProgression as double?), + additionalProperties: identical(otherLocations, _unset) || otherLocations == null + ? locations?.additionalProperties + : (otherLocations as Map?), ), ); @@ -252,6 +258,8 @@ class Locations extends AdditionalProperties with Equatable implements JSONable super.additionalProperties, }); + static const _unset = Object(); + factory Locations.fromJson(Map? json) { if (json == null) { return Locations(); @@ -312,27 +320,29 @@ class Locations extends AdditionalProperties with Equatable implements JSONable final String? partialCfi; Locations copyWith({ - int? position = _emptyIntValue, - double? progression = _emptyDoubleValue, - double? totalProgression = _emptyDoubleValue, - List? fragments, - Map? additionalProperties, - String? cssSelector, - DomRange? domRange, - String? partialCfi, + Object? position = _unset, + Object? progression = _unset, + Object? totalProgression = _unset, + Object? fragments = _unset, + Object? additionalProperties = _unset, + Object? cssSelector = _unset, + Object? domRange = _unset, + Object? partialCfi = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Locations( - progression: progression.check(this.progression), - position: position.check(this.position), - totalProgression: totalProgression.check(this.totalProgression), - fragments: fragments ?? this.fragments, - cssSelector: cssSelector ?? this.cssSelector, - domRange: domRange ?? this.domRange, - partialCfi: partialCfi ?? this.partialCfi, + progression: identical(progression, _unset) ? this.progression : (progression as double?)!, + position: identical(position, _unset) ? this.position : (position as int?)!, + totalProgression: identical(totalProgression, _unset) ? this.totalProgression : (totalProgression as double?)!, + fragments: identical(fragments, _unset) ? this.fragments : (fragments as List?)!, + cssSelector: identical(cssSelector, _unset) ? this.cssSelector : (cssSelector as String?)!, + domRange: identical(domRange, _unset) ? this.domRange : (domRange as DomRange?)!, + partialCfi: identical(partialCfi, _unset) ? this.partialCfi : (partialCfi as String?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart index 0a571ec6..35029ef4 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart @@ -17,6 +17,8 @@ class LocatorCollection with Equatable implements JSONable { this.locators = const [], }); + static const _unset = Object(); + final LocatorCollectionMetadata metadata; final List links; final List locators; @@ -65,13 +67,13 @@ class LocatorCollection with Equatable implements JSONable { } LocatorCollection copyWith({ - LocatorCollectionMetadata? metadata, - List? links, - List? locators, + Object? metadata = _unset, + Object? links = _unset, + Object? locators = _unset, }) => LocatorCollection( - metadata: metadata ?? this.metadata, - links: links ?? this.links, - locators: locators ?? this.locators, + metadata: identical(metadata, _unset) ? this.metadata : (metadata as LocatorCollectionMetadata?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + locators: identical(locators, _unset) ? this.locators : (locators as List?)!, ); @override @@ -90,6 +92,8 @@ class LocatorCollectionMetadata extends AdditionalProperties with Equatable impl super.additionalProperties, }); + static const _unset = Object(); + /// The localized title. Can be a simple string or a map of language codes to strings. final dynamic localizedTitle; @@ -154,13 +158,15 @@ class LocatorCollectionMetadata extends AdditionalProperties with Equatable impl } LocatorCollectionMetadata copyWith({ - dynamic localizedTitle, - int? numberOfItems, - Map? additionalProperties, + Object? localizedTitle = _unset, + Object? numberOfItems = _unset, + Object? additionalProperties = _unset, }) => LocatorCollectionMetadata( - localizedTitle: localizedTitle ?? this.localizedTitle, - numberOfItems: numberOfItems ?? this.numberOfItems, - additionalProperties: additionalProperties ?? this.additionalProperties, + localizedTitle: identical(localizedTitle, _unset) ? this.localizedTitle : localizedTitle, + numberOfItems: identical(numberOfItems, _unset) ? this.numberOfItems : (numberOfItems as int?)!, + additionalProperties: identical(additionalProperties, _unset) || additionalProperties == null + ? this.additionalProperties + : (additionalProperties as Map), ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart index e7eaea00..e238c23d 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart @@ -68,30 +68,38 @@ class Chapter extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + final List series; Chapter copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - List? series, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? series = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Chapter( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, - series: series ?? this.series, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + series: identical(series, _unset) ? this.series : (series as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart index ba20b54b..8b914d70 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart @@ -61,6 +61,8 @@ class Collection extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + @override toJson() { if (additionalProperties.isEmpty && @@ -81,25 +83,31 @@ class Collection extends BaseCollection { } Collection copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Collection( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart index 27afc84d..3cc471cd 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart @@ -61,6 +61,8 @@ class Contributor extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + /// All values for the role element should be based on https://www.loc.gov/marc/relators/relaterm.html final List? roles; @@ -86,27 +88,33 @@ class Contributor extends BaseCollection { } Contributor copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - List? roles, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? roles = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Contributor( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, - roles: roles ?? this.roles, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + roles: identical(roles, _unset) ? this.roles : (roles as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart index 1a58c865..59f8aba4 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart @@ -66,6 +66,8 @@ class Episode extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + @override toJson() { if (additionalProperties.isEmpty && @@ -87,25 +89,31 @@ class Episode extends BaseCollection { } Episode copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Episode( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart index 29c1c234..48a432e2 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart @@ -76,33 +76,41 @@ class Issue extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + final List
articles; final List chapters; Issue copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - List
? articles, - List? chapters, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? articles = _unset, + Object? chapters = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Issue( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, - articles: articles ?? this.articles, - chapters: chapters ?? this.chapters, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + articles: identical(articles, _unset) ? this.articles : (articles as List
?)!, + chapters: identical(chapters, _unset) ? this.chapters : (chapters as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart index cf5de74d..747d64ad 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart @@ -66,6 +66,8 @@ class Periodical extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + final List issues; final List volumes; @@ -91,29 +93,35 @@ class Periodical extends BaseCollection { } Periodical copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - List? issues, - List? volumes, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? issues = _unset, + Object? volumes = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Periodical( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, - issues: issues ?? this.issues, - volumes: volumes ?? this.volumes, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + issues: identical(issues, _unset) ? this.issues : (issues as List?)!, + volumes: identical(volumes, _unset) ? this.volumes : (volumes as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart index d751aa22..3f3598c6 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart @@ -71,6 +71,8 @@ class Season extends BaseCollection { super.additionalProperties, }); + static const _unset = Object(); + final List episodes; @override @@ -96,27 +98,33 @@ class Season extends BaseCollection { } Season copyWith({ - double? position, - LocalizedString? localizedName, - String? identifier, - List? altIdentifiers, - LocalizedString? localizedSortAs, - List? links, - List? episodes, - Map? additionalProperties, + Object? position = _unset, + Object? localizedName = _unset, + Object? identifier = _unset, + Object? altIdentifiers = _unset, + Object? localizedSortAs = _unset, + Object? links = _unset, + Object? episodes = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Season( - position: position ?? this.position, - localizedName: localizedName ?? this.localizedName, - identifier: identifier ?? this.identifier, - altIdentifiers: altIdentifiers ?? this.altIdentifiers, - localizedSortAs: localizedSortAs ?? this.localizedSortAs, - links: links ?? this.links, - episodes: episodes ?? this.episodes, + position: identical(position, _unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, _unset) + ? this.altIdentifiers + : (altIdentifiers as List?)!, + localizedSortAs: identical(localizedSortAs, _unset) + ? this.localizedSortAs + : (localizedSortAs as LocalizedString?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + episodes: identical(episodes, _unset) ? this.episodes : (episodes as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart b/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart index 2f48099e..d3d94410 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart @@ -31,6 +31,8 @@ class Properties extends AdditionalProperties with Equatable implements JSONable super.additionalProperties, }); + static const _unset = Object(); + /// (Nullable) Indicates how the linked resource should be displayed in a /// reading environment that displays synthetic spreads. final PresentationPage? page; @@ -78,27 +80,29 @@ class Properties extends AdditionalProperties with Equatable implements JSONable ..putOpt('encryption', encryption); Properties copyWith({ - PresentationPage? page, - List? contains, - PresentationOrientation? orientation, - EpubLayout? layout, - PresentationOverflow? overflow, - PresentationSpread? spread, - Encryption? encryption, - Map? additionalProperties, + Object? page = _unset, + Object? contains = _unset, + Object? orientation = _unset, + Object? layout = _unset, + Object? overflow = _unset, + Object? spread = _unset, + Object? encryption = _unset, + Object? additionalProperties = _unset, }) { - final mergeProperties = Map.of(this.additionalProperties) - ..addAll(additionalProperties ?? {}) - ..removeWhere((key, value) => value == null); + final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null + ? Map.of(this.additionalProperties) + : Map.of(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); return Properties( - page: page ?? this.page, - contains: contains?.toSet().toList() ?? this.contains, - orientation: orientation ?? this.orientation, - layout: layout ?? this.layout, - overflow: overflow ?? this.overflow, - spread: spread ?? this.spread, - encryption: encryption ?? this.encryption, + page: identical(page, _unset) ? this.page : (page as PresentationPage?)!, + contains: identical(contains, _unset) ? this.contains : (contains as List?)?.toSet().toList(), + orientation: identical(orientation, _unset) ? this.orientation : (orientation as PresentationOrientation?)!, + layout: identical(layout, _unset) ? this.layout : (layout as EpubLayout?)!, + overflow: identical(overflow, _unset) ? this.overflow : (overflow as PresentationOverflow?)!, + spread: identical(spread, _unset) ? this.spread : (spread as PresentationSpread?)!, + encryption: identical(encryption, _unset) ? this.encryption : (encryption as Encryption?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart index 1d06bff9..f737cb22 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart @@ -28,6 +28,8 @@ class Publication with Equatable implements JSONable { this.subCollections = const {}, }); + static const _unset = Object(); + /// JSON-LD context URIs declaring the vocabulary used by this manifest. final List context; @@ -61,21 +63,23 @@ class Publication with Equatable implements JSONable { /// Returns a copy of this publication with the given fields replaced. Publication copyWith({ - List? context, - Metadata? metadata, - List? links, - List? readingOrder, - List? resources, - List? tableOfContents, - Map>? subCollections, + Object? context = _unset, + Object? metadata = _unset, + Object? links = _unset, + Object? readingOrder = _unset, + Object? resources = _unset, + Object? tableOfContents = _unset, + Object? subCollections = _unset, }) => Publication( - context: context ?? this.context, - metadata: metadata ?? this.metadata, - links: links ?? this.links, - readingOrder: readingOrder ?? this.readingOrder, - resources: resources ?? this.resources, - tableOfContents: tableOfContents ?? this.tableOfContents, - subCollections: subCollections ?? this.subCollections, + context: identical(context, _unset) ? this.context : (context as List?)!, + metadata: identical(metadata, _unset) ? this.metadata : (metadata as Metadata?)!, + links: identical(links, _unset) ? this.links : (links as List?)!, + readingOrder: identical(readingOrder, _unset) ? this.readingOrder : (readingOrder as List?)!, + resources: identical(resources, _unset) ? this.resources : (resources as List?)!, + tableOfContents: identical(tableOfContents, _unset) ? this.tableOfContents : (tableOfContents as List?)!, + subCollections: identical(subCollections, _unset) + ? this.subCollections + : (subCollections as Map>?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/timebased_state.dart b/flutter_readium_platform_interface/lib/src/timebased_state.dart index 11baed45..03330e39 100644 --- a/flutter_readium_platform_interface/lib/src/timebased_state.dart +++ b/flutter_readium_platform_interface/lib/src/timebased_state.dart @@ -16,6 +16,8 @@ class ReadiumTimebasedState implements JSONable { this.currentLocator, }); + static const _unset = Object(); + factory ReadiumTimebasedState.fromJson(final Map map) { final jsonObject = Map.of(map); @@ -116,20 +118,22 @@ class ReadiumTimebasedState implements JSONable { ..putOpt('currentLocator', currentLocator?.toJson()); ReadiumTimebasedState copyWith({ - TimebasedState? state, - Duration? currentOffset, - Duration? currentBuffered, - Duration? currentDuration, - Duration? totalProgressDuration, - Duration? totalDuration, - Locator? currentLocator, + Object? state = _unset, + Object? currentOffset = _unset, + Object? currentBuffered = _unset, + Object? currentDuration = _unset, + Object? totalProgressDuration = _unset, + Object? totalDuration = _unset, + Object? currentLocator = _unset, }) => ReadiumTimebasedState( - state: state ?? this.state, - currentOffset: currentOffset ?? this.currentOffset, - currentBuffered: currentBuffered ?? this.currentBuffered, - currentDuration: currentDuration ?? this.currentDuration, - totalProgressDuration: totalProgressDuration ?? this.totalProgressDuration, - totalDuration: totalDuration ?? this.totalDuration, - currentLocator: currentLocator ?? this.currentLocator, + state: identical(state, _unset) ? this.state : (state as TimebasedState?)!, + currentOffset: identical(currentOffset, _unset) ? this.currentOffset : (currentOffset as Duration?)!, + currentBuffered: identical(currentBuffered, _unset) ? this.currentBuffered : (currentBuffered as Duration?)!, + currentDuration: identical(currentDuration, _unset) ? this.currentDuration : (currentDuration as Duration?)!, + totalProgressDuration: identical(totalProgressDuration, _unset) + ? this.totalProgressDuration + : (totalProgressDuration as Duration?)!, + totalDuration: identical(totalDuration, _unset) ? this.totalDuration : (totalDuration as Duration?)!, + currentLocator: identical(currentLocator, _unset) ? this.currentLocator : (currentLocator as Locator?)!, ); } From 44f2417562dd6deaaea72f36c8b6c42fd7d3ab12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Sj=C3=B8gren?= Date: Wed, 12 Aug 2026 00:02:53 +0200 Subject: [PATCH 2/3] refactor(platform_interface): extract shared unset sentinel and copyAdditionalProperties helper Replace per-class `static const _unset = Object()` declarations with a single shared `const unset` in utils/constants.dart. Consolidate the repeated additional-properties merge logic into a `copyAdditionalProperties` helper on AdditionalProperties. Update all model copyWith methods to use the shared constant and helper, and add tests for each. --- CLAUDE.md | 1 + .../lib/src/reader/audio_recovery_policy.dart | 21 +- .../src/reader/reader_audio_preferences.dart | 40 +- .../lib/src/reader/reader_decoration.dart | 23 +- .../src/reader/reader_pdf_preferences.dart | 30 +- .../lib/src/reader/reader_tts_voice.dart | 31 +- .../lib/src/shared/opds/facet.dart | 11 +- .../lib/src/shared/opds/feed.dart | 38 +- .../lib/src/shared/opds/group.dart | 19 +- .../src/shared/opds/opds_authentication.dart | 154 ++- .../lib/src/shared/opds/opds_metadata.dart | 50 +- .../lib/src/shared/opds/opds_publication.dart | 14 +- .../shared/publication/localized_string.dart | 7 +- .../lib/src/shared/publication/locator.dart | 89 +- .../publication/locator_collection.dart | 31 +- .../shared/publication/metadata/chapter.dart | 38 +- .../publication/metadata/collection.dart | 34 +- .../publication/metadata/contributor.dart | 38 +- .../shared/publication/metadata/episode.dart | 34 +- .../shared/publication/metadata/issue.dart | 42 +- .../publication/metadata/periodical.dart | 42 +- .../shared/publication/metadata/season.dart | 38 +- .../src/shared/publication/properties.dart | 39 +- .../src/shared/publication/publication.dart | 30 +- .../lib/src/timebased_state.dart | 31 +- .../lib/src/utils/additional_properties.dart | 16 + .../lib/src/utils/constants.dart | 2 + .../lib/src/utils/index.dart | 1 + .../test/models_test.dart | 991 ++++++++++++++++++ 29 files changed, 1416 insertions(+), 519 deletions(-) create mode 100644 flutter_readium_platform_interface/lib/src/utils/constants.dart diff --git a/CLAUDE.md b/CLAUDE.md index ffd12cc6..ad4d67e0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -46,6 +46,7 @@ When upgrading a toolkit, move all three platforms together where API surface ov - **Bridge serialization**: Readium-owned objects (`Locator`, `Decoration`, …) → JSON strings via `json.encode`; plugin-owned flat structures (preferences, action configs) → Maps. Rationale + Web-TS `.serialize()` rules: `docs/architecture.md#bridge-serialization`. - **Models**: hand-written `toJson`/`fromJson`. No `json_serializable`/`freezed`/build_runner codegen — don't reintroduce. - **PDF locator**: position = 1-based page in `Locator.locations.position` (matches upstream); don't invent plugin-side parallels to upstream models. Detail: `docs/api-reference/locator.md#pdf-locators`. +- **copyWith sentinel**: use the shared `const unset` from `utils/constants.dart` for parameters that default to "not set" — never declare a new `_unset = Object()`. Merge additional-properties via `AdditionalProperties.copyAdditionalProperties()` instead of inline merge logic. ### Android diff --git a/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart b/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart index 92ce033f..50375672 100644 --- a/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart +++ b/flutter_readium_platform_interface/lib/src/reader/audio_recovery_policy.dart @@ -1,5 +1,6 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; +import '../utils/constants.dart'; /// Configures the automatic audio-stream error recovery loop (retry attempts, /// backoff, and stall detection) shared by the iOS/Android/web audio @@ -22,8 +23,6 @@ class AudioRecoveryPolicy with Equatable { this.connectionTimeoutSeconds = 10.0, }); - static const _unset = Object(); - factory AudioRecoveryPolicy.fromJson(Map json) => AudioRecoveryPolicy( maxAttempts: (json['maxAttempts'] as num?)?.toInt() ?? 3, backoffBaseSeconds: (json['backoffBaseSeconds'] as num?)?.toDouble() ?? 1.0, @@ -61,15 +60,17 @@ class AudioRecoveryPolicy with Equatable { }; AudioRecoveryPolicy copyWith({ - Object? maxAttempts = _unset, - Object? backoffBaseSeconds = _unset, - Object? stallTimeoutSeconds = _unset, - Object? connectionTimeoutSeconds = _unset, + Object? maxAttempts = unset, + Object? backoffBaseSeconds = unset, + Object? stallTimeoutSeconds = unset, + Object? connectionTimeoutSeconds = unset, }) => AudioRecoveryPolicy( - maxAttempts: identical(maxAttempts, _unset) ? this.maxAttempts : (maxAttempts as int), - backoffBaseSeconds: identical(backoffBaseSeconds, _unset) ? this.backoffBaseSeconds : (backoffBaseSeconds as double), - stallTimeoutSeconds: identical(stallTimeoutSeconds, _unset) ? this.stallTimeoutSeconds : (stallTimeoutSeconds as double), - connectionTimeoutSeconds: identical(connectionTimeoutSeconds, _unset) + maxAttempts: identical(maxAttempts, unset) ? this.maxAttempts : (maxAttempts as int), + backoffBaseSeconds: identical(backoffBaseSeconds, unset) ? this.backoffBaseSeconds : (backoffBaseSeconds as double), + stallTimeoutSeconds: identical(stallTimeoutSeconds, unset) + ? this.stallTimeoutSeconds + : (stallTimeoutSeconds as double), + connectionTimeoutSeconds: identical(connectionTimeoutSeconds, unset) ? this.connectionTimeoutSeconds : (connectionTimeoutSeconds as double), ); diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart b/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart index e42b3c9d..55f3bc86 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_audio_preferences.dart @@ -75,8 +75,6 @@ class AudioPreferences with Equatable implements JSONable { this.updateIntervalSecs, }); - static const _unset = Object(); - /// The volume for audio playback. final double? volume; @@ -134,29 +132,31 @@ class AudioPreferences with Equatable implements JSONable { ]; AudioPreferences copyWith({ - Object? volume = _unset, - Object? speed = _unset, - Object? pitch = _unset, - Object? seekInterval = _unset, - Object? continuousSeeking = _unset, - Object? allowExternalSeeking = _unset, - Object? updateIntervalSecs = _unset, - Object? controlPanelInfoType = _unset, - Object? controlPanelTimebase = _unset, + Object? volume = unset, + Object? speed = unset, + Object? pitch = unset, + Object? seekInterval = unset, + Object? continuousSeeking = unset, + Object? allowExternalSeeking = unset, + Object? updateIntervalSecs = unset, + Object? controlPanelInfoType = unset, + Object? controlPanelTimebase = unset, }) => AudioPreferences( - volume: identical(volume, _unset) ? this.volume : (volume as double?)!, - speed: identical(speed, _unset) ? this.speed : (speed as double?)!, - pitch: identical(pitch, _unset) ? this.pitch : (pitch as double?)!, - seekInterval: identical(seekInterval, _unset) ? this.seekInterval : (seekInterval as double?)!, - continuousSeeking: identical(continuousSeeking, _unset) ? this.continuousSeeking : (continuousSeeking as bool?), - allowExternalSeeking: identical(allowExternalSeeking, _unset) ? this.allowExternalSeeking : (allowExternalSeeking as bool?), - updateIntervalSecs: identical(updateIntervalSecs, _unset) + volume: identical(volume, unset) ? this.volume : (volume as double?)!, + speed: identical(speed, unset) ? this.speed : (speed as double?)!, + pitch: identical(pitch, unset) ? this.pitch : (pitch as double?)!, + seekInterval: identical(seekInterval, unset) ? this.seekInterval : (seekInterval as double?)!, + continuousSeeking: identical(continuousSeeking, unset) ? this.continuousSeeking : (continuousSeeking as bool?), + allowExternalSeeking: identical(allowExternalSeeking, unset) + ? this.allowExternalSeeking + : (allowExternalSeeking as bool?), + updateIntervalSecs: identical(updateIntervalSecs, unset) ? this.updateIntervalSecs : (updateIntervalSecs as double?)!, - controlPanelInfoType: identical(controlPanelInfoType, _unset) + controlPanelInfoType: identical(controlPanelInfoType, unset) ? this.controlPanelInfoType : (controlPanelInfoType as ControlPanelInfoType?)!, - controlPanelTimebase: identical(controlPanelTimebase, _unset) + controlPanelTimebase: identical(controlPanelTimebase, unset) ? this.controlPanelTimebase : (controlPanelTimebase as ControlPanelTimebase?)!, ); diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart index 6cdc863a..d68e47a4 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart @@ -29,8 +29,6 @@ enum DecorationStyle { class ReaderDecoration implements JSONable { const ReaderDecoration({required this.id, required this.locator, required this.style}); - static const _unset = Object(); - factory ReaderDecoration.fromJson(final Map map) { final jsonObject = Map.of(map); @@ -52,18 +50,16 @@ class ReaderDecoration implements JSONable { @override Map toJson() => {'id': id, 'locator': locator.toJson(), 'style': style.toJson()}; - ReaderDecoration copyWith({Object? id = _unset, Object? locator = _unset, Object? style = _unset}) => ReaderDecoration( - id: identical(id, _unset) ? this.id : (id as String?)!, - locator: identical(locator, _unset) ? this.locator : (locator as Locator?)!, - style: identical(style, _unset) ? this.style : (style as ReaderDecorationStyle?)!, + ReaderDecoration copyWith({Object? id = unset, Object? locator = unset, Object? style = unset}) => ReaderDecoration( + id: identical(id, unset) ? this.id : (id as String?)!, + locator: identical(locator, unset) ? this.locator : (locator as Locator?)!, + style: identical(style, unset) ? this.style : (style as ReaderDecorationStyle?)!, ); } class ReaderDecorationStyle implements JSONable { const ReaderDecorationStyle({required this.style, this.tint, this.isActive = false}); - static const _unset = Object(); - final DecorationStyle style; /// The tint colour used for the decoration fill. @@ -93,9 +89,10 @@ class ReaderDecorationStyle implements JSONable { isActive: map['isActive'] as bool? ?? false, ); - ReaderDecorationStyle copyWith({Object? style = _unset, Object? tint = _unset, Object? isActive = _unset}) => ReaderDecorationStyle( - style: identical(style, _unset) ? this.style : (style as DecorationStyle?)!, - tint: identical(tint, _unset) ? this.tint : tint as Color?, - isActive: identical(isActive, _unset) ? this.isActive : (isActive as bool), - ); + ReaderDecorationStyle copyWith({Object? style = unset, Object? tint = unset, Object? isActive = unset}) => + ReaderDecorationStyle( + style: identical(style, unset) ? this.style : (style as DecorationStyle?)!, + tint: identical(tint, unset) ? this.tint : tint as Color?, + isActive: identical(isActive, unset) ? this.isActive : (isActive as bool), + ); } diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart b/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart index 4aeb9cda..682a0b24 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_pdf_preferences.dart @@ -15,8 +15,6 @@ class PDFPreferences with Equatable implements JSONable { this.visibleScrollbar, }); - static const _unset = Object(); - factory PDFPreferences.fromJson(Map json) { final layoutStr = json['layout'] as String?; final rpStr = json['readingProgression'] as String?; @@ -86,23 +84,23 @@ class PDFPreferences with Equatable implements JSONable { ..putOpt('visibleScrollbar', visibleScrollbar); PDFPreferences copyWith({ - Object? layout = _unset, - Object? readingProgression = _unset, - Object? pageSpacing = _unset, - Object? fit = _unset, - Object? offsetFirstPage = _unset, - Object? spread = _unset, - Object? visibleScrollbar = _unset, + Object? layout = unset, + Object? readingProgression = unset, + Object? pageSpacing = unset, + Object? fit = unset, + Object? offsetFirstPage = unset, + Object? spread = unset, + Object? visibleScrollbar = unset, }) => PDFPreferences( - layout: identical(layout, _unset) ? this.layout : (layout as PDFLayout?)!, - readingProgression: identical(readingProgression, _unset) + layout: identical(layout, unset) ? this.layout : (layout as PDFLayout?)!, + readingProgression: identical(readingProgression, unset) ? this.readingProgression : (readingProgression as PDFReadingProgression?)!, - pageSpacing: identical(pageSpacing, _unset) ? this.pageSpacing : (pageSpacing as double?)!, - fit: identical(fit, _unset) ? this.fit : (fit as PDFFit?)!, - offsetFirstPage: identical(offsetFirstPage, _unset) ? this.offsetFirstPage : (offsetFirstPage as bool?), - spread: identical(spread, _unset) ? this.spread : (spread as PDFSpread?), - visibleScrollbar: identical(visibleScrollbar, _unset) ? this.visibleScrollbar : (visibleScrollbar as bool?), + pageSpacing: identical(pageSpacing, unset) ? this.pageSpacing : (pageSpacing as double?)!, + fit: identical(fit, unset) ? this.fit : (fit as PDFFit?)!, + offsetFirstPage: identical(offsetFirstPage, unset) ? this.offsetFirstPage : (offsetFirstPage as bool?), + spread: identical(spread, unset) ? this.spread : (spread as PDFSpread?), + visibleScrollbar: identical(visibleScrollbar, unset) ? this.visibleScrollbar : (visibleScrollbar as bool?), ); @override diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart index 496ec694..b3d8a00e 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; import '../enums.dart'; +import '../utils/constants.dart'; import '../utils/jsonable.dart'; import '../utils/readium_log.dart'; import 'index.dart'; @@ -18,8 +19,6 @@ class ReaderTTSVoice with Equatable implements JSONable { this.active, ); - static const _unset = Object(); - factory ReaderTTSVoice({ required String identifier, required String name, @@ -121,20 +120,20 @@ class ReaderTTSVoice with Equatable implements JSONable { ]; ReaderTTSVoice copyWith({ - Object? identifier = _unset, - Object? name = _unset, - Object? language = _unset, - Object? networkRequired = _unset, - Object? gender = _unset, - Object? quality = _unset, - Object? active = _unset, + Object? identifier = unset, + Object? name = unset, + Object? language = unset, + Object? networkRequired = unset, + Object? gender = unset, + Object? quality = unset, + Object? active = unset, }) => ReaderTTSVoice( - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - name: identical(name, _unset) ? this.name : (name as String?)!, - language: identical(language, _unset) ? this.language : (language as String?)!, - networkRequired: identical(networkRequired, _unset) ? this.networkRequired : (networkRequired as bool), - gender: identical(gender, _unset) ? this.gender : (gender as TTSVoiceGender), - quality: identical(quality, _unset) ? this.quality : (quality as TTSVoiceQuality?), - active: identical(active, _unset) ? this.active : (active as bool?), + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + name: identical(name, unset) ? this.name : (name as String?)!, + language: identical(language, unset) ? this.language : (language as String?)!, + networkRequired: identical(networkRequired, unset) ? this.networkRequired : (networkRequired as bool), + gender: identical(gender, unset) ? this.gender : (gender as TTSVoiceGender), + quality: identical(quality, unset) ? this.quality : (quality as TTSVoiceQuality?), + active: identical(active, unset) ? this.active : (active as bool?), ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart b/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart index 93032942..9747acd9 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/facet.dart @@ -6,6 +6,7 @@ import 'package:dartx/dartx.dart'; import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../opds.dart' show OpdsMetadata; import '../publication/link.dart' show Link; @@ -14,8 +15,6 @@ import '../publication/link.dart' show Link; class Facet with Equatable implements JSONable { const Facet({required this.metadata, required this.links}); - static const _unset = Object(); - final OpdsMetadata metadata; final List links; @@ -26,11 +25,11 @@ class Facet with Equatable implements JSONable { String toString() => 'Facet{metadata: $metadata, links: $links}'; Facet copyWith({ - Object? metadata = _unset, - Object? links = _unset, + Object? metadata = unset, + Object? links = unset, }) => Facet( - metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata)!, - links: identical(links, _unset) ? this.links : (links as List)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata), + links: identical(links, unset) ? this.links : (links as List), ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart index 80213d90..32b90f32 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart @@ -22,8 +22,6 @@ class Feed extends AdditionalProperties with Equatable implements JSONable { Map? additionalProperties = const {}, }) : super(additionalProperties: additionalProperties ?? const {}); - static const _unset = Object(); - final OpdsMetadata metadata; final List links; final List facets; @@ -52,29 +50,25 @@ class Feed extends AdditionalProperties with Equatable implements JSONable { 'context: $context}'; Feed copyWith({ - Object? metadata = _unset, - Object? links = _unset, - Object? facets = _unset, - Object? groups = _unset, - Object? publications = _unset, - Object? navigation = _unset, - Object? context = _unset, - Object? additionalProperties = _unset, + Object? metadata = unset, + Object? links = unset, + Object? facets = unset, + Object? groups = unset, + Object? publications = unset, + Object? navigation = unset, + Object? context = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Feed( - metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - facets: identical(facets, _unset) ? this.facets : (facets as List?)!, - groups: identical(groups, _unset) ? this.groups : (groups as List?)!, - publications: identical(publications, _unset) ? this.publications : (publications as List?)!, - navigation: identical(navigation, _unset) ? this.navigation : (navigation as List?)!, - context: identical(context, _unset) ? this.context : (context as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + facets: identical(facets, unset) ? this.facets : (facets as List?)!, + groups: identical(groups, unset) ? this.groups : (groups as List?)!, + publications: identical(publications, unset) ? this.publications : (publications as List?)!, + navigation: identical(navigation, unset) ? this.navigation : (navigation as List?)!, + context: identical(context, unset) ? this.context : (context as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart index 45ce20a3..0cbf4355 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart @@ -7,6 +7,7 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../opds.dart'; import '../publication/link.dart'; @@ -20,8 +21,6 @@ class Group with Equatable implements JSONable { this.navigation = const [], }); - static const _unset = Object(); - final OpdsMetadata metadata; final List links; final List publications; @@ -36,15 +35,15 @@ class Group with Equatable implements JSONable { 'publications: $publications, navigation: $navigation}'; Group copyWith({ - Object? metadata = _unset, - Object? links = _unset, - Object? publications = _unset, - Object? navigation = _unset, + Object? metadata = unset, + Object? links = unset, + Object? publications = unset, + Object? navigation = unset, }) => Group( - metadata: identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - publications: identical(publications, _unset) ? this.publications : (publications as List?)!, - navigation: identical(navigation, _unset) ? this.navigation : (navigation as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + publications: identical(publications, unset) ? this.publications : (publications as List?)!, + navigation: identical(navigation, unset) ? this.navigation : (navigation as List?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart index ffe00695..4a88fb0c 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart @@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; import '../../utils/additional_properties.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../publication/link.dart'; @@ -142,8 +143,6 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements super.additionalProperties = const {}, }); - static const _unset = Object(); - /// Title of the Catalog being accessed final String type; @@ -213,45 +212,41 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements ..putJSONableIfNotEmpty('web_color_scheme', webColorScheme); OpdsAuthentication copyWith({ - Object? type = _unset, - Object? id = _unset, - Object? description = _unset, - Object? links = _unset, - Object? announcements = _unset, - Object? audiences = _unset, - Object? collectionSize = _unset, - Object? colorScheme = _unset, - Object? featureFlags = _unset, - Object? inputs = _unset, - Object? labels = _unset, - Object? publicKey = _unset, - Object? serviceDescription = _unset, - Object? webColorScheme = _unset, - Object? additionalProperties = _unset, + Object? type = unset, + Object? id = unset, + Object? description = unset, + Object? links = unset, + Object? announcements = unset, + Object? audiences = unset, + Object? collectionSize = unset, + Object? colorScheme = unset, + Object? featureFlags = unset, + Object? inputs = unset, + Object? labels = unset, + Object? publicKey = unset, + Object? serviceDescription = unset, + Object? webColorScheme = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return OpdsAuthentication( - type: identical(type, _unset) ? this.type : (type as String?)!, - id: identical(id, _unset) ? this.id : (id as String?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - description: identical(description, _unset) ? this.description : description as String?, - announcements: identical(announcements, _unset) ? this.announcements : (announcements as List?)!, - audiences: identical(audiences, _unset) ? this.audiences : (audiences as List?)!, - collectionSize: identical(collectionSize, _unset) ? this.collectionSize : (collectionSize as Map?)!, - colorScheme: identical(colorScheme, _unset) ? this.colorScheme : colorScheme as String?, - featureFlags: identical(featureFlags, _unset) ? this.featureFlags : (featureFlags as FeatureFlags?)!, - inputs: identical(inputs, _unset) ? this.inputs : (inputs as InputData?)!, - labels: identical(labels, _unset) ? this.labels : (labels as Map?)!, - publicKey: identical(publicKey, _unset) ? this.publicKey : (publicKey as PublicKeyData?)!, - serviceDescription: identical(serviceDescription, _unset) + type: identical(type, unset) ? this.type : (type as String?)!, + id: identical(id, unset) ? this.id : (id as String?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + description: identical(description, unset) ? this.description : description as String?, + announcements: identical(announcements, unset) ? this.announcements : (announcements as List?)!, + audiences: identical(audiences, unset) ? this.audiences : (audiences as List?)!, + collectionSize: identical(collectionSize, unset) ? this.collectionSize : (collectionSize as Map?)!, + colorScheme: identical(colorScheme, unset) ? this.colorScheme : colorScheme as String?, + featureFlags: identical(featureFlags, unset) ? this.featureFlags : (featureFlags as FeatureFlags?)!, + inputs: identical(inputs, unset) ? this.inputs : (inputs as InputData?)!, + labels: identical(labels, unset) ? this.labels : (labels as Map?)!, + publicKey: identical(publicKey, unset) ? this.publicKey : (publicKey as PublicKeyData?)!, + serviceDescription: identical(serviceDescription, unset) ? this.serviceDescription : serviceDescription as String?, - webColorScheme: identical(webColorScheme, _unset) ? this.webColorScheme : (webColorScheme as WebColor?)!, + webColorScheme: identical(webColorScheme, unset) ? this.webColorScheme : (webColorScheme as WebColor?)!, additionalProperties: mergeProperties, ); } @@ -297,7 +292,6 @@ class OpdsAuthenticationFlow with Equatable implements JSONable { } const OpdsAuthenticationFlow({required this.type, this.links = const []}); - static const _unset = Object(); final String type; final List links; @@ -306,9 +300,9 @@ class OpdsAuthenticationFlow with Equatable implements JSONable { ..put('type', type) ..putIterableIfNotEmpty('links', links); - OpdsAuthenticationFlow copyWith({Object? type = _unset, Object? links = _unset}) => OpdsAuthenticationFlow( - type: identical(type, _unset) ? this.type : (type as String?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, + OpdsAuthenticationFlow copyWith({Object? type = unset, Object? links = unset}) => OpdsAuthenticationFlow( + type: identical(type, unset) ? this.type : (type as String?)!, + links: identical(links, unset) ? this.links : (links as List?)!, ); @override @@ -327,8 +321,6 @@ class OpdsAuthenticationLabels with Equatable implements JSONable { } const OpdsAuthenticationLabels({this.login, this.password}); - static const _unset = Object(); - final String? login; final String? password; @@ -337,9 +329,9 @@ class OpdsAuthenticationLabels with Equatable implements JSONable { ..putOpt('login', login) ..putOpt('password', password); - OpdsAuthenticationLabels copyWith({Object? login = _unset, Object? password = _unset}) => OpdsAuthenticationLabels( - login: identical(login, _unset) ? this.login : (login as String?)!, - password: identical(password, _unset) ? this.password : (password as String?)!, + OpdsAuthenticationLabels copyWith({Object? login = unset, Object? password = unset}) => OpdsAuthenticationLabels( + login: identical(login, unset) ? this.login : (login as String?)!, + password: identical(password, unset) ? this.password : (password as String?)!, ); @override @@ -376,22 +368,16 @@ class Announcement extends AdditionalProperties with Equatable implements JSONab ..put('id', id) ..put('content', content); - static const _unset = Object(); - Announcement copyWith({ - Object? id = _unset, - Object? content = _unset, - Object? additionalProperties = _unset, + Object? id = unset, + Object? content = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Announcement( - id: identical(id, _unset) ? this.id : (id as String?)!, - content: identical(content, _unset) ? this.content : (content as String?)!, + id: identical(id, unset) ? this.id : (id as String?)!, + content: identical(content, unset) ? this.content : (content as String?)!, additionalProperties: mergeProperties, ); } @@ -470,11 +456,9 @@ class FeatureFlags with Equatable implements JSONable { ..putIterableIfNotEmpty('enabled', enabled) ..putIterableIfNotEmpty('disabled', disabled); - static const _unset = Object(); - - FeatureFlags copyWith({Object? enabled = _unset, Object? disabled = _unset}) => FeatureFlags( - enabled: identical(enabled, _unset) ? this.enabled : (enabled as List?)!, - disabled: identical(disabled, _unset) ? this.disabled : (disabled as List?)!, + FeatureFlags copyWith({Object? enabled = unset, Object? disabled = unset}) => FeatureFlags( + enabled: identical(enabled, unset) ? this.enabled : (enabled as List?)!, + disabled: identical(disabled, unset) ? this.disabled : (disabled as List?)!, ); @override @@ -502,16 +486,14 @@ class InputField with Equatable implements JSONable { final KeyboardType? keyboard; final int? maximumLength; - static const _unset = Object(); - @override Map toJson() => {} ..putOpt('keyboard', keyboard?.name) ..putOpt('maximum_length', maximumLength); - InputField copyWith({Object? keyboard = _unset, Object? maximumLength = _unset}) => InputField( - keyboard: identical(keyboard, _unset) ? this.keyboard : keyboard as KeyboardType?, - maximumLength: identical(maximumLength, _unset) ? this.maximumLength : maximumLength as int?, + InputField copyWith({Object? keyboard = unset, Object? maximumLength = unset}) => InputField( + keyboard: identical(keyboard, unset) ? this.keyboard : keyboard as KeyboardType?, + maximumLength: identical(maximumLength, unset) ? this.maximumLength : maximumLength as int?, ); @override @@ -571,17 +553,15 @@ class LoginInputField extends InputField with Equatable { @override Map toJson() => super.toJson()..putOpt('barcode_format', barcodeFormat); - static const _unset = Object(); - @override LoginInputField copyWith({ - Object? barcodeFormat = _unset, - Object? keyboard = _unset, - Object? maximumLength = _unset, + Object? barcodeFormat = unset, + Object? keyboard = unset, + Object? maximumLength = unset, }) => LoginInputField( - barcodeFormat: identical(barcodeFormat, _unset) ? this.barcodeFormat : barcodeFormat as String?, - keyboard: identical(keyboard, _unset) ? this.keyboard : keyboard as KeyboardType?, - maximumLength: identical(maximumLength, _unset) ? this.maximumLength : maximumLength as int?, + barcodeFormat: identical(barcodeFormat, unset) ? this.barcodeFormat : barcodeFormat as String?, + keyboard: identical(keyboard, unset) ? this.keyboard : keyboard as KeyboardType?, + maximumLength: identical(maximumLength, unset) ? this.maximumLength : maximumLength as int?, ); @override @@ -617,11 +597,9 @@ class InputData with Equatable implements JSONable { ..put('login', login) ..put('password', password); - static const _unset = Object(); - - InputData copyWith({Object? login = _unset, Object? password = _unset}) => InputData( - login: identical(login, _unset) ? this.login : (login as LoginInputField?)!, - password: identical(password, _unset) ? this.password : (password as InputField?)!, + InputData copyWith({Object? login = unset, Object? password = unset}) => InputData( + login: identical(login, unset) ? this.login : (login as LoginInputField?)!, + password: identical(password, unset) ? this.password : (password as InputField?)!, ); @override @@ -652,11 +630,9 @@ class PublicKeyData with Equatable implements JSONable { ..put('type', type) ..put('value', value); - static const _unset = Object(); - - PublicKeyData copyWith({Object? type = _unset, Object? value = _unset}) => PublicKeyData( - type: identical(type, _unset) ? this.type : (type as String?)!, - value: identical(value, _unset) ? this.value : (value as String?)!, + PublicKeyData copyWith({Object? type = unset, Object? value = unset}) => PublicKeyData( + type: identical(type, unset) ? this.type : (type as String?)!, + value: identical(value, unset) ? this.value : (value as String?)!, ); @override @@ -696,11 +672,9 @@ class WebColor with Equatable implements JSONable { ..putOpt('primary', primary) ..putOpt('secondary', secondary); - static const _unset = Object(); - - WebColor copyWith({Object? primary = _unset, Object? secondary = _unset}) => WebColor( - primary: identical(primary, _unset) ? this.primary : (primary as String?)!, - secondary: identical(secondary, _unset) ? this.secondary : (secondary as String?)!, + WebColor copyWith({Object? primary = unset, Object? secondary = unset}) => WebColor( + primary: identical(primary, unset) ? this.primary : (primary as String?)!, + secondary: identical(secondary, unset) ? this.secondary : (secondary as String?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart index f5398c4f..bd739e57 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart @@ -26,8 +26,6 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab super.additionalProperties, }); - static const _unset = Object(); - final String? identifier; final LocalizedString localizedTitle; @@ -57,37 +55,33 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab ]; OpdsMetadata copyWith({ - Object? localizedTitle = _unset, - Object? localizedSubtitle = _unset, - Object? identifier = _unset, - Object? description = _unset, - Object? numberOfItems = _unset, - Object? itemsPerPage = _unset, - Object? currentPage = _unset, - Object? modified = _unset, - Object? position = _unset, - Object? rdfType = _unset, - Object? additionalProperties = _unset, + Object? localizedTitle = unset, + Object? localizedSubtitle = unset, + Object? identifier = unset, + Object? description = unset, + Object? numberOfItems = unset, + Object? itemsPerPage = unset, + Object? currentPage = unset, + Object? modified = unset, + Object? position = unset, + Object? rdfType = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return OpdsMetadata( - localizedTitle: identical(localizedTitle, _unset) ? this.localizedTitle : (localizedTitle as LocalizedString?)!, - localizedSubtitle: identical(localizedSubtitle, _unset) + localizedTitle: identical(localizedTitle, unset) ? this.localizedTitle : (localizedTitle as LocalizedString?)!, + localizedSubtitle: identical(localizedSubtitle, unset) ? this.localizedSubtitle : localizedSubtitle as LocalizedString?, - identifier: identical(identifier, _unset) ? this.identifier : identifier as String?, - description: identical(description, _unset) ? this.description : description as String?, - numberOfItems: identical(numberOfItems, _unset) ? this.numberOfItems : numberOfItems as int?, - itemsPerPage: identical(itemsPerPage, _unset) ? this.itemsPerPage : itemsPerPage as int?, - currentPage: identical(currentPage, _unset) ? this.currentPage : currentPage as int?, - modified: identical(modified, _unset) ? this.modified : modified as DateTime?, - position: identical(position, _unset) ? this.position : position as double?, - rdfType: identical(rdfType, _unset) ? this.rdfType : rdfType as String?, + identifier: identical(identifier, unset) ? this.identifier : identifier as String?, + description: identical(description, unset) ? this.description : description as String?, + numberOfItems: identical(numberOfItems, unset) ? this.numberOfItems : numberOfItems as int?, + itemsPerPage: identical(itemsPerPage, unset) ? this.itemsPerPage : itemsPerPage as int?, + currentPage: identical(currentPage, unset) ? this.currentPage : currentPage as int?, + modified: identical(modified, unset) ? this.modified : modified as DateTime?, + position: identical(position, unset) ? this.position : position as double?, + rdfType: identical(rdfType, unset) ? this.rdfType : rdfType as String?, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart index ce601b2c..5f41a91e 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_publication.dart @@ -7,20 +7,18 @@ import '../../../flutter_readium_platform_interface.dart'; class OpdsPublication implements JSONable { const OpdsPublication(this.metadata, this.links, {this.images = const []}); - static const _unset = Object(); - final OpdsMetadata metadata; final List links; final List images; OpdsPublication copyWith({ - Object? metadata = _unset, - Object? links = _unset, - Object? images = _unset, + Object? metadata = unset, + Object? links = unset, + Object? images = unset, }) => OpdsPublication( - identical(metadata, _unset) ? this.metadata : (metadata as OpdsMetadata?)!, - identical(links, _unset) ? this.links : (links as List?)!, - images: identical(images, _unset) ? this.images : (images as List?)!, + identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata?)!, + identical(links, unset) ? this.links : (links as List?)!, + images: identical(images, unset) ? this.images : (images as List?)!, ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart b/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart index f3b167e3..d393e0d3 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/localized_string.dart @@ -8,6 +8,7 @@ import 'package:dfunc/dfunc.dart'; import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../../utils/readium_log.dart'; @@ -143,10 +144,8 @@ class LocalizedString with Equatable implements JSONable { ), ); - static const _unset = Object(); - - LocalizedString copyWith({Map? translations}) => LocalizedString( - translations: identical(translations, _unset) ? const {} : (translations ?? const {}) as Map, + LocalizedString copyWith({Object? translations = unset}) => LocalizedString( + translations: identical(translations, unset) ? const {} : (translations ?? const {}) as Map, ); /// Serializes a [LocalizedString] to its RWPM JSON representation. diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart index 2575d4b5..1af85c08 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart @@ -11,6 +11,7 @@ import 'package:meta/meta.dart'; import '../../extensions/readium_string_extensions.dart'; import '../../extensions/strings.dart'; import '../../utils/additional_properties.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../../utils/readium_log.dart'; import '../../utils/take.dart'; @@ -68,8 +69,6 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { super.additionalProperties, }) : super(); - static const _unset = Object(); - /// The URI of the resource that the Locator Object points to. final String href; @@ -154,43 +153,39 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { ..putJSONableIfNotEmpty('text', text); Locator copyWith({ - Object? href = _unset, - Object? type = _unset, - Object? title = _unset, - Object? locations = _unset, - Object? text = _unset, - Object? additionalProperties = _unset, + Object? href = unset, + Object? type = unset, + Object? title = unset, + Object? locations = unset, + Object? text = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Locator( - href: identical(href, _unset) ? this.href : (href as String?)!, - type: identical(type, _unset) ? this.type : (type as String?)!, - title: identical(title, _unset) ? this.title : title as String?, - locations: identical(locations, _unset) ? this.locations : (locations as Locations?)!, - text: identical(text, _unset) ? this.text : (text as LocatorText?)!, + href: identical(href, unset) ? this.href : (href as String?)!, + type: identical(type, unset) ? this.type : (type as String?)!, + title: identical(title, unset) ? this.title : title as String?, + locations: identical(locations, unset) ? this.locations : (locations as Locations?)!, + text: identical(text, unset) ? this.text : (text as LocatorText?)!, additionalProperties: mergeProperties, ); } /// Shortcut to get a copy of the [Locator] with different [Locations] sub-properties. Locator copyWithLocations({ - Object? fragments = _unset, - Object? progression = _unset, - Object? position = _unset, - Object? totalProgression = _unset, - Object? otherLocations = _unset, + Object? fragments = unset, + Object? progression = unset, + Object? position = unset, + Object? totalProgression = unset, + Object? otherLocations = unset, }) => copyWith( locations: (locations ?? Locations()).copyWith( - fragments: identical(fragments, _unset) ? this.locations?.fragments : (fragments as List?)!, - progression: identical(progression, _unset) ? null : (progression as double?), - position: identical(position, _unset) ? null : (position as int?), - totalProgression: identical(totalProgression, _unset) ? null : (totalProgression as double?), - additionalProperties: identical(otherLocations, _unset) || otherLocations == null + fragments: identical(fragments, unset) ? locations?.fragments : (fragments as List?)!, + progression: identical(progression, unset) ? null : (progression as double?), + position: identical(position, unset) ? null : (position as int?), + totalProgression: identical(totalProgression, unset) ? null : (totalProgression as double?), + additionalProperties: identical(otherLocations, unset) || otherLocations == null ? locations?.additionalProperties : (otherLocations as Map?), ), @@ -258,8 +253,6 @@ class Locations extends AdditionalProperties with Equatable implements JSONable super.additionalProperties, }); - static const _unset = Object(); - factory Locations.fromJson(Map? json) { if (json == null) { return Locations(); @@ -320,29 +313,25 @@ class Locations extends AdditionalProperties with Equatable implements JSONable final String? partialCfi; Locations copyWith({ - Object? position = _unset, - Object? progression = _unset, - Object? totalProgression = _unset, - Object? fragments = _unset, - Object? additionalProperties = _unset, - Object? cssSelector = _unset, - Object? domRange = _unset, - Object? partialCfi = _unset, + Object? position = unset, + Object? progression = unset, + Object? totalProgression = unset, + Object? fragments = unset, + Object? additionalProperties = unset, + Object? cssSelector = unset, + Object? domRange = unset, + Object? partialCfi = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Locations( - progression: identical(progression, _unset) ? this.progression : (progression as double?)!, - position: identical(position, _unset) ? this.position : (position as int?)!, - totalProgression: identical(totalProgression, _unset) ? this.totalProgression : (totalProgression as double?)!, - fragments: identical(fragments, _unset) ? this.fragments : (fragments as List?)!, - cssSelector: identical(cssSelector, _unset) ? this.cssSelector : (cssSelector as String?)!, - domRange: identical(domRange, _unset) ? this.domRange : (domRange as DomRange?)!, - partialCfi: identical(partialCfi, _unset) ? this.partialCfi : (partialCfi as String?)!, + progression: identical(progression, unset) ? this.progression : (progression as double?)!, + position: identical(position, unset) ? this.position : (position as int?)!, + totalProgression: identical(totalProgression, unset) ? this.totalProgression : (totalProgression as double?)!, + fragments: identical(fragments, unset) ? this.fragments : (fragments as List?)!, + cssSelector: identical(cssSelector, unset) ? this.cssSelector : (cssSelector as String?)!, + domRange: identical(domRange, unset) ? this.domRange : (domRange as DomRange?)!, + partialCfi: identical(partialCfi, unset) ? this.partialCfi : (partialCfi as String?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart index 35029ef4..a292eefb 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; import '../../utils/additional_properties.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import 'link.dart'; import 'locator.dart'; @@ -17,8 +18,6 @@ class LocatorCollection with Equatable implements JSONable { this.locators = const [], }); - static const _unset = Object(); - final LocatorCollectionMetadata metadata; final List links; final List locators; @@ -67,13 +66,13 @@ class LocatorCollection with Equatable implements JSONable { } LocatorCollection copyWith({ - Object? metadata = _unset, - Object? links = _unset, - Object? locators = _unset, + Object? metadata = unset, + Object? links = unset, + Object? locators = unset, }) => LocatorCollection( - metadata: identical(metadata, _unset) ? this.metadata : (metadata as LocatorCollectionMetadata?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - locators: identical(locators, _unset) ? this.locators : (locators as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as LocatorCollectionMetadata?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + locators: identical(locators, unset) ? this.locators : (locators as List?)!, ); @override @@ -92,8 +91,6 @@ class LocatorCollectionMetadata extends AdditionalProperties with Equatable impl super.additionalProperties, }); - static const _unset = Object(); - /// The localized title. Can be a simple string or a map of language codes to strings. final dynamic localizedTitle; @@ -158,15 +155,13 @@ class LocatorCollectionMetadata extends AdditionalProperties with Equatable impl } LocatorCollectionMetadata copyWith({ - Object? localizedTitle = _unset, - Object? numberOfItems = _unset, - Object? additionalProperties = _unset, + Object? localizedTitle = unset, + Object? numberOfItems = unset, + Object? additionalProperties = unset, }) => LocatorCollectionMetadata( - localizedTitle: identical(localizedTitle, _unset) ? this.localizedTitle : localizedTitle, - numberOfItems: identical(numberOfItems, _unset) ? this.numberOfItems : (numberOfItems as int?)!, - additionalProperties: identical(additionalProperties, _unset) || additionalProperties == null - ? this.additionalProperties - : (additionalProperties as Map), + localizedTitle: identical(localizedTitle, unset) ? this.localizedTitle : localizedTitle, + numberOfItems: identical(numberOfItems, unset) ? this.numberOfItems : (numberOfItems as int?)!, + additionalProperties: copyAdditionalProperties(additionalProperties: additionalProperties), ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart index e238c23d..0dbb088b 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart @@ -68,38 +68,32 @@ class Chapter extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - final List series; Chapter copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? series = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? series = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Chapter( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - series: identical(series, _unset) ? this.series : (series as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + series: identical(series, unset) ? this.series : (series as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart index 8b914d70..997e736f 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/collection.dart @@ -61,8 +61,6 @@ class Collection extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - @override toJson() { if (additionalProperties.isEmpty && @@ -83,31 +81,27 @@ class Collection extends BaseCollection { } Collection copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Collection( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart index 3cc471cd..d1b8f208 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/contributor.dart @@ -61,8 +61,6 @@ class Contributor extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - /// All values for the role element should be based on https://www.loc.gov/marc/relators/relaterm.html final List? roles; @@ -88,33 +86,29 @@ class Contributor extends BaseCollection { } Contributor copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? roles = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? roles = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Contributor( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - roles: identical(roles, _unset) ? this.roles : (roles as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + roles: identical(roles, unset) ? this.roles : (roles as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart index 59f8aba4..056d2c93 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart @@ -66,8 +66,6 @@ class Episode extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - @override toJson() { if (additionalProperties.isEmpty && @@ -89,31 +87,27 @@ class Episode extends BaseCollection { } Episode copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Episode( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart index 48a432e2..a0fa8140 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart @@ -76,41 +76,35 @@ class Issue extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - final List
articles; final List chapters; Issue copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? articles = _unset, - Object? chapters = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? articles = unset, + Object? chapters = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Issue( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - articles: identical(articles, _unset) ? this.articles : (articles as List
?)!, - chapters: identical(chapters, _unset) ? this.chapters : (chapters as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + articles: identical(articles, unset) ? this.articles : (articles as List
?)!, + chapters: identical(chapters, unset) ? this.chapters : (chapters as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart index 747d64ad..5bb8dc1d 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/periodical.dart @@ -66,8 +66,6 @@ class Periodical extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - final List issues; final List volumes; @@ -93,35 +91,31 @@ class Periodical extends BaseCollection { } Periodical copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? issues = _unset, - Object? volumes = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? issues = unset, + Object? volumes = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Periodical( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - issues: identical(issues, _unset) ? this.issues : (issues as List?)!, - volumes: identical(volumes, _unset) ? this.volumes : (volumes as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + issues: identical(issues, unset) ? this.issues : (issues as List?)!, + volumes: identical(volumes, unset) ? this.volumes : (volumes as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart index 3f3598c6..7d634c16 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart @@ -71,8 +71,6 @@ class Season extends BaseCollection { super.additionalProperties, }); - static const _unset = Object(); - final List episodes; @override @@ -98,33 +96,29 @@ class Season extends BaseCollection { } Season copyWith({ - Object? position = _unset, - Object? localizedName = _unset, - Object? identifier = _unset, - Object? altIdentifiers = _unset, - Object? localizedSortAs = _unset, - Object? links = _unset, - Object? episodes = _unset, - Object? additionalProperties = _unset, + Object? position = unset, + Object? localizedName = unset, + Object? identifier = unset, + Object? altIdentifiers = unset, + Object? localizedSortAs = unset, + Object? links = unset, + Object? episodes = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Season( - position: identical(position, _unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, _unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, _unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, _unset) + position: identical(position, unset) ? this.position : (position as double?)!, + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, _unset) + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - episodes: identical(episodes, _unset) ? this.episodes : (episodes as List?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + episodes: identical(episodes, unset) ? this.episodes : (episodes as List?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart b/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart index d3d94410..e5d9b02a 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/properties.dart @@ -8,6 +8,7 @@ import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; import '../../utils/additional_properties.dart'; +import '../../utils/constants.dart'; import '../../utils/jsonable.dart'; import '../publication.dart'; @@ -31,8 +32,6 @@ class Properties extends AdditionalProperties with Equatable implements JSONable super.additionalProperties, }); - static const _unset = Object(); - /// (Nullable) Indicates how the linked resource should be displayed in a /// reading environment that displays synthetic spreads. final PresentationPage? page; @@ -80,29 +79,25 @@ class Properties extends AdditionalProperties with Equatable implements JSONable ..putOpt('encryption', encryption); Properties copyWith({ - Object? page = _unset, - Object? contains = _unset, - Object? orientation = _unset, - Object? layout = _unset, - Object? overflow = _unset, - Object? spread = _unset, - Object? encryption = _unset, - Object? additionalProperties = _unset, + Object? page = unset, + Object? contains = unset, + Object? orientation = unset, + Object? layout = unset, + Object? overflow = unset, + Object? spread = unset, + Object? encryption = unset, + Object? additionalProperties = unset, }) { - final mergeProperties = identical(additionalProperties, _unset) || additionalProperties == null - ? Map.of(this.additionalProperties) - : Map.of(this.additionalProperties) - ..addAll(additionalProperties as Map) - ..removeWhere((key, value) => value == null); + final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Properties( - page: identical(page, _unset) ? this.page : (page as PresentationPage?)!, - contains: identical(contains, _unset) ? this.contains : (contains as List?)?.toSet().toList(), - orientation: identical(orientation, _unset) ? this.orientation : (orientation as PresentationOrientation?)!, - layout: identical(layout, _unset) ? this.layout : (layout as EpubLayout?)!, - overflow: identical(overflow, _unset) ? this.overflow : (overflow as PresentationOverflow?)!, - spread: identical(spread, _unset) ? this.spread : (spread as PresentationSpread?)!, - encryption: identical(encryption, _unset) ? this.encryption : (encryption as Encryption?)!, + page: identical(page, unset) ? this.page : (page as PresentationPage?)!, + contains: identical(contains, unset) ? this.contains : (contains as List?)?.toSet().toList(), + orientation: identical(orientation, unset) ? this.orientation : (orientation as PresentationOrientation?)!, + layout: identical(layout, unset) ? this.layout : (layout as EpubLayout?)!, + overflow: identical(overflow, unset) ? this.overflow : (overflow as PresentationOverflow?)!, + spread: identical(spread, unset) ? this.spread : (spread as PresentationSpread?)!, + encryption: identical(encryption, unset) ? this.encryption : (encryption as Encryption?)!, additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart index f737cb22..0b8f18b4 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart @@ -28,8 +28,6 @@ class Publication with Equatable implements JSONable { this.subCollections = const {}, }); - static const _unset = Object(); - /// JSON-LD context URIs declaring the vocabulary used by this manifest. final List context; @@ -63,21 +61,21 @@ class Publication with Equatable implements JSONable { /// Returns a copy of this publication with the given fields replaced. Publication copyWith({ - Object? context = _unset, - Object? metadata = _unset, - Object? links = _unset, - Object? readingOrder = _unset, - Object? resources = _unset, - Object? tableOfContents = _unset, - Object? subCollections = _unset, + Object? context = unset, + Object? metadata = unset, + Object? links = unset, + Object? readingOrder = unset, + Object? resources = unset, + Object? tableOfContents = unset, + Object? subCollections = unset, }) => Publication( - context: identical(context, _unset) ? this.context : (context as List?)!, - metadata: identical(metadata, _unset) ? this.metadata : (metadata as Metadata?)!, - links: identical(links, _unset) ? this.links : (links as List?)!, - readingOrder: identical(readingOrder, _unset) ? this.readingOrder : (readingOrder as List?)!, - resources: identical(resources, _unset) ? this.resources : (resources as List?)!, - tableOfContents: identical(tableOfContents, _unset) ? this.tableOfContents : (tableOfContents as List?)!, - subCollections: identical(subCollections, _unset) + context: identical(context, unset) ? this.context : (context as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as Metadata?)!, + links: identical(links, unset) ? this.links : (links as List?)!, + readingOrder: identical(readingOrder, unset) ? this.readingOrder : (readingOrder as List?)!, + resources: identical(resources, unset) ? this.resources : (resources as List?)!, + tableOfContents: identical(tableOfContents, unset) ? this.tableOfContents : (tableOfContents as List?)!, + subCollections: identical(subCollections, unset) ? this.subCollections : (subCollections as Map>?)!, ); diff --git a/flutter_readium_platform_interface/lib/src/timebased_state.dart b/flutter_readium_platform_interface/lib/src/timebased_state.dart index 03330e39..0ce9b761 100644 --- a/flutter_readium_platform_interface/lib/src/timebased_state.dart +++ b/flutter_readium_platform_interface/lib/src/timebased_state.dart @@ -2,6 +2,7 @@ import 'package:meta/meta.dart'; import 'enums.dart'; import 'shared/publication/locator.dart'; +import 'utils/constants.dart'; import 'utils/jsonable.dart'; @immutable @@ -16,8 +17,6 @@ class ReadiumTimebasedState implements JSONable { this.currentLocator, }); - static const _unset = Object(); - factory ReadiumTimebasedState.fromJson(final Map map) { final jsonObject = Map.of(map); @@ -118,22 +117,22 @@ class ReadiumTimebasedState implements JSONable { ..putOpt('currentLocator', currentLocator?.toJson()); ReadiumTimebasedState copyWith({ - Object? state = _unset, - Object? currentOffset = _unset, - Object? currentBuffered = _unset, - Object? currentDuration = _unset, - Object? totalProgressDuration = _unset, - Object? totalDuration = _unset, - Object? currentLocator = _unset, + Object? state = unset, + Object? currentOffset = unset, + Object? currentBuffered = unset, + Object? currentDuration = unset, + Object? totalProgressDuration = unset, + Object? totalDuration = unset, + Object? currentLocator = unset, }) => ReadiumTimebasedState( - state: identical(state, _unset) ? this.state : (state as TimebasedState?)!, - currentOffset: identical(currentOffset, _unset) ? this.currentOffset : (currentOffset as Duration?)!, - currentBuffered: identical(currentBuffered, _unset) ? this.currentBuffered : (currentBuffered as Duration?)!, - currentDuration: identical(currentDuration, _unset) ? this.currentDuration : (currentDuration as Duration?)!, - totalProgressDuration: identical(totalProgressDuration, _unset) + state: identical(state, unset) ? this.state : (state as TimebasedState?)!, + currentOffset: identical(currentOffset, unset) ? this.currentOffset : (currentOffset as Duration?)!, + currentBuffered: identical(currentBuffered, unset) ? this.currentBuffered : (currentBuffered as Duration?)!, + currentDuration: identical(currentDuration, unset) ? this.currentDuration : (currentDuration as Duration?)!, + totalProgressDuration: identical(totalProgressDuration, unset) ? this.totalProgressDuration : (totalProgressDuration as Duration?)!, - totalDuration: identical(totalDuration, _unset) ? this.totalDuration : (totalDuration as Duration?)!, - currentLocator: identical(currentLocator, _unset) ? this.currentLocator : (currentLocator as Locator?)!, + totalDuration: identical(totalDuration, unset) ? this.totalDuration : (totalDuration as Duration?)!, + currentLocator: identical(currentLocator, unset) ? this.currentLocator : (currentLocator as Locator?)!, ); } diff --git a/flutter_readium_platform_interface/lib/src/utils/additional_properties.dart b/flutter_readium_platform_interface/lib/src/utils/additional_properties.dart index bc23f28a..8eb0d510 100644 --- a/flutter_readium_platform_interface/lib/src/utils/additional_properties.dart +++ b/flutter_readium_platform_interface/lib/src/utils/additional_properties.dart @@ -1,5 +1,7 @@ import 'package:collection/collection.dart'; +import 'constants.dart'; + abstract class AdditionalProperties { const AdditionalProperties({this.additionalProperties = const {}}); @@ -35,4 +37,18 @@ abstract class AdditionalProperties { } return null; } + + /// Returns a new [Map] with the merged additional properties. + Map copyAdditionalProperties({ + Object? additionalProperties = unset, + }) { + if (identical(additionalProperties, unset) || additionalProperties == null) { + return this.additionalProperties; + } + final result = {} + ..addAll(this.additionalProperties) + ..addAll(additionalProperties as Map) + ..removeWhere((key, value) => value == null); + return result; + } } diff --git a/flutter_readium_platform_interface/lib/src/utils/constants.dart b/flutter_readium_platform_interface/lib/src/utils/constants.dart new file mode 100644 index 00000000..005f5c0d --- /dev/null +++ b/flutter_readium_platform_interface/lib/src/utils/constants.dart @@ -0,0 +1,2 @@ +/// Sentinel value used to distinguish "not set" from null in copyWith methods. +const unset = Object(); diff --git a/flutter_readium_platform_interface/lib/src/utils/index.dart b/flutter_readium_platform_interface/lib/src/utils/index.dart index a43c6300..6cde4245 100644 --- a/flutter_readium_platform_interface/lib/src/utils/index.dart +++ b/flutter_readium_platform_interface/lib/src/utils/index.dart @@ -1,4 +1,5 @@ export 'additional_properties.dart'; +export 'constants.dart'; export 'href.dart'; export 'jsonable.dart'; export 'readium_log.dart'; diff --git a/flutter_readium_platform_interface/test/models_test.dart b/flutter_readium_platform_interface/test/models_test.dart index ac44010a..69a65456 100644 --- a/flutter_readium_platform_interface/test/models_test.dart +++ b/flutter_readium_platform_interface/test/models_test.dart @@ -56,6 +56,33 @@ void main() { expect(restored?.href, '/ch.xhtml'); expect(restored?.type, 'application/xhtml+xml'); }); + + test('copyWith() with no args preserves all fields', () { + final locator = Locator( + href: '/ch.xhtml', + type: 'application/xhtml+xml', + title: 'Chapter 1', + locations: Locations(progression: 0.5), + text: LocatorText(before: 'a', highlight: 'b', after: 'c'), + ); + final copied = locator.copyWith(); + expect(copied.href, '/ch.xhtml'); + expect(copied.type, 'application/xhtml+xml'); + expect(copied.title, 'Chapter 1'); + expect(copied.locations?.progression, closeTo(0.5, 1e-6)); + expect(copied.text?.before, 'a'); + }); + + test('copyWith() overrides only specified fields', () { + final locator = Locator( + href: '/ch.xhtml', + type: 'application/xhtml+xml', + title: 'Chapter 1', + ); + final updated = locator.copyWith(title: 'Updated'); + expect(updated.href, '/ch.xhtml'); + expect(updated.title, 'Updated'); + }); }); // --------------------------------------------------------------------------- @@ -98,6 +125,26 @@ void main() { expect(copied.preventMOColumnBreaks, isTrue); }); + test('copyWith() with no args preserves all fields', () { + const prefs = EPUBPreferences( + preventMOColumnBreaks: true, + spread: 'both', + ); + final copied = prefs.copyWith(); + expect(copied.preventMOColumnBreaks, isTrue); + expect(copied.spread, 'both'); + }); + + test('copyWith() overrides only specified fields', () { + const prefs = EPUBPreferences( + preventMOColumnBreaks: false, + spread: 'both', + ); + final updated = prefs.copyWith(preventMOColumnBreaks: true); + expect(updated.preventMOColumnBreaks, isTrue); + expect(updated.spread, 'both'); + }); + test('equality distinguishes preventMOColumnBreaks values', () { const a = EPUBPreferences(preventMOColumnBreaks: true); const b = EPUBPreferences(preventMOColumnBreaks: false); @@ -130,6 +177,30 @@ void main() { expect(restored.pageSpacing, 8.0); expect(restored.fit, PDFFit.auto); }); + + test('copyWith() with no args preserves all fields', () { + const prefs = PDFPreferences( + layout: PDFLayout.scrollVertical, + readingProgression: PDFReadingProgression.rtl, + pageSpacing: 12.5, + fit: PDFFit.page, + ); + final copied = prefs.copyWith(); + expect(copied.layout, PDFLayout.scrollVertical); + expect(copied.readingProgression, PDFReadingProgression.rtl); + expect(copied.pageSpacing, 12.5); + expect(copied.fit, PDFFit.page); + }); + + test('copyWith() overrides only specified fields', () { + const prefs = PDFPreferences( + layout: PDFLayout.scrollVertical, + pageSpacing: 12.5, + ); + final updated = prefs.copyWith(pageSpacing: 20.0); + expect(updated.layout, PDFLayout.scrollVertical); + expect(updated.pageSpacing, 20.0); + }); }); // --------------------------------------------------------------------------- @@ -624,6 +695,20 @@ void main() { expect(updated.stallTimeoutSeconds, 10.0); }); + test('copyWith() with no args preserves all fields', () { + const policy = AudioRecoveryPolicy( + maxAttempts: 5, + backoffBaseSeconds: 2.0, + stallTimeoutSeconds: 30.0, + connectionTimeoutSeconds: 10.0, + ); + final copied = policy.copyWith(); + expect(copied.maxAttempts, 5); + expect(copied.backoffBaseSeconds, 2.0); + expect(copied.stallTimeoutSeconds, 30.0); + expect(copied.connectionTimeoutSeconds, 10.0); + }); + test('equality is value-based', () { expect(const AudioRecoveryPolicy(), const AudioRecoveryPolicy()); expect( @@ -633,6 +718,912 @@ void main() { }); }); + // --------------------------------------------------------------------------- + // ReaderTTSVoice copyWith + // --------------------------------------------------------------------------- + group('ReaderTTSVoice', () { + test('copyWith() with no args preserves all fields', () { + final voice = ReaderTTSVoice( + identifier: 'voice1', + name: 'Test Voice', + language: 'en-US', + networkRequired: false, + gender: TTSVoiceGender.unspecified, + quality: TTSVoiceQuality.normal, + active: true, + ); + final copied = voice.copyWith(); + expect(copied.identifier, 'voice1'); + expect(copied.name, 'Test Voice'); + expect(copied.language, 'en-US'); + expect(copied.networkRequired, isFalse); + }); + + test('copyWith() overrides only specified fields', () { + final voice = ReaderTTSVoice( + identifier: 'voice1', + name: 'Test Voice', + language: 'en-US', + networkRequired: false, + gender: TTSVoiceGender.unspecified, + quality: TTSVoiceQuality.normal, + active: true, + ); + final updated = voice.copyWith(name: 'Updated Voice'); + expect(updated.identifier, 'voice1'); + expect(updated.name, 'Updated Voice'); + }); + + test('equality is value-based', () { + final a = ReaderTTSVoice( + identifier: 'v1', + name: 'A', + language: 'en', + networkRequired: false, + gender: TTSVoiceGender.unspecified, + quality: TTSVoiceQuality.normal, + active: true, + ); + final b = ReaderTTSVoice( + identifier: 'v1', + name: 'A', + language: 'en', + networkRequired: false, + gender: TTSVoiceGender.unspecified, + quality: TTSVoiceQuality.normal, + active: true, + ); + expect(a, equals(b)); + + final c = ReaderTTSVoice( + identifier: 'v1', + name: 'B', + language: 'en', + networkRequired: false, + gender: TTSVoiceGender.unspecified, + quality: TTSVoiceQuality.normal, + active: true, + ); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // ReaderDecoration copyWith + // --------------------------------------------------------------------------- + group('ReaderDecoration', () { + test('copyWith() with no args preserves all fields', () { + final decoration = ReaderDecoration( + id: 'deco1', + locator: const Locator(href: '/ch.xhtml', type: 'application/xhtml+xml'), + style: const ReaderDecorationStyle(style: DecorationStyle.highlight), + ); + final copied = decoration.copyWith(); + expect(copied.id, 'deco1'); + expect(copied.locator.href, '/ch.xhtml'); + }); + + test('copyWith() overrides only specified fields', () { + final decoration = ReaderDecoration( + id: 'deco1', + locator: const Locator(href: '/ch.xhtml', type: 'application/xhtml+xml'), + style: const ReaderDecorationStyle(style: DecorationStyle.highlight), + ); + final updated = decoration.copyWith(id: 'deco2'); + expect(updated.id, 'deco2'); + expect(updated.locator.href, '/ch.xhtml'); + }); + }); + + // --------------------------------------------------------------------------- + // ReaderDecorationStyle copyWith + // --------------------------------------------------------------------------- + group('ReaderDecorationStyle', () { + test('copyWith() with no args preserves all fields', () { + final style = ReaderDecorationStyle( + style: DecorationStyle.highlight, + tint: const Color(0xFFFF0000), + ); + final copied = style.copyWith(); + expect(copied.style, DecorationStyle.highlight); + expect(copied.tint, const Color(0xFFFF0000)); + }); + + test('copyWith() overrides only specified fields', () { + final style = ReaderDecorationStyle( + style: DecorationStyle.highlight, + tint: const Color(0xFFFF0000), + ); + final updated = style.copyWith(tint: const Color(0xFF00FF00)); + expect(updated.style, DecorationStyle.highlight); + expect(updated.tint, const Color(0xFF00FF00)); + }); + }); + + // --------------------------------------------------------------------------- + // ReadiumTimebasedState copyWith + // --------------------------------------------------------------------------- + group('ReadiumTimebasedState', () { + test('copyWith() with no args preserves all fields', () { + final state = ReadiumTimebasedState( + state: TimebasedState.playing, + currentLocator: const Locator(href: '/ch.xhtml', type: 'application/xhtml+xml'), + ); + final copied = state.copyWith(); + expect(copied.state, TimebasedState.playing); + expect(copied.currentLocator?.href, '/ch.xhtml'); + }); + + test('copyWith() overrides only specified fields', () { + final state = ReadiumTimebasedState( + state: TimebasedState.playing, + ); + final updated = state.copyWith(state: TimebasedState.paused); + expect(updated.state, TimebasedState.paused); + }); + }); + + // --------------------------------------------------------------------------- + // Facet copyWith + // --------------------------------------------------------------------------- + group('Facet', () { + test('copyWith() with no args preserves all fields', () { + final facet = Facet( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/link1.xhtml')], + ); + final copied = facet.copyWith(); + expect(copied.metadata, facet.metadata); + expect(copied.links, facet.links); + }); + + test('copyWith() overrides only specified fields', () { + final facet = Facet( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/link1.xhtml')], + ); + final updated = facet.copyWith(links: [const Link(href: '/link2.xhtml')]); + expect(updated.links.first.href, '/link2.xhtml'); + }); + + test('equality is value-based', () { + final a = Facet( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l1.xhtml')], + ); + final b = Facet( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l1.xhtml')], + ); + expect(a, equals(b)); + + final c = Facet( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l2.xhtml')], + ); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // OpdsPublication copyWith + // --------------------------------------------------------------------------- + group('OpdsPublication', () { + test('copyWith() with no args preserves all fields', () { + final pub = OpdsPublication( + const OpdsMetadata(localizedTitle: LocalizedString()), + [const Link(href: '/link1.xhtml')], + ); + final copied = pub.copyWith(); + expect(copied.metadata, pub.metadata); + expect(copied.links, pub.links); + }); + + test('copyWith() overrides only specified fields', () { + final pub = OpdsPublication( + const OpdsMetadata(localizedTitle: LocalizedString()), + [const Link(href: '/link1.xhtml')], + ); + final updated = pub.copyWith(links: [const Link(href: '/link2.xhtml')]); + expect(updated.links.first.href, '/link2.xhtml'); + }); + }); + + // --------------------------------------------------------------------------- + // Properties copyWith + // --------------------------------------------------------------------------- + group('Properties', () { + test('copyWith() with no args preserves all fields', () { + final props = Properties( + orientation: PresentationOrientation.landscape, + layout: EpubLayout.fixed, + ); + final copied = props.copyWith(); + expect(copied.orientation, PresentationOrientation.landscape); + expect(copied.layout, EpubLayout.fixed); + }); + + test('copyWith() overrides only specified fields', () { + final props = Properties(orientation: PresentationOrientation.landscape); + final updated = props.copyWith(layout: EpubLayout.reflowable); + expect(updated.orientation, PresentationOrientation.landscape); + expect(updated.layout, EpubLayout.reflowable); + }); + }); + + // --------------------------------------------------------------------------- + // Chapter copyWith + // --------------------------------------------------------------------------- + group('Chapter', () { + test('copyWith() with no args preserves all fields', () { + final chapter = Chapter(position: 1.0); + final copied = chapter.copyWith(); + expect(copied.position, 1.0); + }); + + test('copyWith() overrides only specified fields', () { + final chapter = Chapter(position: 1.0); + final updated = chapter.copyWith(position: 2.0); + expect(updated.position, 2.0); + }); + + test('equality is value-based', () { + final a = Chapter(position: 1.0); + final b = Chapter(position: 1.0); + expect(a, equals(b)); + + final c = Chapter(position: 2.0); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Season copyWith + // --------------------------------------------------------------------------- + group('Season', () { + test('copyWith() with no args preserves all fields', () { + final season = Season(position: 1.0); + final copied = season.copyWith(); + expect(copied.position, 1.0); + }); + + test('copyWith() overrides only specified fields', () { + final season = Season(position: 1.0); + final updated = season.copyWith(position: 2.0); + expect(updated.position, 2.0); + }); + + test('equality is value-based', () { + final a = Season(position: 1.0); + final b = Season(position: 1.0); + expect(a, equals(b)); + + final c = Season(position: 2.0); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Episode copyWith + // --------------------------------------------------------------------------- + group('Episode', () { + test('copyWith() with no args preserves all fields', () { + final episode = Episode(position: 1.0); + final copied = episode.copyWith(); + expect(copied.position, 1.0); + }); + + test('copyWith() overrides only specified fields', () { + final episode = Episode(position: 1.0); + final updated = episode.copyWith(position: 2.0); + expect(updated.position, 2.0); + }); + + test('equality is value-based', () { + final a = Episode(position: 1.0); + final b = Episode(position: 1.0); + expect(a, equals(b)); + + final c = Episode(position: 2.0); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Issue copyWith + // --------------------------------------------------------------------------- + group('Issue', () { + test('copyWith() with no args preserves all fields', () { + final issue = Issue(position: 1.0); + final copied = issue.copyWith(); + expect(copied.position, 1.0); + }); + + test('copyWith() overrides only specified fields', () { + final issue = Issue(position: 1.0); + final updated = issue.copyWith(position: 2.0); + expect(updated.position, 2.0); + }); + + test('equality is value-based', () { + final a = Issue(position: 1.0); + final b = Issue(position: 1.0); + expect(a, equals(b)); + + final c = Issue(position: 2.0); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Periodical copyWith + // --------------------------------------------------------------------------- + group('Periodical', () { + test('copyWith() with no args preserves all fields', () { + final periodical = Periodical(localizedName: LocalizedString()); + final copied = periodical.copyWith(); + expect(copied.localizedName, isNotNull); + }); + + test('copyWith() overrides only specified fields', () { + final periodical = Periodical(localizedName: LocalizedString()); + final updated = periodical.copyWith(identifier: 'id1'); + expect(updated.identifier, 'id1'); + }); + + test('equality is value-based', () { + final a = Periodical(localizedName: LocalizedString()); + final b = Periodical(localizedName: LocalizedString()); + expect(a, equals(b)); + + final c = Periodical(localizedName: LocalizedString(), identifier: 'id1'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Collection copyWith + // --------------------------------------------------------------------------- + group('Collection', () { + test('copyWith() with no args preserves all fields', () { + final collection = Collection(localizedName: LocalizedString()); + final copied = collection.copyWith(); + expect(copied.localizedName, isNotNull); + }); + + test('copyWith() overrides only specified fields', () { + final collection = Collection(localizedName: LocalizedString()); + final updated = collection.copyWith(identifier: 'id1'); + expect(updated.identifier, 'id1'); + }); + + test('equality is value-based', () { + final a = Collection(localizedName: LocalizedString()); + final b = Collection(localizedName: LocalizedString()); + expect(a, equals(b)); + + final c = Collection(localizedName: LocalizedString(), identifier: 'id1'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Contributor copyWith + // --------------------------------------------------------------------------- + group('Contributor', () { + test('copyWith() with no args preserves all fields', () { + final contributor = Contributor(localizedName: LocalizedString()); + final copied = contributor.copyWith(); + expect(copied.localizedName, isNotNull); + }); + + test('copyWith() overrides only specified fields', () { + final contributor = Contributor(localizedName: LocalizedString()); + final updated = contributor.copyWith(identifier: 'id1'); + expect(updated.identifier, 'id1'); + }); + + test('equality is value-based', () { + final a = Contributor(localizedName: LocalizedString()); + final b = Contributor(localizedName: LocalizedString()); + expect(a, equals(b)); + + final c = Contributor(localizedName: LocalizedString(), identifier: 'id1'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // OpdsMetadata copyWith + // --------------------------------------------------------------------------- + group('OpdsMetadata', () { + test('copyWith() with no args preserves all fields', () { + final metadata = OpdsMetadata( + localizedTitle: LocalizedString(), + ); + final copied = metadata.copyWith(); + expect(copied.localizedTitle, metadata.localizedTitle); + }); + + test('copyWith() overrides only specified fields', () { + final metadata = OpdsMetadata( + localizedTitle: LocalizedString(), + ); + final updated = metadata.copyWith(identifier: 'id1'); + expect(updated.identifier, 'id1'); + }); + + test('equality is value-based', () { + final a = OpdsMetadata(localizedTitle: LocalizedString()); + final b = OpdsMetadata(localizedTitle: LocalizedString()); + expect(a, equals(b)); + + final c = OpdsMetadata(localizedTitle: LocalizedString(), identifier: 'id1'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Feed copyWith + // --------------------------------------------------------------------------- + group('Feed', () { + test('copyWith() with no args preserves all fields', () { + final feed = Feed( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + ); + final copied = feed.copyWith(); + expect(copied.metadata, feed.metadata); + }); + + test('copyWith() overrides only specified fields', () { + final feed = Feed( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + ); + final updated = feed.copyWith(links: [const Link(href: '/link1.xhtml')]); + expect(updated.links, isNotEmpty); + }); + + test('equality is value-based', () { + final a = Feed(metadata: const OpdsMetadata(localizedTitle: LocalizedString())); + final b = Feed(metadata: const OpdsMetadata(localizedTitle: LocalizedString())); + expect(a, equals(b)); + + final c = Feed( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l1.xhtml')], + ); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Group copyWith + // --------------------------------------------------------------------------- + group('Group', () { + test('copyWith() with no args preserves all fields', () { + final group = Group( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/link1.xhtml')], + ); + final copied = group.copyWith(); + expect(copied.metadata, group.metadata); + expect(copied.links, group.links); + }); + + test('copyWith() overrides only specified fields', () { + final group = Group( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/link1.xhtml')], + ); + final updated = group.copyWith(links: [const Link(href: '/link2.xhtml')]); + expect(updated.links.first.href, '/link2.xhtml'); + }); + + test('equality is value-based', () { + final a = Group( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l1.xhtml')], + ); + final b = Group( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l1.xhtml')], + ); + expect(a, equals(b)); + + final c = Group( + metadata: const OpdsMetadata(localizedTitle: LocalizedString()), + links: [const Link(href: '/l2.xhtml')], + ); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // OpdsAuthentication copyWith + // --------------------------------------------------------------------------- + group('OpdsAuthentication', () { + test('copyWith() with no args preserves all fields', () { + final auth = OpdsAuthentication( + type: 'http://opds-spec.org/auth/schemes/open', + id: 'auth1', + ); + final copied = auth.copyWith(); + expect(copied.type, 'http://opds-spec.org/auth/schemes/open'); + expect(copied.id, 'auth1'); + }); + + test('copyWith() overrides only specified fields', () { + final auth = OpdsAuthentication( + type: 'http://opds-spec.org/auth/schemes/open', + id: 'auth1', + ); + final updated = auth.copyWith(id: 'auth2'); + expect(updated.type, 'http://opds-spec.org/auth/schemes/open'); + expect(updated.id, 'auth2'); + }); + + test('equality is value-based', () { + final a = OpdsAuthentication(type: 't1', id: 'i1'); + final b = OpdsAuthentication(type: 't1', id: 'i1'); + expect(a, equals(b)); + + final c = OpdsAuthentication(type: 't1', id: 'i2'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // OpdsAuthenticationFlow copyWith + // --------------------------------------------------------------------------- + group('OpdsAuthenticationFlow', () { + test('copyWith() with no args preserves all fields', () { + final flow = OpdsAuthenticationFlow( + type: 'http://opds-spec.org/auth/schemes/open', + ); + final copied = flow.copyWith(); + expect(copied.type, 'http://opds-spec.org/auth/schemes/open'); + }); + + test('copyWith() overrides only specified fields', () { + final flow = OpdsAuthenticationFlow( + type: 'http://opds-spec.org/auth/schemes/open', + ); + final updated = flow.copyWith(links: [const Link(href: '/link1.xhtml')]); + expect(updated.links, isNotEmpty); + }); + + test('equality is value-based', () { + final a = OpdsAuthenticationFlow(type: 't1'); + final b = OpdsAuthenticationFlow(type: 't1'); + expect(a, equals(b)); + + final c = OpdsAuthenticationFlow(type: 't2'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // Announcement copyWith + // --------------------------------------------------------------------------- + group('Announcement', () { + test('copyWith() with no args preserves all fields', () { + final announcement = Announcement( + id: 'announce1', + content: 'Test Announcement', + ); + final copied = announcement.copyWith(); + expect(copied.id, 'announce1'); + expect(copied.content, 'Test Announcement'); + }); + + test('copyWith() overrides only specified fields', () { + final announcement = Announcement( + id: 'announce1', + content: 'Original', + ); + final updated = announcement.copyWith(content: 'Updated'); + expect(updated.id, 'announce1'); + expect(updated.content, 'Updated'); + }); + + test('equality is value-based', () { + final a = Announcement(id: 'a1', content: 'C'); + final b = Announcement(id: 'a1', content: 'C'); + expect(a, equals(b)); + + final c = Announcement(id: 'a1', content: 'D'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // FeatureFlags copyWith + // --------------------------------------------------------------------------- + group('FeatureFlags', () { + test('copyWith() with no args preserves all fields', () { + final flags = FeatureFlags( + enabled: ['feature1'], + disabled: ['feature2'], + ); + final copied = flags.copyWith(); + expect(copied.enabled, ['feature1']); + expect(copied.disabled, ['feature2']); + }); + + test('copyWith() overrides only specified fields', () { + final flags = FeatureFlags( + enabled: ['feature1'], + disabled: ['feature2'], + ); + final updated = flags.copyWith(enabled: ['feature3']); + expect(updated.enabled, ['feature3']); + }); + + test('equality is value-based', () { + final a = FeatureFlags(enabled: ['f1'], disabled: ['f2']); + final b = FeatureFlags(enabled: ['f1'], disabled: ['f2']); + expect(a, equals(b)); + + final c = FeatureFlags(enabled: ['f3'], disabled: ['f2']); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // InputField copyWith + // --------------------------------------------------------------------------- + group('InputField', () { + test('copyWith() with no args preserves all fields', () { + final field = InputField( + keyboard: KeyboardType.defaultType, + maximumLength: 100, + ); + final copied = field.copyWith(); + expect(copied.keyboard, KeyboardType.defaultType); + expect(copied.maximumLength, 100); + }); + + test('copyWith() overrides only specified fields', () { + final field = InputField( + keyboard: KeyboardType.defaultType, + maximumLength: 100, + ); + final updated = field.copyWith(maximumLength: 200); + expect(updated.keyboard, KeyboardType.defaultType); + expect(updated.maximumLength, 200); + }); + + test('equality is value-based', () { + final a = InputField(keyboard: KeyboardType.defaultType, maximumLength: 100); + final b = InputField(keyboard: KeyboardType.defaultType, maximumLength: 100); + expect(a, equals(b)); + + final c = InputField(keyboard: KeyboardType.defaultType, maximumLength: 200); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // LoginInputField copyWith + // --------------------------------------------------------------------------- + group('LoginInputField', () { + test('copyWith() with no args preserves all fields', () { + final loginField = LoginInputField( + barcodeFormat: 'qr-code', + ); + final copied = loginField.copyWith(); + expect(copied.barcodeFormat, 'qr-code'); + }); + + test('copyWith() overrides only specified fields', () { + final loginField = LoginInputField( + barcodeFormat: 'qr-code', + ); + final updated = loginField.copyWith(barcodeFormat: 'barcode'); + expect(updated.barcodeFormat, 'barcode'); + }); + + test('equality is value-based', () { + final a = LoginInputField(barcodeFormat: 'qr-code'); + final b = LoginInputField(barcodeFormat: 'qr-code'); + expect(a, equals(b)); + + final c = LoginInputField(barcodeFormat: 'barcode'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // InputData copyWith + // --------------------------------------------------------------------------- + group('InputData', () { + test('copyWith() with no args preserves all fields', () { + final inputData = InputData( + login: const LoginInputField(), + password: const InputField(), + ); + final copied = inputData.copyWith(); + expect(copied.login, const LoginInputField()); + expect(copied.password, const InputField()); + }); + + test('copyWith() overrides only specified fields', () { + final inputData = InputData( + login: const LoginInputField(), + password: const InputField(), + ); + final updated = inputData.copyWith(password: const InputField(keyboard: KeyboardType.numPad)); + expect(updated.password.keyboard, KeyboardType.numPad); + }); + + test('equality is value-based', () { + final a = InputData(); + final b = InputData(); + expect(a, equals(b)); + + final c = InputData(password: const InputField(keyboard: KeyboardType.numPad)); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // PublicKeyData copyWith + // --------------------------------------------------------------------------- + group('PublicKeyData', () { + test('copyWith() with no args preserves all fields', () { + final publicKey = PublicKeyData( + type: 'RSA', + value: 'base64-encoded-key', + ); + final copied = publicKey.copyWith(); + expect(copied.type, 'RSA'); + expect(copied.value, 'base64-encoded-key'); + }); + + test('copyWith() overrides only specified fields', () { + final publicKey = PublicKeyData( + type: 'RSA', + value: 'base64-encoded-key', + ); + final updated = publicKey.copyWith(value: 'new-key'); + expect(updated.type, 'RSA'); + expect(updated.value, 'new-key'); + }); + + test('equality is value-based', () { + final a = PublicKeyData(type: 'RSA', value: 'key1'); + final b = PublicKeyData(type: 'RSA', value: 'key1'); + expect(a, equals(b)); + + final c = PublicKeyData(type: 'RSA', value: 'key2'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // WebColor copyWith + // --------------------------------------------------------------------------- + group('WebColor', () { + test('copyWith() with no args preserves all fields', () { + final color = WebColor( + primary: '#FF0000', + secondary: '#00FF00', + ); + final copied = color.copyWith(); + expect(copied.primary, '#FF0000'); + expect(copied.secondary, '#00FF00'); + }); + + test('copyWith() overrides only specified fields', () { + final color = WebColor( + primary: '#FF0000', + secondary: '#00FF00', + ); + final updated = color.copyWith(primary: '#0000FF'); + expect(updated.primary, '#0000FF'); + expect(updated.secondary, '#00FF00'); + }); + + test('equality is value-based', () { + final a = WebColor(primary: '#FF0000', secondary: '#00FF00'); + final b = WebColor(primary: '#FF0000', secondary: '#00FF00'); + expect(a, equals(b)); + + final c = WebColor(primary: '#0000FF', secondary: '#00FF00'); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // LocatorCollection copyWith + // --------------------------------------------------------------------------- + group('LocatorCollection', () { + test('copyWith() with no args preserves all fields', () { + final collection = LocatorCollection( + metadata: const LocatorCollectionMetadata(), + ); + final copied = collection.copyWith(); + expect(copied.metadata, const LocatorCollectionMetadata()); + }); + + test('copyWith() overrides only specified fields', () { + final collection = LocatorCollection( + metadata: const LocatorCollectionMetadata(), + ); + final updated = collection.copyWith(links: [const Link(href: '/link1.xhtml')]); + expect(updated.links, isNotEmpty); + }); + + test('equality is value-based', () { + final a = LocatorCollection(); + final b = LocatorCollection(); + expect(a, equals(b)); + + final c = LocatorCollection(links: [const Link(href: '/l1.xhtml')]); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // LocatorCollectionMetadata copyWith + // --------------------------------------------------------------------------- + group('LocatorCollectionMetadata', () { + test('copyWith() with no args preserves all fields', () { + final metadata = LocatorCollectionMetadata( + localizedTitle: LocalizedString(), + ); + final copied = metadata.copyWith(); + expect(copied.localizedTitle, isNotNull); + }); + + test('copyWith() overrides only specified fields', () { + final metadata = LocatorCollectionMetadata( + localizedTitle: LocalizedString(), + ); + final updated = metadata.copyWith(numberOfItems: 10); + expect(updated.numberOfItems, 10); + }); + + test('equality is value-based', () { + final a = LocatorCollectionMetadata(localizedTitle: LocalizedString()); + final b = LocatorCollectionMetadata(localizedTitle: LocalizedString()); + expect(a, equals(b)); + + final c = LocatorCollectionMetadata(localizedTitle: LocalizedString(), numberOfItems: 10); + expect(a, isNot(equals(c))); + }); + }); + + // --------------------------------------------------------------------------- + // LocalizedString copyWith + // --------------------------------------------------------------------------- + group('LocalizedString', () { + test('copyWith() with no args preserves all fields', () { + final str = LocalizedString( + translations: {'en': Translation('Hello')}, + ); + final copied = str.copyWith(); + expect(copied.translations, isNotNull); + }); + + test('copyWith() overrides only specified fields', () { + final str = LocalizedString( + translations: {'en': Translation('Original')}, + ); + final updated = str.copyWith(translations: {'en': Translation('Updated')}); + expect(updated.translations, isNotNull); + }); + + test('equality is value-based', () { + final a = LocalizedString(translations: {'en': Translation('Hello')}); + final b = LocalizedString(translations: {'en': Translation('Hello')}); + expect(a, equals(b)); + + final c = LocalizedString(translations: {'en': Translation('Hi')}); + expect(a, isNot(equals(c))); + }); + }); + // --------------------------------------------------------------------------- // Properties serialisation // --------------------------------------------------------------------------- From 1c8706f4f44bbd18188588abeab2777f80f79bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Sj=C3=B8gren?= Date: Thu, 13 Aug 2026 15:51:04 +0200 Subject: [PATCH 3/3] fix: handle issue with non-nullable values in copyWith(...) functions --- flutter_readium/example/ios/Podfile.lock | 2 +- .../readium_locations_extension.dart | 10 +-- .../lib/src/reader/reader_decoration.dart | 12 ++-- .../lib/src/reader/reader_tts_voice.dart | 16 ++--- .../lib/src/shared/opds/feed.dart | 28 ++++---- .../lib/src/shared/opds/group.dart | 16 ++--- .../src/shared/opds/opds_authentication.dart | 72 +++++++++---------- .../lib/src/shared/opds/opds_metadata.dart | 4 +- .../lib/src/shared/publication/locator.dart | 50 ++++++------- .../publication/locator_collection.dart | 14 ++-- .../shared/publication/metadata/chapter.dart | 20 +++--- .../shared/publication/metadata/episode.dart | 16 ++--- .../shared/publication/metadata/issue.dart | 24 +++---- .../shared/publication/metadata/season.dart | 20 +++--- .../src/shared/publication/publication.dart | 28 ++++---- .../lib/src/timebased_state.dart | 16 ++--- 16 files changed, 168 insertions(+), 180 deletions(-) diff --git a/flutter_readium/example/ios/Podfile.lock b/flutter_readium/example/ios/Podfile.lock index 5b8dc68c..229dfe81 100644 --- a/flutter_readium/example/ios/Podfile.lock +++ b/flutter_readium/example/ios/Podfile.lock @@ -108,6 +108,6 @@ SPEC CHECKSUMS: SwiftSoup: 959c9ac70d7053fbf476341bfac90ab228523f2a wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 -PODFILE CHECKSUM: 2f4fb5dcab74326e2b88472463efb20c7535dda1 +PODFILE CHECKSUM: c4906ba94e31390c41a115760de24db9cfc2379e COCOAPODS: 1.16.2 diff --git a/flutter_readium_platform_interface/lib/src/extensions/readium_locations_extension.dart b/flutter_readium_platform_interface/lib/src/extensions/readium_locations_extension.dart index eba46692..8701b72d 100644 --- a/flutter_readium_platform_interface/lib/src/extensions/readium_locations_extension.dart +++ b/flutter_readium_platform_interface/lib/src/extensions/readium_locations_extension.dart @@ -1,4 +1,5 @@ import 'package:collection/collection.dart'; +import 'package:meta/meta.dart'; import '../shared/index.dart'; import '../shared/publication.dart'; @@ -15,7 +16,7 @@ extension LocationExtension on Locations { if (fragment != null) fragment.fragment, ]; - return copyWith(fragments: newFragments.isEmpty ? null : newFragments); + return copyWith(fragments: newFragments); } Locations copyWithPhysicalPageNumber(final String? index) { @@ -24,7 +25,7 @@ extension LocationExtension on Locations { if (index != null) 'physicalPage=$index', ]; - return copyWith(fragments: newFragments.isEmpty ? null : newFragments); + return copyWith(fragments: newFragments); } Locations copyWithPage(final int? index) { @@ -33,7 +34,7 @@ extension LocationExtension on Locations { if (index != null) 'page=$index', ]; - return copyWith(fragments: newFragments.isEmpty ? null : newFragments); + return copyWith(fragments: newFragments); } /// Duration must be in seconds. @@ -44,7 +45,7 @@ extension LocationExtension on Locations { if (duration != null) 'duration=$duration', ]; - return copyWith(fragments: newFragments.isEmpty ? null : newFragments); + return copyWith(fragments: newFragments); } String? get physicalPage => fragments.firstWhereOrNull((final f) => f.startsWith('physicalPage='))?.split('=').last; @@ -64,6 +65,7 @@ extension LocationExtension on Locations { ); } +@immutable class TimeFragment { const TimeFragment({this.begin = Duration.zero, this.end}); diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart index d68e47a4..5c214018 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_decoration.dart @@ -50,10 +50,10 @@ class ReaderDecoration implements JSONable { @override Map toJson() => {'id': id, 'locator': locator.toJson(), 'style': style.toJson()}; - ReaderDecoration copyWith({Object? id = unset, Object? locator = unset, Object? style = unset}) => ReaderDecoration( - id: identical(id, unset) ? this.id : (id as String?)!, - locator: identical(locator, unset) ? this.locator : (locator as Locator?)!, - style: identical(style, unset) ? this.style : (style as ReaderDecorationStyle?)!, + ReaderDecoration copyWith({Object id = unset, Object locator = unset, Object style = unset}) => ReaderDecoration( + id: identical(id, unset) ? this.id : (id as String), + locator: identical(locator, unset) ? this.locator : (locator as Locator), + style: identical(style, unset) ? this.style : (style as ReaderDecorationStyle), ); } @@ -89,9 +89,9 @@ class ReaderDecorationStyle implements JSONable { isActive: map['isActive'] as bool? ?? false, ); - ReaderDecorationStyle copyWith({Object? style = unset, Object? tint = unset, Object? isActive = unset}) => + ReaderDecorationStyle copyWith({Object style = unset, Object? tint = unset, Object isActive = unset}) => ReaderDecorationStyle( - style: identical(style, unset) ? this.style : (style as DecorationStyle?)!, + style: identical(style, unset) ? this.style : (style as DecorationStyle), tint: identical(tint, unset) ? this.tint : tint as Color?, isActive: identical(isActive, unset) ? this.isActive : (isActive as bool), ); diff --git a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart index b3d8a00e..4ed45237 100644 --- a/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart +++ b/flutter_readium_platform_interface/lib/src/reader/reader_tts_voice.dart @@ -120,17 +120,17 @@ class ReaderTTSVoice with Equatable implements JSONable { ]; ReaderTTSVoice copyWith({ - Object? identifier = unset, - Object? name = unset, - Object? language = unset, - Object? networkRequired = unset, - Object? gender = unset, + Object identifier = unset, + Object name = unset, + Object language = unset, + Object networkRequired = unset, + Object gender = unset, Object? quality = unset, Object? active = unset, }) => ReaderTTSVoice( - identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, - name: identical(name, unset) ? this.name : (name as String?)!, - language: identical(language, unset) ? this.language : (language as String?)!, + identifier: identical(identifier, unset) ? this.identifier : (identifier as String), + name: identical(name, unset) ? this.name : (name as String), + language: identical(language, unset) ? this.language : (language as String), networkRequired: identical(networkRequired, unset) ? this.networkRequired : (networkRequired as bool), gender: identical(gender, unset) ? this.gender : (gender as TTSVoiceGender), quality: identical(quality, unset) ? this.quality : (quality as TTSVoiceQuality?), diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart index 32b90f32..1bbad3ed 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/feed.dart @@ -50,25 +50,25 @@ class Feed extends AdditionalProperties with Equatable implements JSONable { 'context: $context}'; Feed copyWith({ - Object? metadata = unset, - Object? links = unset, - Object? facets = unset, - Object? groups = unset, - Object? publications = unset, - Object? navigation = unset, - Object? context = unset, + Object metadata = unset, + Object links = unset, + Object facets = unset, + Object groups = unset, + Object publications = unset, + Object navigation = unset, + Object context = unset, Object? additionalProperties = unset, }) { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Feed( - metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - facets: identical(facets, unset) ? this.facets : (facets as List?)!, - groups: identical(groups, unset) ? this.groups : (groups as List?)!, - publications: identical(publications, unset) ? this.publications : (publications as List?)!, - navigation: identical(navigation, unset) ? this.navigation : (navigation as List?)!, - context: identical(context, unset) ? this.context : (context as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata), + links: identical(links, unset) ? this.links : (links as List), + facets: identical(facets, unset) ? this.facets : (facets as List), + groups: identical(groups, unset) ? this.groups : (groups as List), + publications: identical(publications, unset) ? this.publications : (publications as List), + navigation: identical(navigation, unset) ? this.navigation : (navigation as List), + context: identical(context, unset) ? this.context : (context as List), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart index 0cbf4355..4223e1a2 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/group.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/group.dart @@ -35,15 +35,15 @@ class Group with Equatable implements JSONable { 'publications: $publications, navigation: $navigation}'; Group copyWith({ - Object? metadata = unset, - Object? links = unset, - Object? publications = unset, - Object? navigation = unset, + Object metadata = unset, + Object links = unset, + Object publications = unset, + Object navigation = unset, }) => Group( - metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - publications: identical(publications, unset) ? this.publications : (publications as List?)!, - navigation: identical(navigation, unset) ? this.navigation : (navigation as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as OpdsMetadata), + links: identical(links, unset) ? this.links : (links as List), + publications: identical(publications, unset) ? this.publications : (publications as List), + navigation: identical(navigation, unset) ? this.navigation : (navigation as List), ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart index 4a88fb0c..950ee2ea 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_authentication.dart @@ -212,13 +212,13 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements ..putJSONableIfNotEmpty('web_color_scheme', webColorScheme); OpdsAuthentication copyWith({ - Object? type = unset, - Object? id = unset, + Object type = unset, + Object id = unset, Object? description = unset, - Object? links = unset, - Object? announcements = unset, - Object? audiences = unset, - Object? collectionSize = unset, + Object links = unset, + Object announcements = unset, + Object audiences = unset, + Object collectionSize = unset, Object? colorScheme = unset, Object? featureFlags = unset, Object? inputs = unset, @@ -231,22 +231,22 @@ class OpdsAuthentication extends AdditionalProperties with Equatable implements final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return OpdsAuthentication( - type: identical(type, unset) ? this.type : (type as String?)!, - id: identical(id, unset) ? this.id : (id as String?)!, - links: identical(links, unset) ? this.links : (links as List?)!, + type: identical(type, unset) ? this.type : (type as String), + id: identical(id, unset) ? this.id : (id as String), + links: identical(links, unset) ? this.links : (links as List), description: identical(description, unset) ? this.description : description as String?, - announcements: identical(announcements, unset) ? this.announcements : (announcements as List?)!, - audiences: identical(audiences, unset) ? this.audiences : (audiences as List?)!, - collectionSize: identical(collectionSize, unset) ? this.collectionSize : (collectionSize as Map?)!, + announcements: identical(announcements, unset) ? this.announcements : (announcements as List), + audiences: identical(audiences, unset) ? this.audiences : (audiences as List), + collectionSize: identical(collectionSize, unset) ? this.collectionSize : (collectionSize as Map), colorScheme: identical(colorScheme, unset) ? this.colorScheme : colorScheme as String?, - featureFlags: identical(featureFlags, unset) ? this.featureFlags : (featureFlags as FeatureFlags?)!, - inputs: identical(inputs, unset) ? this.inputs : (inputs as InputData?)!, - labels: identical(labels, unset) ? this.labels : (labels as Map?)!, - publicKey: identical(publicKey, unset) ? this.publicKey : (publicKey as PublicKeyData?)!, + featureFlags: identical(featureFlags, unset) ? this.featureFlags : (featureFlags as FeatureFlags?), + inputs: identical(inputs, unset) ? this.inputs : (inputs as InputData?), + labels: identical(labels, unset) ? this.labels : (labels as Map?), + publicKey: identical(publicKey, unset) ? this.publicKey : (publicKey as PublicKeyData?), serviceDescription: identical(serviceDescription, unset) ? this.serviceDescription : serviceDescription as String?, - webColorScheme: identical(webColorScheme, unset) ? this.webColorScheme : (webColorScheme as WebColor?)!, + webColorScheme: identical(webColorScheme, unset) ? this.webColorScheme : (webColorScheme as WebColor?), additionalProperties: mergeProperties, ); } @@ -300,9 +300,9 @@ class OpdsAuthenticationFlow with Equatable implements JSONable { ..put('type', type) ..putIterableIfNotEmpty('links', links); - OpdsAuthenticationFlow copyWith({Object? type = unset, Object? links = unset}) => OpdsAuthenticationFlow( - type: identical(type, unset) ? this.type : (type as String?)!, - links: identical(links, unset) ? this.links : (links as List?)!, + OpdsAuthenticationFlow copyWith({Object type = unset, Object links = unset}) => OpdsAuthenticationFlow( + type: identical(type, unset) ? this.type : (type as String), + links: identical(links, unset) ? this.links : (links as List), ); @override @@ -369,15 +369,15 @@ class Announcement extends AdditionalProperties with Equatable implements JSONab ..put('content', content); Announcement copyWith({ - Object? id = unset, - Object? content = unset, + Object id = unset, + Object content = unset, Object? additionalProperties = unset, }) { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Announcement( - id: identical(id, unset) ? this.id : (id as String?)!, - content: identical(content, unset) ? this.content : (content as String?)!, + id: identical(id, unset) ? this.id : (id as String), + content: identical(content, unset) ? this.content : (content as String), additionalProperties: mergeProperties, ); } @@ -456,9 +456,9 @@ class FeatureFlags with Equatable implements JSONable { ..putIterableIfNotEmpty('enabled', enabled) ..putIterableIfNotEmpty('disabled', disabled); - FeatureFlags copyWith({Object? enabled = unset, Object? disabled = unset}) => FeatureFlags( - enabled: identical(enabled, unset) ? this.enabled : (enabled as List?)!, - disabled: identical(disabled, unset) ? this.disabled : (disabled as List?)!, + FeatureFlags copyWith({Object enabled = unset, Object disabled = unset}) => FeatureFlags( + enabled: identical(enabled, unset) ? this.enabled : (enabled as List), + disabled: identical(disabled, unset) ? this.disabled : (disabled as List), ); @override @@ -597,9 +597,9 @@ class InputData with Equatable implements JSONable { ..put('login', login) ..put('password', password); - InputData copyWith({Object? login = unset, Object? password = unset}) => InputData( - login: identical(login, unset) ? this.login : (login as LoginInputField?)!, - password: identical(password, unset) ? this.password : (password as InputField?)!, + InputData copyWith({Object login = unset, Object password = unset}) => InputData( + login: identical(login, unset) ? this.login : (login as LoginInputField), + password: identical(password, unset) ? this.password : (password as InputField), ); @override @@ -630,9 +630,9 @@ class PublicKeyData with Equatable implements JSONable { ..put('type', type) ..put('value', value); - PublicKeyData copyWith({Object? type = unset, Object? value = unset}) => PublicKeyData( - type: identical(type, unset) ? this.type : (type as String?)!, - value: identical(value, unset) ? this.value : (value as String?)!, + PublicKeyData copyWith({Object type = unset, Object value = unset}) => PublicKeyData( + type: identical(type, unset) ? this.type : (type as String), + value: identical(value, unset) ? this.value : (value as String), ); @override @@ -672,9 +672,9 @@ class WebColor with Equatable implements JSONable { ..putOpt('primary', primary) ..putOpt('secondary', secondary); - WebColor copyWith({Object? primary = unset, Object? secondary = unset}) => WebColor( - primary: identical(primary, unset) ? this.primary : (primary as String?)!, - secondary: identical(secondary, unset) ? this.secondary : (secondary as String?)!, + WebColor copyWith({Object primary = unset, Object secondary = unset}) => WebColor( + primary: identical(primary, unset) ? this.primary : (primary as String), + secondary: identical(secondary, unset) ? this.secondary : (secondary as String), ); @override diff --git a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart index bd739e57..ff9e0cf7 100644 --- a/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart +++ b/flutter_readium_platform_interface/lib/src/shared/opds/opds_metadata.dart @@ -55,7 +55,7 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab ]; OpdsMetadata copyWith({ - Object? localizedTitle = unset, + Object localizedTitle = unset, Object? localizedSubtitle = unset, Object? identifier = unset, Object? description = unset, @@ -70,7 +70,7 @@ class OpdsMetadata extends AdditionalProperties with Equatable implements JSONab final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return OpdsMetadata( - localizedTitle: identical(localizedTitle, unset) ? this.localizedTitle : (localizedTitle as LocalizedString?)!, + localizedTitle: identical(localizedTitle, unset) ? this.localizedTitle : (localizedTitle as LocalizedString), localizedSubtitle: identical(localizedSubtitle, unset) ? this.localizedSubtitle : localizedSubtitle as LocalizedString?, diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart index 1af85c08..be1cd6c4 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator.dart @@ -153,8 +153,8 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { ..putJSONableIfNotEmpty('text', text); Locator copyWith({ - Object? href = unset, - Object? type = unset, + Object href = unset, + Object type = unset, Object? title = unset, Object? locations = unset, Object? text = unset, @@ -163,31 +163,33 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Locator( - href: identical(href, unset) ? this.href : (href as String?)!, - type: identical(type, unset) ? this.type : (type as String?)!, + href: identical(href, unset) ? this.href : (href as String), + type: identical(type, unset) ? this.type : (type as String), title: identical(title, unset) ? this.title : title as String?, - locations: identical(locations, unset) ? this.locations : (locations as Locations?)!, - text: identical(text, unset) ? this.text : (text as LocatorText?)!, + locations: identical(locations, unset) ? this.locations : (locations as Locations), + text: identical(text, unset) ? this.text : (text as LocatorText), additionalProperties: mergeProperties, ); } /// Shortcut to get a copy of the [Locator] with different [Locations] sub-properties. Locator copyWithLocations({ - Object? fragments = unset, + Object fragments = unset, Object? progression = unset, Object? position = unset, Object? totalProgression = unset, - Object? otherLocations = unset, + Object? additionalProperties = unset, }) => copyWith( locations: (locations ?? Locations()).copyWith( - fragments: identical(fragments, unset) ? locations?.fragments : (fragments as List?)!, - progression: identical(progression, unset) ? null : (progression as double?), - position: identical(position, unset) ? null : (position as int?), - totalProgression: identical(totalProgression, unset) ? null : (totalProgression as double?), - additionalProperties: identical(otherLocations, unset) || otherLocations == null + fragments: identical(fragments, unset) ? (locations?.fragments ?? const []) : (fragments as List), + progression: identical(progression, unset) ? locations?.progression : (progression as double?), + position: identical(position, unset) ? locations?.position : (position as int?), + totalProgression: identical(totalProgression, unset) + ? locations?.totalProgression + : (totalProgression as double?), + additionalProperties: identical(additionalProperties, unset) || additionalProperties == null ? locations?.additionalProperties - : (otherLocations as Map?), + : (additionalProperties as Map?), ), ); @@ -222,9 +224,9 @@ class Locator extends AdditionalProperties with Equatable implements JSONable { return copyWith( // Makes sure href only contains /path. href: hrefPath, - type: MediaType.html.name, + type: MediaType.html.toString(), locations: locations?.copyWith( - fragments: idFragment == null ? null : [idFragment], + fragments: idFragment == null ? [] : [idFragment], ), ); } @@ -316,7 +318,7 @@ class Locations extends AdditionalProperties with Equatable implements JSONable Object? position = unset, Object? progression = unset, Object? totalProgression = unset, - Object? fragments = unset, + Object fragments = unset, Object? additionalProperties = unset, Object? cssSelector = unset, Object? domRange = unset, @@ -325,13 +327,13 @@ class Locations extends AdditionalProperties with Equatable implements JSONable final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Locations( - progression: identical(progression, unset) ? this.progression : (progression as double?)!, - position: identical(position, unset) ? this.position : (position as int?)!, - totalProgression: identical(totalProgression, unset) ? this.totalProgression : (totalProgression as double?)!, - fragments: identical(fragments, unset) ? this.fragments : (fragments as List?)!, - cssSelector: identical(cssSelector, unset) ? this.cssSelector : (cssSelector as String?)!, - domRange: identical(domRange, unset) ? this.domRange : (domRange as DomRange?)!, - partialCfi: identical(partialCfi, unset) ? this.partialCfi : (partialCfi as String?)!, + progression: identical(progression, unset) ? this.progression : (progression as double?), + position: identical(position, unset) ? this.position : (position as int?), + totalProgression: identical(totalProgression, unset) ? this.totalProgression : (totalProgression as double?), + fragments: identical(fragments, unset) ? this.fragments : (fragments as List), + cssSelector: identical(cssSelector, unset) ? this.cssSelector : (cssSelector as String?), + domRange: identical(domRange, unset) ? this.domRange : (domRange as DomRange?), + partialCfi: identical(partialCfi, unset) ? this.partialCfi : (partialCfi as String?), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart index a292eefb..11dbc738 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/locator_collection.dart @@ -66,13 +66,13 @@ class LocatorCollection with Equatable implements JSONable { } LocatorCollection copyWith({ - Object? metadata = unset, - Object? links = unset, - Object? locators = unset, + Object metadata = unset, + Object links = unset, + Object locators = unset, }) => LocatorCollection( - metadata: identical(metadata, unset) ? this.metadata : (metadata as LocatorCollectionMetadata?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - locators: identical(locators, unset) ? this.locators : (locators as List?)!, + metadata: identical(metadata, unset) ? this.metadata : (metadata as LocatorCollectionMetadata), + links: identical(links, unset) ? this.links : (links as List), + locators: identical(locators, unset) ? this.locators : (locators as List), ); @override @@ -160,7 +160,7 @@ class LocatorCollectionMetadata extends AdditionalProperties with Equatable impl Object? additionalProperties = unset, }) => LocatorCollectionMetadata( localizedTitle: identical(localizedTitle, unset) ? this.localizedTitle : localizedTitle, - numberOfItems: identical(numberOfItems, unset) ? this.numberOfItems : (numberOfItems as int?)!, + numberOfItems: identical(numberOfItems, unset) ? this.numberOfItems : (numberOfItems as int?), additionalProperties: copyAdditionalProperties(additionalProperties: additionalProperties), ); diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart index 0dbb088b..6559aa0a 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/chapter.dart @@ -77,23 +77,19 @@ class Chapter extends BaseCollection { Object? altIdentifiers = unset, Object? localizedSortAs = unset, Object? links = unset, - Object? series = unset, + Object series = unset, Object? additionalProperties = unset, }) { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Chapter( - position: identical(position, unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, unset) - ? this.altIdentifiers - : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, unset) - ? this.localizedSortAs - : (localizedSortAs as LocalizedString?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - series: identical(series, unset) ? this.series : (series as List?)!, + position: identical(position, unset) ? this.position : (position as double?), + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?), + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?), + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?), + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?), + links: identical(links, unset) ? this.links : (links as List?), + series: identical(series, unset) ? this.series : (series as List), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart index 056d2c93..699bebda 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/episode.dart @@ -98,16 +98,12 @@ class Episode extends BaseCollection { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Episode( - position: identical(position, unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, unset) - ? this.altIdentifiers - : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, unset) - ? this.localizedSortAs - : (localizedSortAs as LocalizedString?)!, - links: identical(links, unset) ? this.links : (links as List?)!, + position: identical(position, unset) ? this.position : (position as double?), + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?), + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?), + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?), + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?), + links: identical(links, unset) ? this.links : (links as List?), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart index a0fa8140..067691bc 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/issue.dart @@ -86,25 +86,21 @@ class Issue extends BaseCollection { Object? altIdentifiers = unset, Object? localizedSortAs = unset, Object? links = unset, - Object? articles = unset, - Object? chapters = unset, + Object articles = unset, + Object chapters = unset, Object? additionalProperties = unset, }) { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Issue( - position: identical(position, unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, unset) - ? this.altIdentifiers - : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, unset) - ? this.localizedSortAs - : (localizedSortAs as LocalizedString?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - articles: identical(articles, unset) ? this.articles : (articles as List
?)!, - chapters: identical(chapters, unset) ? this.chapters : (chapters as List?)!, + position: identical(position, unset) ? this.position : (position as double?), + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?), + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?), + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?), + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?), + links: identical(links, unset) ? this.links : (links as List?), + articles: identical(articles, unset) ? this.articles : (articles as List
), + chapters: identical(chapters, unset) ? this.chapters : (chapters as List), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart index 7d634c16..97e64e4c 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/metadata/season.dart @@ -102,23 +102,19 @@ class Season extends BaseCollection { Object? altIdentifiers = unset, Object? localizedSortAs = unset, Object? links = unset, - Object? episodes = unset, + Object episodes = unset, Object? additionalProperties = unset, }) { final mergeProperties = copyAdditionalProperties(additionalProperties: additionalProperties); return Season( - position: identical(position, unset) ? this.position : (position as double?)!, - localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?)!, - identifier: identical(identifier, unset) ? this.identifier : (identifier as String?)!, - altIdentifiers: identical(altIdentifiers, unset) - ? this.altIdentifiers - : (altIdentifiers as List?)!, - localizedSortAs: identical(localizedSortAs, unset) - ? this.localizedSortAs - : (localizedSortAs as LocalizedString?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - episodes: identical(episodes, unset) ? this.episodes : (episodes as List?)!, + position: identical(position, unset) ? this.position : (position as double?), + localizedName: identical(localizedName, unset) ? this.localizedName : (localizedName as LocalizedString?), + identifier: identical(identifier, unset) ? this.identifier : (identifier as String?), + altIdentifiers: identical(altIdentifiers, unset) ? this.altIdentifiers : (altIdentifiers as List?), + localizedSortAs: identical(localizedSortAs, unset) ? this.localizedSortAs : (localizedSortAs as LocalizedString?), + links: identical(links, unset) ? this.links : (links as List?), + episodes: identical(episodes, unset) ? this.episodes : (episodes as List), additionalProperties: mergeProperties, ); } diff --git a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart index 0b8f18b4..b948a6ad 100644 --- a/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart +++ b/flutter_readium_platform_interface/lib/src/shared/publication/publication.dart @@ -61,23 +61,23 @@ class Publication with Equatable implements JSONable { /// Returns a copy of this publication with the given fields replaced. Publication copyWith({ - Object? context = unset, - Object? metadata = unset, - Object? links = unset, - Object? readingOrder = unset, - Object? resources = unset, - Object? tableOfContents = unset, - Object? subCollections = unset, + Object context = unset, + Object metadata = unset, + Object links = unset, + Object readingOrder = unset, + Object resources = unset, + Object tableOfContents = unset, + Object subCollections = unset, }) => Publication( - context: identical(context, unset) ? this.context : (context as List?)!, - metadata: identical(metadata, unset) ? this.metadata : (metadata as Metadata?)!, - links: identical(links, unset) ? this.links : (links as List?)!, - readingOrder: identical(readingOrder, unset) ? this.readingOrder : (readingOrder as List?)!, - resources: identical(resources, unset) ? this.resources : (resources as List?)!, - tableOfContents: identical(tableOfContents, unset) ? this.tableOfContents : (tableOfContents as List?)!, + context: identical(context, unset) ? this.context : (context as List), + metadata: identical(metadata, unset) ? this.metadata : (metadata as Metadata), + links: identical(links, unset) ? this.links : (links as List), + readingOrder: identical(readingOrder, unset) ? this.readingOrder : (readingOrder as List), + resources: identical(resources, unset) ? this.resources : (resources as List), + tableOfContents: identical(tableOfContents, unset) ? this.tableOfContents : (tableOfContents as List), subCollections: identical(subCollections, unset) ? this.subCollections - : (subCollections as Map>?)!, + : (subCollections as Map>), ); @override diff --git a/flutter_readium_platform_interface/lib/src/timebased_state.dart b/flutter_readium_platform_interface/lib/src/timebased_state.dart index 0ce9b761..6e2702bd 100644 --- a/flutter_readium_platform_interface/lib/src/timebased_state.dart +++ b/flutter_readium_platform_interface/lib/src/timebased_state.dart @@ -117,7 +117,7 @@ class ReadiumTimebasedState implements JSONable { ..putOpt('currentLocator', currentLocator?.toJson()); ReadiumTimebasedState copyWith({ - Object? state = unset, + Object state = unset, Object? currentOffset = unset, Object? currentBuffered = unset, Object? currentDuration = unset, @@ -125,14 +125,14 @@ class ReadiumTimebasedState implements JSONable { Object? totalDuration = unset, Object? currentLocator = unset, }) => ReadiumTimebasedState( - state: identical(state, unset) ? this.state : (state as TimebasedState?)!, - currentOffset: identical(currentOffset, unset) ? this.currentOffset : (currentOffset as Duration?)!, - currentBuffered: identical(currentBuffered, unset) ? this.currentBuffered : (currentBuffered as Duration?)!, - currentDuration: identical(currentDuration, unset) ? this.currentDuration : (currentDuration as Duration?)!, + state: identical(state, unset) ? this.state : (state as TimebasedState), + currentOffset: identical(currentOffset, unset) ? this.currentOffset : (currentOffset as Duration?), + currentBuffered: identical(currentBuffered, unset) ? this.currentBuffered : (currentBuffered as Duration?), + currentDuration: identical(currentDuration, unset) ? this.currentDuration : (currentDuration as Duration?), totalProgressDuration: identical(totalProgressDuration, unset) ? this.totalProgressDuration - : (totalProgressDuration as Duration?)!, - totalDuration: identical(totalDuration, unset) ? this.totalDuration : (totalDuration as Duration?)!, - currentLocator: identical(currentLocator, unset) ? this.currentLocator : (currentLocator as Locator?)!, + : (totalProgressDuration as Duration?), + totalDuration: identical(totalDuration, unset) ? this.totalDuration : (totalDuration as Duration?), + currentLocator: identical(currentLocator, unset) ? this.currentLocator : (currentLocator as Locator?), ); }